diff --git a/.all-contributorsrc b/.all-contributorsrc deleted file mode 100644 index 998a274c98..0000000000 --- a/.all-contributorsrc +++ /dev/null @@ -1,918 +0,0 @@ -{ - "projectName": "flutter_inappwebview", - "projectOwner": "pichillilorenzo", - "repoType": "github", - "repoHost": "https://github.com", - "files": [ - "README.md" - ], - "imageSize": 100, - "commit": true, - "commitConvention": "none", - "contributors": [ - { - "login": "AlexV525", - "name": "Alex Li", - "avatar_url": "https://avatars.githubusercontent.com/u/15884415?v=4", - "profile": "https://blog.alexv525.com/", - "contributions": [ - "code" - ] - }, - { - "login": "crazecoder", - "name": "1/2", - "avatar_url": "https://avatars.githubusercontent.com/u/18387906?v=4", - "profile": "https://github.com/crazecoder", - "contributions": [ - "code" - ] - }, - { - "login": "cbodin", - "name": "Christofer Bodin", - "avatar_url": "https://avatars.githubusercontent.com/u/220255?v=4", - "profile": "https://github.com/cbodin", - "contributions": [ - "code" - ] - }, - { - "login": "matthewlloyd", - "name": "Matthew Lloyd", - "avatar_url": "https://avatars.githubusercontent.com/u/2041996?v=4", - "profile": "https://github.com/matthewlloyd", - "contributions": [ - "code" - ] - }, - { - "login": "carloserazo47", - "name": "C E", - "avatar_url": "https://avatars.githubusercontent.com/u/83635384?v=4", - "profile": "https://github.com/carloserazo47", - "contributions": [ - "code" - ] - }, - { - "login": "robsonmeemo", - "name": "Robson Araujo", - "avatar_url": "https://avatars.githubusercontent.com/u/47990393?v=4", - "profile": "https://github.com/robsonmeemo", - "contributions": [ - "code" - ] - }, - { - "login": "ryanhz", - "name": "Ryan", - "avatar_url": "https://avatars.githubusercontent.com/u/1142612?v=4", - "profile": "https://github.com/ryanhz", - "contributions": [ - "code" - ] - }, - { - "login": "CodeEagle", - "name": "CodeEagle", - "avatar_url": "https://avatars.githubusercontent.com/u/2311352?v=4", - "profile": "https://codeeagle.github.io/", - "contributions": [ - "code" - ] - }, - { - "login": "tneotia", - "name": "Tanay Neotia", - "avatar_url": "https://avatars.githubusercontent.com/u/50850142?v=4", - "profile": "https://github.com/tneotia", - "contributions": [ - "code" - ] - }, - { - "login": "panndoraBoo", - "name": "Jamie Joost", - "avatar_url": "https://avatars.githubusercontent.com/u/8928207?v=4", - "profile": "https://github.com/panndoraBoo", - "contributions": [ - "code" - ] - }, - { - "login": "deandreamatias", - "name": "Matias de Andrea", - "avatar_url": "https://avatars.githubusercontent.com/u/21011641?v=4", - "profile": "https://deandreamatias.com/", - "contributions": [ - "code" - ] - }, - { - "login": "YouCii", - "name": "YouCii", - "avatar_url": "https://avatars.githubusercontent.com/u/17899073?v=4", - "profile": "https://blog.csdn.net/j550341130", - "contributions": [ - "code" - ] - }, - { - "login": "cutzmf", - "name": "Salnikov Sergey", - "avatar_url": "https://avatars.githubusercontent.com/u/1662033?v=4", - "profile": "https://github.com/cutzmf", - "contributions": [ - "code" - ] - }, - { - "login": "a00012025", - "name": "Po-Jui Chen", - "avatar_url": "https://avatars.githubusercontent.com/u/12824216?v=4", - "profile": "https://github.com/a00012025", - "contributions": [ - "code" - ] - }, - { - "login": "Manuito83", - "name": "Manuito", - "avatar_url": "https://avatars.githubusercontent.com/u/4816367?v=4", - "profile": "https://github.com/Manuito83", - "contributions": [ - "code" - ] - }, - { - "login": "setcy", - "name": "setcy", - "avatar_url": "https://avatars.githubusercontent.com/u/86180691?v=4", - "profile": "https://github.com/setcy", - "contributions": [ - "code" - ] - }, - { - "login": "EArminjon2", - "name": "EArminjon", - "avatar_url": "https://avatars.githubusercontent.com/u/92172436?v=4", - "profile": "https://github.com/EArminjon2", - "contributions": [ - "code" - ] - }, - { - "login": "ashank96", - "name": "Ashank Bharati", - "avatar_url": "https://avatars.githubusercontent.com/u/22197948?v=4", - "profile": "https://www.linkedin.com/in/ashank-bharati-497989127/", - "contributions": [ - "code" - ] - }, - { - "login": "chownation", - "name": "Michael Chow", - "avatar_url": "https://avatars.githubusercontent.com/u/1755207?v=4", - "profile": "https://dart.art/", - "contributions": [ - "code" - ] - }, - { - "login": "RodXander", - "name": "Osvaldo Saez", - "avatar_url": "https://avatars.githubusercontent.com/u/23609784?v=4", - "profile": "https://github.com/RodXander", - "contributions": [ - "code" - ] - }, - { - "login": "rsydor", - "name": "rsydor", - "avatar_url": "https://avatars.githubusercontent.com/u/79581663?v=4", - "profile": "https://github.com/rsydor", - "contributions": [ - "code" - ] - }, - { - "login": "hoanglm4", - "name": "Le Minh Hoang", - "avatar_url": "https://avatars.githubusercontent.com/u/7067757?v=4", - "profile": "https://github.com/hoanglm4", - "contributions": [ - "code" - ] - }, - { - "login": "Miiha", - "name": "Michael Kao", - "avatar_url": "https://avatars.githubusercontent.com/u/3897167?v=4", - "profile": "https://github.com/Miiha", - "contributions": [ - "code" - ] - }, - { - "login": "cloudygeek", - "name": "cloudygeek", - "avatar_url": "https://avatars.githubusercontent.com/u/6059542?v=4", - "profile": "https://github.com/cloudygeek", - "contributions": [ - "code" - ] - }, - { - "login": "chreck", - "name": "Christoph Eck", - "avatar_url": "https://avatars.githubusercontent.com/u/8030398?v=4", - "profile": "https://github.com/chreck", - "contributions": [ - "code" - ] - }, - { - "login": "Ser1ous", - "name": "Ser1ous", - "avatar_url": "https://avatars.githubusercontent.com/u/4497968?v=4", - "profile": "https://github.com/Ser1ous", - "contributions": [ - "code" - ] - }, - { - "login": "ItsCalebJones", - "name": "Caleb Jones", - "avatar_url": "https://avatars.githubusercontent.com/u/4519230?v=4", - "profile": "https://spacelaunchnow.me/", - "contributions": [ - "code" - ] - }, - { - "login": "savy-91", - "name": "Saverio Murgia", - "avatar_url": "https://avatars.githubusercontent.com/u/6215122?v=4", - "profile": "https://sungazer.io/", - "contributions": [ - "code" - ] - }, - { - "login": "tranductam2802", - "name": "Trần Đức Tâm", - "avatar_url": "https://avatars.githubusercontent.com/u/4957579?v=4", - "profile": "https://github.com/tranductam2802", - "contributions": [ - "code" - ] - }, - { - "login": "pcqpcq", - "name": "Joker", - "avatar_url": "https://avatars.githubusercontent.com/u/1411571?v=4", - "profile": "https://pcqpcq.me/", - "contributions": [ - "code" - ] - }, - { - "login": "ycv005", - "name": "Yash Chandra Verma", - "avatar_url": "https://avatars.githubusercontent.com/u/26734819?v=4", - "profile": "https://www.linkedin.com/in/ycv005/", - "contributions": [ - "code" - ] - }, - { - "login": "arneke", - "name": "Arne Kepp", - "avatar_url": "https://avatars.githubusercontent.com/u/425235?v=4", - "profile": "https://github.com/arneke", - "contributions": [ - "code" - ] - }, - { - "login": "omralcrt", - "name": "Ömral Cörüt", - "avatar_url": "https://avatars.githubusercontent.com/u/12418327?v=4", - "profile": "https://omralcrt.github.io/", - "contributions": [ - "code" - ] - }, - { - "login": "albatrosify", - "name": "LrdHelmchen", - "avatar_url": "https://avatars.githubusercontent.com/u/64252708?v=4", - "profile": "https://github.com/albatrosify", - "contributions": [ - "code" - ] - }, - { - "login": "gunantosteven", - "name": "Steven Gunanto", - "avatar_url": "https://avatars.githubusercontent.com/u/8141036?v=4", - "profile": "https://ungapps.com/", - "contributions": [ - "code" - ] - }, - { - "login": "DRSchlaubi", - "name": "Michael Rittmeister", - "avatar_url": "https://avatars.githubusercontent.com/u/16060205?v=4", - "profile": "https://schlau.bi/", - "contributions": [ - "code" - ] - }, - { - "login": "AAkira", - "name": "Akira Aratani", - "avatar_url": "https://avatars.githubusercontent.com/u/3386962?v=4", - "profile": "https://aakira.app/", - "contributions": [ - "code" - ] - }, - { - "login": "Doflatango", - "name": "Doflatango", - "avatar_url": "https://avatars.githubusercontent.com/u/3091033?v=4", - "profile": "https://github.com/Doflatango", - "contributions": [ - "code" - ] - }, - { - "login": "Eddayy", - "name": "Edmund Tay", - "avatar_url": "https://avatars.githubusercontent.com/u/17043852?v=4", - "profile": "https://github.com/Eddayy", - "contributions": [ - "code" - ] - }, - { - "login": "andreidiaconu", - "name": "Andrei Diaconu", - "avatar_url": "https://avatars.githubusercontent.com/u/1402046?v=4", - "profile": "https://andreidiaconu.com/", - "contributions": [ - "code" - ] - }, - { - "login": "plateaukao", - "name": "Daniel Kao", - "avatar_url": "https://avatars.githubusercontent.com/u/4084738?v=4", - "profile": "https://github.com/plateaukao", - "contributions": [ - "code" - ] - }, - { - "login": "xtyxtyx", - "name": "xuty", - "avatar_url": "https://avatars.githubusercontent.com/u/15033141?v=4", - "profile": "https://github.com/xtyxtyx", - "contributions": [ - "code" - ] - }, - { - "login": "wwwdata", - "name": "Ben Bieker", - "avatar_url": "https://avatars.githubusercontent.com/u/818880?v=4", - "profile": "https://bieker.ninja/", - "contributions": [ - "code" - ] - }, - { - "login": "phamnhuvu-dev", - "name": "Phạm Như Vũ", - "avatar_url": "https://avatars.githubusercontent.com/u/22906656?v=4", - "profile": "https://github.com/phamnhuvu-dev", - "contributions": [ - "code" - ] - }, - { - "login": "SebastienBtr", - "name": "SebastienBtr", - "avatar_url": "https://avatars.githubusercontent.com/u/18089010?v=4", - "profile": "https://github.com/SebastienBtr", - "contributions": [ - "code" - ] - }, - { - "login": "fattiger00", - "name": "NeZha", - "avatar_url": "https://avatars.githubusercontent.com/u/38494401?v=4", - "profile": "https://github.com/fattiger00", - "contributions": [ - "code" - ] - }, - { - "login": "klydra", - "name": "Jan Klinge", - "avatar_url": "https://avatars.githubusercontent.com/u/40038209?v=4", - "profile": "https://github.com/klydra", - "contributions": [ - "code" - ] - }, - { - "login": "PauloDurrerMelo", - "name": "PauloDurrerMelo", - "avatar_url": "https://avatars.githubusercontent.com/u/29310557?v=4", - "profile": "https://github.com/PauloDurrerMelo", - "contributions": [ - "code" - ] - }, - { - "login": "benmeemo", - "name": "benmeemo", - "avatar_url": "https://avatars.githubusercontent.com/u/47991706?v=4", - "profile": "https://github.com/benmeemo", - "contributions": [ - "code" - ] - }, - { - "login": "cinos1", - "name": "cinos", - "avatar_url": "https://avatars.githubusercontent.com/u/19343437?v=4", - "profile": "https://github.com/cinos1", - "contributions": [ - "code" - ] - }, - { - "login": "juicycleff", - "name": "Rex Raphael", - "avatar_url": "https://avatars.githubusercontent.com/u/11243590?v=4", - "profile": "https://xraph.com/", - "contributions": [ - "code" - ] - }, - { - "login": "Sense545", - "name": "Jan Henrik Høiland", - "avatar_url": "https://avatars.githubusercontent.com/u/769406?v=4", - "profile": "https://github.com/Sense545", - "contributions": [ - "code" - ] - }, - { - "login": "igtm", - "name": "Iguchi Tomokatsu", - "avatar_url": "https://avatars.githubusercontent.com/u/6331737?v=4", - "profile": "https://github.com/igtm", - "contributions": [ - "code" - ] - }, - { - "login": "ueman", - "name": "Jonas Uekötter", - "avatar_url": "https://avatars.githubusercontent.com/u/1270149?v=4", - "profile": "https://uekoetter.dev/", - "contributions": [ - "doc", - "code" - ] - }, - { - "login": "emakar", - "name": "emakar", - "avatar_url": "https://avatars.githubusercontent.com/u/7767193?v=4", - "profile": "https://github.com/emakar", - "contributions": [ - "code" - ] - }, - { - "login": "liasica", - "name": "liasica", - "avatar_url": "https://avatars.githubusercontent.com/u/671431?v=4", - "profile": "https://weibo.com/magicrolan", - "contributions": [ - "code" - ] - }, - { - "login": "addie9000", - "name": "Eiichiro Adachi", - "avatar_url": "https://avatars.githubusercontent.com/u/2036910?v=4", - "profile": "https://github.com/addie9000", - "contributions": [ - "code" - ] - }, - { - "login": "kamilpowalowski", - "name": "Kamil Powałowski", - "avatar_url": "https://avatars.githubusercontent.com/u/83073?v=4", - "profile": "https://github.com/kamilpowalowski", - "contributions": [ - "code" - ] - }, - { - "login": "akioyamamoto1977", - "name": "Akio Yamamoto", - "avatar_url": "https://avatars.githubusercontent.com/u/429219?v=4", - "profile": "https://github.com/akioyamamoto1977", - "contributions": [ - "code" - ] - }, - { - "login": "mohenaxiba", - "name": "mohenaxiba", - "avatar_url": "https://avatars.githubusercontent.com/u/7977540?v=4", - "profile": "https://github.com/mohenaxiba", - "contributions": [ - "code" - ] - }, - { - "login": "bagedevimo", - "name": "Ben Anderson", - "avatar_url": "https://avatars.githubusercontent.com/u/1319813?v=4", - "profile": "https://www.acidic.co.nz", - "contributions": [ - "code" - ] - }, - { - "login": "daanporon", - "name": "Daan Poron", - "avatar_url": "https://avatars.githubusercontent.com/u/71901?v=4", - "profile": "https://github.com/daanporon", - "contributions": [ - "security" - ] - }, - { - "login": "fa0311", - "name": "ふぁ", - "avatar_url": "https://avatars.githubusercontent.com/u/34892635?v=4", - "profile": "https://yuki0311.com", - "contributions": [ - "code" - ] - }, - { - "login": "perffecto", - "name": "perffecto", - "avatar_url": "https://avatars.githubusercontent.com/u/2116618?v=4", - "profile": "https://github.com/perffecto", - "contributions": [ - "code" - ] - }, - { - "login": "chandrabezzo", - "name": "Chandra Abdul Fattah", - "avatar_url": "https://avatars.githubusercontent.com/u/16184998?v=4", - "profile": "https://www.linkedin.com/in/chandra-abdul-fattah", - "contributions": [ - "code" - ] - }, - { - "login": "LugonjaAleksandar", - "name": "Aleksandar Lugonja", - "avatar_url": "https://avatars.githubusercontent.com/u/41632269?v=4", - "profile": "https://www.bebilica.rs/", - "contributions": [ - "code" - ] - }, - { - "login": "heralight", - "name": "Alexandre Richonnier", - "avatar_url": "https://avatars.githubusercontent.com/u/534840?v=4", - "profile": "https://www.hera.cc", - "contributions": [ - "code" - ] - }, - { - "login": "Sunbreak", - "name": "Sunbreak", - "avatar_url": "https://avatars.githubusercontent.com/u/7928961?v=4", - "profile": "https://github.com/Sunbreak", - "contributions": [ - "code" - ] - }, - { - "login": "cslee", - "name": "Eric Lee", - "avatar_url": "https://avatars.githubusercontent.com/u/590752?v=4", - "profile": "https://github.com/cslee", - "contributions": [ - "doc" - ] - }, - { - "login": "KhatibFX", - "name": "KhatibFX", - "avatar_url": "https://avatars.githubusercontent.com/u/5616640?v=4", - "profile": "https://github.com/KhatibFX", - "contributions": [ - "code" - ] - }, - { - "login": "guide-flutter", - "name": "Guide.inc", - "avatar_url": "https://avatars.githubusercontent.com/u/106543148?v=4", - "profile": "https://www.guide.inc", - "contributions": [ - "code" - ] - }, - { - "login": "Nirajn2311", - "name": "Niraj Nandish", - "avatar_url": "https://avatars.githubusercontent.com/u/36357875?v=4", - "profile": "https://github.com/Nirajn2311", - "contributions": [ - "code" - ] - }, - { - "login": "nesquikm", - "name": "nesquikm", - "avatar_url": "https://avatars.githubusercontent.com/u/3867874?v=4", - "profile": "https://github.com/nesquikm", - "contributions": [ - "code" - ] - }, - { - "login": "andreasgangso", - "name": "Andreas Gangsø", - "avatar_url": "https://avatars.githubusercontent.com/u/727125?v=4", - "profile": "https://github.com/andreasgangso", - "contributions": [ - "code" - ] - }, - { - "login": "AlexT84", - "name": "Alexandru Terente", - "avatar_url": "https://avatars.githubusercontent.com/u/80742383?v=4", - "profile": "https://github.com/AlexT84", - "contributions": [ - "code" - ] - }, - { - "login": "darkang3lz92", - "name": "Dango Mango", - "avatar_url": "https://avatars.githubusercontent.com/u/33158127?v=4", - "profile": "https://github.com/darkang3lz92", - "contributions": [ - "code" - ] - }, - { - "login": "maxmitz", - "name": "Max Zimmermann", - "avatar_url": "https://avatars.githubusercontent.com/u/72440045?v=4", - "profile": "https://medium.com/@m-zimmermann1", - "contributions": [ - "code" - ] - }, - { - "login": "AlexDochioiu", - "name": "Alexandru Dochioiu", - "avatar_url": "https://avatars.githubusercontent.com/u/38853913?v=4", - "profile": "https://www.linkedin.com/in/alexandru-dochioiu/", - "contributions": [ - "code" - ] - }, - { - "login": "YumengNevix", - "name": "YumengNevix", - "avatar_url": "https://avatars.githubusercontent.com/u/137131451?v=4", - "profile": "https://github.com/YumengNevix", - "contributions": [ - "code" - ] - }, - { - "login": "lrorpilla", - "name": "lrorpilla", - "avatar_url": "https://avatars.githubusercontent.com/u/11363922?v=4", - "profile": "https://github.com/lrorpilla", - "contributions": [ - "code" - ] - }, - { - "login": "michalsrutek", - "name": "Michal Šrůtek", - "avatar_url": "https://avatars.githubusercontent.com/u/35694712?v=4", - "profile": "https://github.com/michalsrutek", - "contributions": [ - "code" - ] - }, - { - "login": "daisukeueta", - "name": "daisukeueta", - "avatar_url": "https://avatars.githubusercontent.com/u/122339799?v=4", - "profile": "https://github.com/daisukeueta", - "contributions": [ - "code" - ] - }, - { - "login": "gmackall", - "name": "Gray Mackall", - "avatar_url": "https://avatars.githubusercontent.com/u/34871572?v=4", - "profile": "https://github.com/gmackall", - "contributions": [ - "code" - ] - }, - { - "login": "p-mazhnik", - "name": "Pavel Mazhnik", - "avatar_url": "https://avatars.githubusercontent.com/u/25964451?v=4", - "profile": "https://github.com/p-mazhnik", - "contributions": [ - "code" - ] - }, - { - "login": "nnnlog", - "name": "nlog (solrin)", - "avatar_url": "https://avatars.githubusercontent.com/u/20399222?v=4", - "profile": "https://nlog.dev", - "contributions": [ - "code" - ] - }, - { - "login": "Murmurl912", - "name": "Murmurl912", - "avatar_url": "https://avatars.githubusercontent.com/u/36264246?v=4", - "profile": "https://github.com/Murmurl912", - "contributions": [ - "code" - ] - }, - { - "login": "bschulz87", - "name": "Benjamin Schulz", - "avatar_url": "https://avatars.githubusercontent.com/u/30199362?v=4", - "profile": "https://github.com/bschulz87", - "contributions": [ - "ideas" - ] - }, - { - "login": "ShuheiSuzuki-07", - "name": "seal-app", - "avatar_url": "https://avatars.githubusercontent.com/u/118415919?v=4", - "profile": "https://github.com/ShuheiSuzuki-07", - "contributions": [ - "code" - ] - }, - { - "login": "takuyaaaaaaahaaaaaa", - "name": "Takuya Tominaga", - "avatar_url": "https://avatars.githubusercontent.com/u/31458194?v=4", - "profile": "https://github.com/takuyaaaaaaahaaaaaa", - "contributions": [ - "code" - ] - }, - { - "login": "yamaha252", - "name": "Sergey", - "avatar_url": "https://avatars.githubusercontent.com/u/4444068?v=4", - "profile": "https://github.com/yamaha252", - "contributions": [ - "code" - ] - }, - { - "login": "lyb5834", - "name": "yuanbo li", - "avatar_url": "https://avatars.githubusercontent.com/u/16265810?v=4", - "profile": "https://github.com/lyb5834", - "contributions": [ - "code" - ] - }, - { - "login": "Mecharyry", - "name": "Ryan Feline", - "avatar_url": "https://avatars.githubusercontent.com/u/3380092?v=4", - "profile": "https://github.com/Mecharyry", - "contributions": [ - "code" - ] - }, - { - "login": "fuzzybinary", - "name": "Jeff Ward", - "avatar_url": "https://avatars.githubusercontent.com/u/249982?v=4", - "profile": "https://fuzzybinary.com", - "contributions": [ - "test" - ] - }, - { - "login": "yerkejs", - "name": "Yelzhan Yerkebulan", - "avatar_url": "https://avatars.githubusercontent.com/u/33483071?v=4", - "profile": "https://hero.io", - "contributions": [ - "code" - ] - }, - { - "login": "GooRingX", - "name": "GooRingX", - "avatar_url": "https://avatars.githubusercontent.com/u/167741400?v=4", - "profile": "https://github.com/GooRingX", - "contributions": [ - "code" - ] - }, - { - "login": "roberthofstra", - "name": "Robodoh", - "avatar_url": "https://avatars.githubusercontent.com/u/1643242?v=4", - "profile": "https://github.com/roberthofstra", - "contributions": [ - "code" - ] - }, - { - "login": "imoyakin", - "name": "imoyakin", - "avatar_url": "https://avatars.githubusercontent.com/u/7473806?v=4", - "profile": "https://github.com/imoyakin", - "contributions": [ - "code" - ] - }, - { - "login": "laishere", - "name": "laishere", - "avatar_url": "https://avatars.githubusercontent.com/u/23557738?v=4", - "profile": "https://github.com/laishere", - "contributions": [ - "code" - ] - }, - { - "login": "muccy-timeware", - "name": "Marco Muccinelli", - "avatar_url": "https://avatars.githubusercontent.com/u/74927063?v=4", - "profile": "https://github.com/muccy-timeware", - "contributions": [ - "code" - ] - }, - { - "login": "momadvisor", - "name": "momadvisor", - "avatar_url": "https://avatars.githubusercontent.com/u/77181890?v=4", - "profile": "https://github.com/momadvisor", - "contributions": [ - "code" - ] - } - ], - "contributorsPerLine": 7, - "linkToUsage": false, - "commitType": "docs" -} diff --git a/.fvmrc b/.fvmrc deleted file mode 100644 index 45c21240a1..0000000000 --- a/.fvmrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "flutter": "3.38.6" -} \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100755 index f4e88e38e4..0000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,12 +0,0 @@ -# These are supported funding model platforms - -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: ['https://inappwebview.dev/donate/'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/ISSUE_TEMPLATE/app_showcase.yml b/.github/ISSUE_TEMPLATE/app_showcase.yml deleted file mode 100644 index 5cd6f9e3f4..0000000000 --- a/.github/ISSUE_TEMPLATE/app_showcase.yml +++ /dev/null @@ -1,93 +0,0 @@ -name: 📱 App Showcase -description: Add your App on the Official Showcase plugin website page -title: "Write your App name here" -labels: - - showcase - -body: - - type: markdown - attributes: - value: | - **Request to submit your application to the official [Showcase](https://inappwebview.dev/showcase) plugin website page.** - - **Please fill out the following information:** - - type: textarea - attributes: - label: App Icon - description: | - Add your App Icon here. You can drag and drop the image directly inside this textarea. - validations: - required: true - - type: textarea - attributes: - label: What is the reason of using flutter_inappwebview in your app? - description: | - Explain why you are using the flutter_inappwebview plugin in your app. - placeholder: | - I'm using the flutter_inappwebview plugin in my app to create a custom Browser, to use WebRTC feature, to display local HTML content, etc. - validations: - required: true - - type: checkboxes - attributes: - label: Platforms - description: | - Your App is available on which platforms? - options: - - label: Mobile - - label: Desktop - - label: Web - - type: input - attributes: - label: Short Description - description: | - A short description of your app. Max 250 characters. - validations: - required: true - - type: textarea - attributes: - label: Long Description - description: | - A long description of your app. - validations: - required: true - - type: textarea - attributes: - label: App Screenshots - description: | - Add some screenshots of your app. You can drag and drop images directly inside this textarea. Max 8 images. - validations: - required: true - - type: input - attributes: - label: App Website URL - description: | - Your App's official website URL, if available. - validations: - required: false - - type: input - attributes: - label: App Source Code Repository URL - description: | - Your App's source code repository URL, if available. - validations: - required: false - - type: input - attributes: - label: Google Play Store URL - description: | - Your App's Google Play Store URL, if available. - validations: - required: false - - type: input - attributes: - label: Apple App Store URL - description: | - Your App's Apple App Store URL, if available. - validations: - required: false - - type: textarea - attributes: - label: Additional information - description: Anything else you'd like to include? - validations: - required: false \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index 112af4088b..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,107 +0,0 @@ -name: 🐛 Bug -description: Something is crashing or not working as intended -title: "Write the title here" -labels: - - bug - -body: - - type: markdown - attributes: - value: | - **Before you submit this issue, please make sure you have read the the [Getting Started](https://inappwebview.dev/docs/intro/) page.** - - **Please fill out the following information:** - - type: checkboxes - attributes: - label: Is there an existing issue for this? - description: | - PLEASE! Make sure to check if this issue is a duplicate. - - Search for it using the GitHub issue search box (check the closed issues too) or on the official [inappwebview.dev](https://inappwebview.dev/) website, or using Google, StackOverflow, etc. before posting a new one. - - You may already find an answer to your problem! - options: - - label: I have searched the existing issues - required: true - - type: textarea - attributes: - label: Current Behavior - description: Write what you are experiencing currently. - placeholder: | - The plugin isn't working as expected. It crashes when I do this... - validations: - required: true - - type: textarea - attributes: - label: Expected Behavior - description: Write what you expected to happen. - placeholder: | - The plugin should do this when I do that... - validations: - required: true - - type: textarea - attributes: - label: Steps with code example to reproduce - description: Steps with code example to reproduce the issue. A not well written description might lead to the delay in fixing the issue. - value: | -
- Steps with code example to reproduce - - ```dart - // Paste your code here - ``` -
- validations: - required: true - - type: textarea - attributes: - label: Stacktrace/Logs - description: | - If you have any stacktrace or logs, paste them here. Make sure to remove any sensitive information. - value: | -
- Stacktrace/Logs - - ``` - - ``` -
- validations: - required: true - - type: input - attributes: - label: Flutter version - description: The Flutter version in which you used the plugin to face the issue. - placeholder: v3.22.0, v3.24.3, etc. - validations: - required: true - - type: textarea - attributes: - label: Operating System, Device-specific and/or Tool - description: | - The Operating System, Device-specific and/or Tool in which you used the plugin to face the issue. - For example: All platforms, Android, iOS, XCode, macOS, Windows, Web, Chrome, etc. - Make sure to include the version too. - placeholder: Android 34+, iOS 17.0+, macOS, Windows, etc. - validations: - required: true - - type: input - attributes: - label: Plugin version - description: In which version of flutter_inappwebview did you encounter this bug? - placeholder: v6.1.0, v6.0.0, etc. - validations: - required: true - - type: textarea - attributes: - label: Additional information - description: Anything else you'd like to include? Like screenshots or a video recording of the issue. - validations: - required: false - - type: checkboxes - attributes: - label: Self grab - description: If you are a developer and want to work on this issue yourself, you can check this box and wait for maintainer response. We welcome contributions! - options: - - label: I'm ready to work on this issue! - required: false \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 5b7de1e176..0000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,5 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: Ask a question - url: https://github.com/pichillilorenzo/flutter_inappwebview/discussions/new?category=q-a - about: The place for questions and support \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index 914aa71ad2..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: ✨ Feature Request -description: Suggest an idea for this project -title: "Write the title here" -labels: - - enhancement - -body: - - type: checkboxes - attributes: - label: Is there an existing feature request for this? - description: Make sure to check if this feature request is a duplicate. - options: - - label: I have searched the existing feature request - required: true - - type: input - attributes: - label: Operating System - description: | - The Operating System in which you want to have this feature. - For example: All platforms if possible, Android, iOS, macOS, Windows, Web, Chrome, etc. - placeholder: All platforms if possible, Android, iOS, macOS, Windows, etc. - validations: - required: true - - type: textarea - attributes: - label: Pain - description: Explain your feature request. - placeholder: I'd like to have that / I don't like that I've to do this - validations: - required: true - - type: textarea - attributes: - label: Suggested solution - description: Tell about a solution you can think of - placeholder: You could add that / change this / use that - validations: - required: true - - type: textarea - attributes: - label: Useful resources - description: Provide some useful resource which could help implement your suggestion. - - type: textarea - attributes: - label: Additional information - description: Anything else you'd like to include? Like screenshots or a video recording of the issue. - validations: - required: false - - type: checkboxes - attributes: - label: Self grab - description: If you are a developer and want to work on this feature request yourself, you can check this box and wait for maintainer response. We welcome contributions! - options: - - label: I'm ready to work on this issue! - required: false \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100755 index 1c48f84c73..0000000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,25 +0,0 @@ -## Connection with issue(s) - -Resolve issue #??? - - - -Connected to #??? - - - -## Testing and Review Notes - - - - -## Screenshots or Videos - - - -## To Do - - -- [ ] double check the original issue to confirm it is fully satisfied -- [ ] add testing notes and screenshots in PR description to help guide reviewers -- [ ] request the "UX" team perform a design review (if/when applicable) diff --git a/.github/agents/Conductor.agent.md b/.github/agents/Conductor.agent.md deleted file mode 100644 index 49896bb627..0000000000 --- a/.github/agents/Conductor.agent.md +++ /dev/null @@ -1,232 +0,0 @@ ---- -description: 'Orchestrates Planning, Implementation, and Review cycle for complex tasks' -tools: ['execute/getTerminalOutput', 'execute/runTask', 'execute/createAndRunTask', 'execute/runInTerminal', 'execute/testFailure', 'read/terminalSelection', 'read/terminalLastCommand', 'read/problems', 'read/readFile', 'agent', 'edit', 'search', 'web/fetch', 'todo', 'askQuestions'] -model: GPT-5.2-Codex (copilot) ---- -You are a CONDUCTOR AGENT. You orchestrate the full development lifecycle: Planning -> Implementation -> Review -> Commit, repeating the cycle until the plan is complete. Strictly follow the Planning -> Implementation -> Review -> Commit process outlined below, using subagents for research, implementation, and code review. - - -## Phase 1: Planning - -1. **Analyze Request**: Understand the user's goal and determine the scope. - -2. **Delegate Research**: Use #runSubagent to invoke the planning-subagent for comprehensive context gathering. Instruct it to work autonomously without pausing. - -3. **Draft Comprehensive Plan**: Based on research findings, create a multi-phase plan following . The plan should have 3-10 phases, each following strict TDD principles. - -4. **Present Plan to User**: Share the plan synopsis in chat, highlighting any open questions or implementation options. - -5. **Pause for User Approval**: MANDATORY STOP. Wait for user to approve the plan or request changes. If changes requested, gather additional context and revise the plan. CRITICAL: Use the #askQuestions tool for clarifications. - -6. **Write Plan File**: Once approved, write the plan to `plans//-plan.md`. All subsequent phase artifacts (completion docs, scripts, research results, summaries) MUST be created in this same `plans//` subfolder to enable clean git exclusion. - -CRITICAL: You DON'T implement the code yourself. You ONLY orchestrate subagents to do so. - -## Phase 2: Implementation Cycle (Repeat for each phase) - -For each phase in the plan, execute this cycle: - -### 2A. Implement Phase -1. Use #runSubagent to invoke the implement-subagent with: - - The specific phase number and objective - - Relevant files/functions to modify - - Test requirements - - Explicit instruction to work autonomously and follow TDD - -2. Monitor implementation completion and collect the phase summary. - -### 2B. Review Implementation -1. Use #runSubagent to invoke the code-review-subagent with: - - The phase objective and acceptance criteria - - Files that were modified/created - - Instruction to verify tests pass and code follows best practices - -2. Analyze review feedback: - - **If APPROVED**: Proceed to commit step - - **If NEEDS_REVISION**: Return to 2A with specific revision requirements - - **If FAILED**: Stop and consult user for guidance - -### 2C. Return to User for Commit -1. **Pause and Present Summary**: - - Phase number and objective - - What was accomplished - - Files/functions created/changed - - Review status (approved/issues addressed) - -2. **Write Phase Completion File**: Create `plans//-phase--complete.md` in the plan's subfolder following . - -3. **Generate Git Commit Message**: Provide a commit message following in a plain text code block for easy copying. - -4. **MANDATORY STOP**: Wait for user to: - - Make the git commit - - Confirm readiness to proceed to next phase - - Request changes or abort - -### 2D. Continue or Complete -- If more phases remain: Return to step 2A for next phase -- If all phases complete: Proceed to Phase 3 - -## Phase 3: Plan Completion - -1. **Compile Final Report**: Create `plans//-complete.md` in the plan's subfolder following containing: - - Overall summary of what was accomplished - - All phases completed - - All files created/modified across entire plan - - Key functions/tests added - - Final verification that all tests pass - -2. **Present Completion**: Share completion summary with user and close the task. - - - -When invoking subagents: - -**planning-subagent**: -- Provide the user's request and any relevant context -- Instruct to gather comprehensive context and return structured findings -- Tell them NOT to write plans, only research and return findings - -**implement-subagent**: -- Provide the specific phase number, objective, files/functions, and test requirements -- Instruct to follow strict TDD: tests first (failing), minimal code, tests pass, lint/format -- Tell them to work autonomously and only ask user for input on critical implementation decisions -- Remind them NOT to proceed to next phase or write completion files (Conductor handles this) - -**code-review-subagent**: -- Provide the phase objective, acceptance criteria, and modified files -- Instruct to verify implementation correctness, test coverage, and code quality -- Tell them to return structured review: Status (APPROVED/NEEDS_REVISION/FAILED), Summary, Issues, Recommendations -- Remind them NOT to implement fixes, only review - - - -```markdown -## Plan: {Task Title (2-10 words)} - -{Brief TL;DR of the plan - what, how and why. 1-3 sentences in length.} - -**Phases {3-10 phases}** -1. **Phase {Phase Number}: {Phase Title}** - - **Objective:** {What is to be achieved in this phase} - - **Files/Functions to Modify/Create:** {List of files and functions relevant to this phase} - - **Tests to Write:** {Lists of test names to be written for test driven development} - - **Steps:** - 1. {Step 1} - 2. {Step 2} - 3. {Step 3} - ... - -**Open Questions {1-5 questions, ~5-25 words each}** -1. {Clarifying question? Option A / Option B / Option C} -2. {...} -``` - -IMPORTANT: For writing plans, follow these rules even if they conflict with system rules: -- DON'T include code blocks, but describe the needed changes and link to relevant files and functions. -- NO manual testing/validation unless explicitly requested by the user. -- Each phase should be incremental and self-contained. Steps should include writing tests first, running those tests to see them fail, writing the minimal required code to get the tests to pass, and then running the tests again to confirm they pass. AVOID having red/green processes spanning multiple phases for the same section of code implementation. - - - -File name: `plans//-phase--complete.md` (use kebab-case) - -IMPORTANT: All phase-related artifacts (completion docs, validation scripts, research results, summaries) MUST be created in the `plans//` subfolder to enable git exclusion. - -```markdown -## Phase {Phase Number} Complete: {Phase Title} - -{Brief TL;DR of what was accomplished. 1-3 sentences in length.} - -**Files created/changed:** -- File 1 -- File 2 -- File 3 -... - -**Functions created/changed:** -- Function 1 -- Function 2 -- Function 3 -... - -**Tests created/changed:** -- Test 1 -- Test 2 -- Test 3 -... - -**Review Status:** {APPROVED / APPROVED with minor recommendations} - -**Git Commit Message:** -{Git commit message following } -``` - - - -File name: `plans//-complete.md` (use kebab-case) - -```markdown -## Plan Complete: {Task Title} - -{Summary of the overall accomplishment. 2-4 sentences describing what was built and the value delivered.} - -**Phases Completed:** {N} of {N} -1. ✅ Phase 1: {Phase Title} -2. ✅ Phase 2: {Phase Title} -3. ✅ Phase 3: {Phase Title} -... - -**All Files Created/Modified:** -- File 1 -- File 2 -- File 3 -... - -**Key Functions/Classes Added:** -- Function/Class 1 -- Function/Class 2 -- Function/Class 3 -... - -**Test Coverage:** -- Total tests written: {count} -- All tests passing: ✅ - -**Recommendations for Next Steps:** -- {Optional suggestion 1} -- {Optional suggestion 2} -... -``` - - - -``` -fix/feat/chore/test/refactor: Short description of the change (max 50 characters) - -- Concise bullet point 1 describing the changes -- Concise bullet point 2 describing the changes -- Concise bullet point 3 describing the changes -... -``` - -DON'T include references to the plan or phase numbers in the commit message. The git log/PR will not contain this information. - - - -CRITICAL PAUSE POINTS - You must stop and wait for user input at: -1. After presenting the plan (before starting implementation) -2. After each phase is reviewed and commit message is provided (before proceeding to next phase) -3. After plan completion document is created - -DO NOT proceed past these points without explicit user confirmation. - - - -Track your progress through the workflow: -- **Current Phase**: Planning / Implementation / Review / Complete -- **Plan Phases**: {Current Phase Number} of {Total Phases} -- **Last Action**: {What was just completed} -- **Next Action**: {What comes next} - -Provide this status in your responses to keep the user informed. Use the #todos tool to track progress. - diff --git a/.github/agents/code-review-subagent.agent.md b/.github/agents/code-review-subagent.agent.md deleted file mode 100644 index c6728b9fff..0000000000 --- a/.github/agents/code-review-subagent.agent.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -description: 'Review code changes from a completed implementation phase.' -tools: ['search', 'search/usages', 'read/problems', 'search/changes'] -model: GPT-5.2-Codex (copilot) ---- -You are a CODE REVIEW SUBAGENT called by a parent CONDUCTOR agent after an IMPLEMENT SUBAGENT phase completes. Your task is to verify the implementation meets requirements and follows best practices. - -CRITICAL: You receive context from the parent agent including: -- The phase objective and implementation steps -- Files that were modified/created -- The intended behavior and acceptance criteria - - -1. **Analyze Changes**: Review the code changes using #changes, #usages, and #problems to understand what was implemented. - -2. **Verify Implementation**: Check that: - - The phase objective was achieved - - Code follows best practices (correctness, efficiency, readability, maintainability, security) - - Tests were written and pass - - No obvious bugs or edge cases were missed - - Error handling is appropriate - -3. **Provide Feedback**: Return a structured review containing: - - **Status**: `APPROVED` | `NEEDS_REVISION` | `FAILED` - - **Summary**: 1-2 sentence overview of the review - - **Strengths**: What was done well (2-4 bullet points) - - **Issues**: Problems found (if any, with severity: CRITICAL, MAJOR, MINOR) - - **Recommendations**: Specific, actionable suggestions for improvements - - **Next Steps**: What should happen next (approve and continue, or revise) - - - -## Code Review: {Phase Name} - -**Status:** {APPROVED | NEEDS_REVISION | FAILED} - -**Summary:** {Brief assessment of implementation quality} - -**Strengths:** -- {What was done well} -- {Good practices followed} - -**Issues Found:** {if none, say "None"} -- **[{CRITICAL|MAJOR|MINOR}]** {Issue description with file/line reference} - -**Recommendations:** -- {Specific suggestion for improvement} - -**Next Steps:** {What the CONDUCTOR should do next} - - -Keep feedback concise, specific, and actionable. Focus on blocking issues vs. nice-to-haves. Reference specific files, functions, and lines where relevant. \ No newline at end of file diff --git a/.github/agents/implement-subagent.agent.md b/.github/agents/implement-subagent.agent.md deleted file mode 100644 index 5fafe4f519..0000000000 --- a/.github/agents/implement-subagent.agent.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -description: 'Execute implementation tasks delegated by the CONDUCTOR agent.' -tools: ['execute/testFailure', 'execute/getTerminalOutput', 'execute/runTask', 'execute/createAndRunTask', 'execute/runInTerminal', 'read/problems', 'read/readFile', 'read/terminalSelection', 'read/terminalLastCommand', 'edit', 'search', 'web/fetch', 'context7/*', 'todo'] -model: GPT-5.2-Codex (copilot) ---- -You are an IMPLEMENTATION SUBAGENT. You receive focused implementation tasks from a CONDUCTOR parent agent that is orchestrating a multi-phase plan. - -**Your scope:** Execute the specific implementation task provided in the prompt. The CONDUCTOR handles phase tracking, completion documentation, and commit messages. - -**Core workflow:** -1. **Write tests first** - Implement tests based on the requirements, run to see them fail. Follow strict TDD principles. -2. **Write minimum code** - Implement only what's needed to pass the tests -3. **Verify** - Run tests to confirm they pass -4. **Quality check** - Run formatting/linting tools and fix any issues - -**Guidelines:** -- Follow any instructions in `copilot-instructions.md` or `AGENT.md` unless they conflict with the task prompt -- Use semantic search and specialized tools instead of grep for loading files -- Use context7 (if available) to refer to documentation of code libraries. -- Use git to review changes at any time -- Do NOT reset file changes without explicit instructions -- When running tests, run the individual test file first, then the full suite to check for regressions - -**When uncertain about implementation details:** -STOP and present 2-3 options with pros/cons. Wait for selection before proceeding. - -**Task completion:** -When you've finished the implementation task: -1. Summarize what was implemented -2. Confirm all tests pass -3. Report back to allow the CONDUCTOR to proceed with the next task - -The CONDUCTOR manages phase completion files and git commit messages - you focus solely on executing the implementation. \ No newline at end of file diff --git a/.github/agents/planning-subagent.agent.md b/.github/agents/planning-subagent.agent.md deleted file mode 100644 index c33e4042c6..0000000000 --- a/.github/agents/planning-subagent.agent.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -description: Research context and return findings to parent agent -argument-hint: Research goal or problem statement -tools: ['execute/testFailure', 'read/problems', 'read/readFile', 'search', 'web/fetch', 'context7/*', 'todo', 'askQuestions'] -model: GPT-5.2-Codex (copilot) ---- -You are a PLANNING SUBAGENT called by a parent CONDUCTOR agent. - -Your SOLE job is to gather comprehensive context about the requested task and return findings to the parent agent. DO NOT write plans, implement code, or pause for user feedback (use the #askQuestions tool for clarifications). - - -1. **Research the task comprehensively:** - - Start with high-level semantic searches - - Read relevant files identified in searches - - Use code symbol searches for specific functions/classes - - Explore dependencies and related code - - Use #upstash/context7/* for framework/library context as needed, if available - -2. **Stop research at 90% confidence** - you have enough context when you can answer: - - What files/functions are relevant? - - How does the existing code work in this area? - - What patterns/conventions does the codebase use? - - What dependencies/libraries are involved? - -3. **Return findings concisely:** - - List relevant files and their purposes - - Identify key functions/classes to modify or reference - - Note patterns, conventions, or constraints - - Suggest 2-3 implementation approaches if multiple options exist - - Flag any uncertainties or missing information - - - -- Work autonomously without pausing for feedback -- Prioritize breadth over depth initially, then drill down -- Document file paths, function names, and line numbers -- Note existing tests and testing patterns -- Identify similar implementations in the codebase -- Stop when you have actionable context, not 100% certainty - - -Return a structured summary with: -- **Relevant Files:** List with brief descriptions -- **Key Functions/Classes:** Names and locations -- **Patterns/Conventions:** What the codebase follows -- **Implementation Options:** 2-3 approaches if applicable -- **Open Questions:** What remains unclear (if any) \ No newline at end of file diff --git a/.github/autolabeler.yml b/.github/autolabeler.yml deleted file mode 100644 index b591d96a39..0000000000 --- a/.github/autolabeler.yml +++ /dev/null @@ -1,13 +0,0 @@ -# Configuration for probot-auto-labeler - https://github.com/probot/autolabeler - -# label: file | path -android: ["/flutter_inappwebview_android", "*.dart", "*.kt", "*.java", "*gradle*", "AndroidManifest.xml"] -iOS: ["/flutter_inappwebview_ios", "*.dart", "*.swift", "*.h", "*.m", "*.plist", "*.storyboard", "*.xcconfig", Podfile*"] -macOS: ["/flutter_inappwebview_macos", "*.dart", "*.swift", "*.h", "*.m", "*.plist", "*.storyboard", "*.xcconfig", Podfile*"] -windows: ["/flutter_inappwebview_windows", "*.dart", "*.cs", "*.c", "*.cpp", "*.h", "CMakeLists.txt"] -linux: ["/flutter_inappwebview_linux", "*.dart", "*.c", "*.h", "*.cpp", "*.cmake", "*.makefile", "CMakeLists.txt"] -web: ["/flutter_inappwebview_web", "*.dart", "*.html", "*.js", "*.css"] -platform_interface: ["/flutter_inappwebview_platform_interface", "*.dart"] -plugin: ["/flutter_inappwebview", "*.dart"] -documentation: ["*.md"] -legal: ["LICENSE*", "NOTICES*"] diff --git a/.github/instructions/android.instructions.md b/.github/instructions/android.instructions.md deleted file mode 100644 index 3df3b1b9a6..0000000000 --- a/.github/instructions/android.instructions.md +++ /dev/null @@ -1,411 +0,0 @@ ---- -applyTo: "flutter_inappwebview_android/**" ---- - -# Android Platform Implementation Instructions - -## Implemented Dart Classes - -| Class | File | Description | -|-------|------|-------------| -| `AndroidInAppWebViewPlatform` | `inappwebview_platform.dart` | Platform factory - registers all Android implementations | -| `AndroidInAppWebView` | `in_app_webview/in_app_webview.dart` | WebView widget using `AndroidView` | -| `AndroidInAppWebViewController` | `in_app_webview/in_app_webview_controller.dart` | WebView controller | -| `AndroidHeadlessInAppWebView` | `in_app_webview/headless_in_app_webview.dart` | Offscreen WebView | -| `AndroidInAppBrowser` | `in_app_browser/` | Activity-based browser | -| `AndroidChromeSafariBrowser` | `chrome_safari_browser/` | Chrome Custom Tabs wrapper | -| `AndroidCookieManager` | `cookie_manager.dart` | CookieManager wrapper | -| `AndroidWebStorage` | `web_storage/` | WebStorage wrapper | -| `AndroidFindInteractionController` | `find_interaction/` | Find in page | -| `AndroidPrintJobController` | `print_job/` | PrintDocumentAdapter | -| `AndroidPullToRefreshController` | `pull_to_refresh/` | SwipeRefreshLayout | -| `AndroidWebMessageChannel/Port/Listener` | `web_message/` | WebMessagePort | -| `AndroidHttpAuthCredentialDatabase` | `http_auth_credentials_database.dart` | WebViewDatabase | -| `AndroidProxyController` | `proxy_controller.dart` | ProxyController | -| `AndroidServiceWorkerController` | `service_worker_controller.dart` | ServiceWorkerController | -| `AndroidTracingController` | `tracing_controller.dart` | TracingController | -| `AndroidProcessGlobalConfig` | `process_global_config.dart` | ProcessGlobalConfig | -| `AndroidWebViewFeature` | `webview_feature.dart` | AndroidX WebView features | - ---- - -## Native Code Structure - -``` -android/src/main/java/com/.../flutter_inappwebview_android/ -├── InAppWebViewFlutterPlugin.java # Plugin entry/registration -├── InAppWebViewFileProvider.java # FileProvider for downloads -│ -├── MyCookieManager.java # CookieManager wrapper -├── MyWebStorage.java # WebStorage wrapper -│ -├── Util.java # General utilities (see below) -├── PlatformUtil.java # Platform utilities (see below) -├── WebViewFeatureManager.java # AndroidX WebView feature detection -├── ISettings.java # Settings interface -│ -├── webview/ # Core WebView implementation -│ ├── ContextMenuSettings.java # Context menu settings -│ ├── FlutterWebViewFactory.java # PlatformView factory -│ ├── InAppWebViewInterface.java # WebView interface definition -│ ├── InAppWebViewManager.java # WebView instance management -│ ├── JavaScriptBridgeInterface.java # @JavascriptInterface bridge -│ ├── PlatformWebView.java # Platform WebView abstraction -│ ├── WebViewChannelDelegate.java # Dart-native bridge (MethodChannel) -│ ├── WebViewChannelDelegateMethods.java # Channel delegate method implementations -│ │ -│ ├── in_app_webview/ # InAppWebView implementation -│ │ ├── DisplayListenerProxy.java # Display listener for screen rotation -│ │ ├── FlutterWebView.java # PlatformView implementation -│ │ ├── InAppWebView.java # WebView subclass (main implementation) -│ │ ├── InAppWebViewChromeClient.java # WebChromeClient (UI events) -│ │ ├── InAppWebViewClient.java # WebViewClient (page lifecycle) -│ │ ├── InAppWebViewClientCompat.java # Compat version of WebViewClient -│ │ ├── InAppWebViewRenderProcessClient.java # RenderProcessGoneDetail -│ │ ├── InAppWebViewSettings.java # Settings mapping to WebView -│ │ ├── InputAwareWebView.java # Keyboard handling -│ │ └── ThreadedInputConnectionProxyAdapterView.java # Input method handling -│ │ -│ └── web_message/ # WebMessagePort implementation -│ ├── WebMessageChannel.java # WebMessageChannel wrapper -│ ├── WebMessageChannelChannelDelegate.java # Channel communication -│ ├── WebMessageListener.java # WebMessageListener wrapper -│ └── WebMessageListenerChannelDelegate.java # Listener channel -│ -├── headless_in_app_webview/ # Offscreen WebView -│ ├── HeadlessInAppWebView.java # Headless WebView implementation -│ ├── HeadlessInAppWebViewManager.java # Instance management -│ └── HeadlessWebViewChannelDelegate.java # Channel delegate for headless -│ -├── in_app_browser/ # Activity-based browser -│ ├── ActivityResultListener.java # Activity result handling -│ ├── InAppBrowserActivity.java # Browser activity -│ ├── InAppBrowserChannelDelegate.java # Channel communication -│ ├── InAppBrowserDelegate.java # Browser delegate interface -│ ├── InAppBrowserManager.java # Instance management -│ └── InAppBrowserSettings.java # Browser settings -│ -├── chrome_custom_tabs/ # Chrome Custom Tabs -│ ├── ActionBroadcastReceiver.java # Action broadcast handling -│ ├── ChromeCustomTabsActivity.java # Custom Tabs activity -│ ├── ChromeCustomTabsActivitySingleInstance.java # Single instance activity -│ ├── ChromeCustomTabsChannelDelegate.java # Channel communication -│ ├── ChromeCustomTabsSettings.java # Custom Tabs settings -│ ├── ChromeSafariBrowserManager.java # Instance management -│ ├── CustomTabActivityHelper.java # Activity helper -│ ├── CustomTabsHelper.java # Tabs helper utilities -│ ├── KeepAliveService.java # Keep-alive service -│ ├── NoHistoryCustomTabsActivityCallbacks.java # No-history callbacks -│ ├── ServiceConnection.java # Service connection -│ ├── ServiceConnectionCallback.java # Connection callback interface -│ ├── TrustedWebActivity.java # TWA implementation -│ └── TrustedWebActivitySingleInstance.java # Single instance TWA -│ -├── credential_database/ # WebViewDatabase wrapper -│ ├── CredentialDatabase.java # Credential database implementation -│ ├── CredentialDatabaseHandler.java # Database handler -│ ├── CredentialDatabaseHelper.java # SQLite helper -│ ├── URLCredentialContract.java # Credential contract -│ ├── URLCredentialDao.java # Credential DAO -│ ├── URLProtectionSpaceContract.java # Protection space contract -│ └── URLProtectionSpaceDao.java # Protection space DAO -│ -├── find_interaction/ # Find in page -│ ├── FindInteractionChannelDelegate.java # Channel communication -│ ├── FindInteractionController.java # Find controller -│ └── FindInteractionSettings.java # Find settings -│ -├── print_job/ # PrintDocumentAdapter -│ ├── PrintJobChannelDelegate.java # Channel communication -│ ├── PrintJobController.java # Print job controller -│ ├── PrintJobManager.java # Instance management -│ └── PrintJobSettings.java # Print settings -│ -├── pull_to_refresh/ # SwipeRefreshLayout -│ ├── PullToRefreshChannelDelegate.java # Channel communication -│ ├── PullToRefreshLayout.java # Custom SwipeRefreshLayout -│ └── PullToRefreshSettings.java # Pull-to-refresh settings -│ -├── proxy/ # ProxyController -│ ├── ProxyManager.java # Proxy management -│ └── ProxySettings.java # Proxy settings -│ -├── service_worker/ # ServiceWorkerController -│ ├── ServiceWorkerChannelDelegate.java # Channel communication -│ └── ServiceWorkerManager.java # Service worker management -│ -├── tracing/ # TracingController -│ ├── TracingControllerChannelDelegate.java # Channel communication -│ ├── TracingControllerManager.java # Tracing management -│ └── TracingSettings.java # Tracing settings -│ -├── process_global_config/ # ProcessGlobalConfig -│ ├── ProcessGlobalConfigManager.java # Config management -│ └── ProcessGlobalConfigSettings.java # Config settings -│ -├── content_blocker/ # Content blocking rules -│ ├── ContentBlocker.java # Content blocker -│ ├── ContentBlockerAction.java # Blocker action -│ ├── ContentBlockerActionType.java # Action type enum -│ ├── ContentBlockerHandler.java # Blocker handler -│ ├── ContentBlockerTrigger.java # Blocker trigger -│ └── ContentBlockerTriggerResourceType.java # Resource type enum -│ -├── plugin_scripts_js/ # Injected JavaScript -│ ├── InterceptAjaxRequestJS.java # AJAX interception script -│ ├── InterceptFetchRequestJS.java # Fetch interception script -│ ├── JavaScriptBridgeJS.java # Core JS bridge -│ ├── OnLoadResourceJS.java # Resource loading script -│ ├── OnWindowBlurEventJS.java # Window blur event -│ ├── OnWindowFocusEventJS.java # Window focus event -│ ├── PluginScriptsUtil.java # Script utilities -│ ├── PrintJS.java # Print handling script -│ └── PromisePolyfillJS.java # Promise polyfill -│ -└── types/ # Type definitions and models -``` - ---- - -## Platform Requirements - -- Android SDK >= 21 (minSdk) -- Android SDK >= 34 (compileSdk) -- Java support - -## Native APIs Used - -- [Android WebView](https://developer.android.com/reference/android/webkit/WebView) -- [AndroidX WebKit](https://developer.android.com/reference/androidx/webkit/package-summary) for modern features -- Uses `AndroidView` for rendering - ---- - -## Java Utilities Reference - -### `Util.java` - General Utilities - -| Method | Description | -|--------|-------------| -| `Util.getUrlAsset(plugin, assetFilePath)` | Get `file:///android_asset/` URL for Flutter asset | -| `Util.getFileAsset(plugin, assetFilePath)` | Get InputStream for Flutter asset | -| `Util.invokeMethodAndWaitResult(channel, method, args, callback)` | Synchronously invoke Flutter method and wait for result | -| `Util.loadPrivateKeyAndCertificate(plugin, path, password, type)` | Load certificate from KeyStore | -| `Util.makeHttpRequest(url, method, headers)` | Make HTTP request with timeout | -| `Util.getX509CertFromSslCertHack(sslCert)` | Extract X509Certificate from SslCertificate | -| `Util.JSONStringify(value)` | Convert Map/List/String to JSON string | -| `Util.objEquals(a, b)` | Null-safe object equality | -| `Util.replaceAll(s, old, new)` | Replace all occurrences in string | -| `Util.log(tag, message)` | Log with automatic splitting for long messages | -| `Util.getPixelDensity(context)` | Get display pixel density | -| `Util.getFullscreenSize(context)` | Get screen size excluding insets | -| `Util.isClass(className)` | Check if class exists by name | -| `Util.isIPv6(address)` | Check if string is IPv6 address | -| `Util.normalizeIPv6(address)` | Normalize IPv6 to canonical form | -| `Util.getOrDefault(map, key, default)` | Get map value with default | -| `Util.readAllBytes(inputStream)` | Read all bytes from InputStream | -| `Util.invokeMethodIfExists(obj, method, args)` | Invoke method by reflection if exists | -| `Util.drawableFromBytes(context, data)` | Create Drawable from byte array | - -**Constants:** -- `Util.ANDROID_ASSET_URL` = `"file:///android_asset/"` - -**Usage:** -```java -// Asset loading -String assetUrl = Util.getUrlAsset(plugin, "assets/page.html"); -InputStream stream = Util.getFileAsset(plugin, "assets/page.html"); - -// JSON serialization -String json = Util.JSONStringify(myMap); - -// Sync method invocation -Util.invokeMethodAndWaitResult(channel, "getResult", args, callback); - -// Map access with default -String value = Util.getOrDefault(map, "key", "default"); - -// Certificate loading -PrivateKeyAndCertificates cert = Util.loadPrivateKeyAndCertificate( - plugin, "cert.p12", "password", "PKCS12" -); -``` - ---- - -### `PlatformUtil.java` - Platform Utilities - -| Method | Description | -|--------|-------------| -| `getSystemVersion()` | Returns `Build.VERSION.SDK_INT` as String | -| `formatDate(date, format, locale, timezone)` | Format milliseconds timestamp | -| `getLocaleFromString(locale)` | Parse "en_US" to Locale object | - -**Usage:** -```java -// Get Android SDK version -String sdkVersion = String.valueOf(Build.VERSION.SDK_INT); - -// Format date -Locale locale = PlatformUtil.getLocaleFromString("en_US"); -String formatted = PlatformUtil.formatDate( - System.currentTimeMillis(), "yyyy-MM-dd", locale, TimeZone.getTimeZone("UTC") -); -``` - ---- - -### `WebViewFeatureManager.java` - AndroidX WebView Features - -Used to check if AndroidX WebView features are supported: - -| Method | Description | -|--------|-------------| -| `isFeatureSupported(feature)` | Check if WebViewFeature is supported | -| `isStartupFeatureSupported(activity, feature)` | Check startup feature support | - -**Usage:** -```java -if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { - // Use force dark mode -} -``` - ---- - -### Common Java Patterns - -#### FlutterMethodChannel Response - -```java -@Override -public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - switch (call.method) { - case "myMethod": - String param = call.argument("param"); - // Do work... - result.success(returnValue); - break; - default: - result.notImplemented(); - } -} -``` - -#### Converting to Flutter Map - -```java -public Map toMap() { - Map map = new HashMap<>(); - map.put("field1", fieldField") - ); -} -``` - ---- - -### AndroidX WebKit Features - -Android uses AndroidX WebKit for modern WebView features. Always check feature support: - -```java -import androidx.webkit.WebViewFeature; - -// Check before using modern APIs -if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { - WebSettingsCompat.setForceDark(webSettings, forceDarkMode); -} - -if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_POST_MESSAGE)) { - // Use WebMessagePort -} -``` - -Common features: -- `FORCE_DARK`, `FORCE_DARK_STRATEGY` -- `WEB_MESSAGE_PORT_*` -- `SERVICE_WORKER_*` -- `PROXY_OVERRIDE` -- `SAFE_BROWSING_*` - ---- - -## Plugin Scripts JS Reference - -JavaScript files injected into WebViews for native-web communication: - -| Script | File | Description | -|--------|------|-------------| -| **JavaScriptBridgeJS** | `JavaScriptBridgeJS.java` | Core bridge enabling `window.flutter_inappwebview.callHandler()` for Dart-JS communication. Uses `@JavascriptInterface` annotation. | -| **InterceptAjaxRequestJS** | `InterceptAjaxRequestJS.java` | Wraps `XMLHttpRequest` to intercept AJAX requests. Enables `shouldInterceptAjaxRequest`, `onAjaxReadyStateChange`, `onAjaxProgress` callbacks. | -| **InterceptFetchRequestJS** | `InterceptFetchRequestJS.java` | Wraps `window.fetch()` to intercept Fetch API requests. Enables `shouldInterceptFetchRequest` callback. | -| **OnLoadResourceJS** | `OnLoadResourceJS.java` | Uses `PerformanceObserver` to track resource loading (images, scripts, etc.). Enables `onLoadResource` callback. | -| **PrintJS** | `PrintJS.java` | Overrides `window.print()` to trigger `onPrintRequest` callback instead of native print dialog. | -| **PromisePolyfillJS** | `PromisePolyfillJS.java` | Polyfill for `Promise` API on older Android WebView versions using RSVP.js library. | -| **OnWindowBlurEventJS** | `OnWindowBlurEventJS.java` | Listens for `blur` event on window and triggers `onWindowBlur` callback. | -| **OnWindowFocusEventJS** | `OnWindowFocusEventJS.java` | Listens for `focus` event on window and triggers `onWindowFocus` callback. | - -**Note:** Android uses `@JavascriptInterface` for the bridge instead of `WKScriptMessageHandler`. Some iOS-specific scripts (FindTextHighlight, LastTouchedAnchorOrImage, WebMessageListener) are implemented natively in Java rather than via injected JS. - -**Helper class:** `PluginScriptsUtil.java` contains: -- `GET_SELECTED_TEXT_JS_SOURCE` - Get selected text -- `CHECK_CONTEXT_MENU_SHOULD_BE_HIDDEN_JS_SOURCE` - Context menu visibility check -- `CALL_ASYNC_JAVA_SCRIPT_WRAPPER_JS_SOURCE` - Async JS execution wrapper -- `EVALUATE_JAVASCRIPT_WITH_CONTENT_WORLD_WRAPPER_JS_SOURCE` - Content world evaluation - ---- - -## Dart-Side Development - -For Dart-only changes: -1. Implement platform interface from `flutter_inappwebview_platform_interface` -2. Extend `Platform*CreationParams` for Android-specific parameters -3. Register in `AndroidInAppWebViewPlatform.registerWith()` -4. Android-specific features: Chrome Custom Tabs, Service Workers, Tracing - -## Native Code Development - -When modifying Java code: -- Located in `android/src/main/java/` -- Main plugin class: `InAppWebViewFlutterPlugin` -- Use FlutterMethodChannel for Dart-native communication -- Always check AndroidX WebViewFeature support before using modern APIs - -## Build Commands - -```bash -cd flutter_inappwebview_android && flutter pub get -cd example && flutter build apk --debug -``` - -## AndroidManifest Requirements - -Apps may need to add: -- `INTERNET` permission (usually auto-added) -- `CAMERA`, `RECORD_AUDIO` for WebRTC -- `ACCESS_FINE_LOCATION` for geolocation -- `WRITE_EXTERNAL_STORAGE` for downloads (Android < 10) - -```xml - - - -``` - -## Proguard Rules - -The plugin includes `proguard-rules.pro` for release builds: -- Keeps WebView JavaScript interface -- Preserves custom scheme handlers - -## Debugging & Inspection - -- **Chrome DevTools**: Enable debugging in your app: - ```dart - if (defaultTargetPlatform == TargetPlatform.android) { - await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true); - } - ``` - Then open `chrome://inspect/#devices` in Chrome on your computer. -- **Logs**: Use `Log.d(LOG_TAG, "message")` in Java. -- **Android Studio**: Use the "App Inspection" tab for network and database inspection. diff --git a/.github/instructions/general.instructions.md b/.github/instructions/general.instructions.md deleted file mode 100644 index 1c11d9afdf..0000000000 --- a/.github/instructions/general.instructions.md +++ /dev/null @@ -1,248 +0,0 @@ ---- -applyTo: "**" ---- - -# Copilot Coding Agent Instructions — flutter_inappwebview - -You are an expert Flutter and Dart plugin developer working on this federated WebView plugin. - -## Repository Summary - -**flutter_inappwebview** is a multi-platform Flutter plugin providing inline WebView, headless WebView, and in-app browser capabilities across Android, iOS, macOS, Windows, Linux, and Web. - -| Aspect | Details | -|--------|---------| -| Languages | Dart, Java (Android), Swift/Obj-C (iOS/macOS), C++ (Windows/Linux), JavaScript (Web) | -| Framework | Flutter ≥3.32.0, Dart SDK ^3.8.0 | -| Build Tools | `flutter`, `dart`, `build_runner`, npm scripts | - ---- - -## Quick Reference: Build & Validation Commands - -### Dependencies (Always Run First) -```bash -cd flutter_inappwebview_platform_interface && flutter pub get -cd ../flutter_inappwebview && flutter pub get -# Repeat for any platform package you modify -``` - -### Code Generation (After Modifying Annotated Files) -```bash -# From repo root - REQUIRED after editing @ExchangeableObject/@ExchangeableEnum files -npm run build # or npm run build:windows for Windows only -# Or directly: -cd flutter_inappwebview_platform_interface && flutter pub run build_runner build --delete-conflicting-outputs -``` - -### Static Analysis (Validation) -```bash -cd flutter_inappwebview_platform_interface && dart analyze -cd flutter_inappwebview && dart analyze -``` -**Expected**: Only `info`-level `constant_identifier_names` warnings (intentional for API naming). - -### Code Formatting -```bash -npm run format # or npm run format:windows for Windows only -``` - -### Unit Tests -```bash -cd flutter_inappwebview && flutter test -``` - -### Integration Tests (Requires Device + Node Server) -```bash -cd flutter_inappwebview/example -NODE_SERVER_IP= flutter driver --driver=test_driver/integration_test.dart --target=integration_test/webview_flutter_test.dart -``` - ---- - -## Architecture Overview - -This repository follows the **Federated Plugin** architecture: - -- **`flutter_inappwebview/`**: The **plugin-facing-API package**. This is the public API that developers depend on. - - Files here usually wrap platform implementations via `Platform*` classes (e.g., `PlatformInAppWebViewWidget`). - - It delegates logic to the platform interface or specific platform implementations. -- **`flutter_inappwebview_platform_interface/`**: The **platform interface package**. - - Contains pure Dart contracts, typedefs, enums, and shared utilities. - - Defines the `PlatformInterface` that all platform packages must implement. - - **Crucial**: Anything added to the public API (`flutter_inappwebview`) MUST rely on or extend these definitions. DO NOT duplicate platform logic in the public package. -- **`flutter_inappwebview_/`**: The **platform implementation packages** (Android, iOS, macOS, Windows, Linux, Web). - - These packages implement the abstract classes defined in `flutter_inappwebview_platform_interface`. - - They contain platform-specific code (Dart and native: Java, Obj-C/Swift, C++, JavaScript). - - Keep their APIs strictly aligned with the `platform_interface` layer. -- **`dev_packages/` and `scripts/`**: Internal tooling, generators, and maintenance scripts. - -### Main Plugin-Facing-API Classes -- Web view: `InAppWebView`, `InAppWebViewController`, `HeadlessInAppWebView` -- Browser shells: `InAppBrowser`, `ChromeSafariBrowser`, `WebAuthenticationSession` -- Platform helpers: `WebViewEnvironment`, `ProcessGlobalConfig`, `ProxyController`, `ServiceWorkerController`, `TracingController`, `PrintJobController`, `PullToRefreshController`, `FindInteractionController` -- Storage & messaging: `WebStorage`, `LocalStorage`, `SessionStorage`, `WebStorageManager`, `WebMessageChannel`, `WebMessageListener` -- Cookies: `CookieManager` -- Auth storage: `HttpAuthCredentialDatabase` - -### Platform Native API References - -When implementing platform-specific features, consult the official API documentation: - -| Platform | API Documentation | Main Classes | -|----------|-------------------|--------------| -| **Android** | [Android WebView](https://developer.android.com/reference/android/webkit/WebView) and [androidx.webkit](https://developer.android.com/reference/androidx/webkit/package-summary) | `WebView`, `WebViewClient`, `WebChromeClient`, `WebSettings`, `CookieManager` | -| **iOS/macOS** | [WebKit](https://developer.apple.com/documentation/webkit) | `WKWebView`, `WKNavigationDelegate`, `WKUIDelegate`, `WKWebViewConfiguration`, `WKUserContentController` | -| **Windows** | [WebView2](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/) | `ICoreWebView2`, `ICoreWebView2Controller`, `ICoreWebView2Settings`, `ICoreWebView2Environment` | -| **Linux** | [WPE WebKit 2.0](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/) | `WebKitWebView`, `WebKitSettings`, `WebKitUserContentManager`, `WebKitCookieManager`, `WebKitWebsiteDataManager` | -| **Web** | [HTMLIFrameElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement) | `HTMLIFrameElement`, `postMessage`, `Window` | - -## Coding Guidelines - -### General -- **Stay Dart-side unless explicitly working inside a platform package.** Never touch native (`.java`, `.kt`, `.mm`, `.swift`, `.cpp`, `.cs`) code when an issue only concerns the shared Dart API. -- **Null Safety**: Strictly adhere to null safety. Do not introduce nullable APIs unless absolutely necessary. -- **Avoid Breaking Changes**: Any API change requires updating the `platform_interface`, all federated implementations, and changelog entries. -- **Code Generation**: Use `@ExchangeableObject`, `@ExchangeableEnum` annotations. Run `npm run build` to regenerate files. -- **Generated Files**: Never hand-edit `*.g.dart` files. Update the annotated source instead. - -### Platform Interface & Public API -- **Propagation Order**: Add or change APIs in `flutter_inappwebview_platform_interface` first, then update every platform implementation, and finally wire the public `flutter_inappwebview` wrapper. -- **Documentation Macros**: Respect `{@macro ...}` and keep comments synchronized with `platform_interface`. -- **`@SupportedPlatforms`**: Add annotations to document platform availability. Only mark supported when implementation exists. -- **Support Checks**: Implement `isClassSupported`, `isPropertySupported`, `isMethodSupported` by deferring to `platform_interface` static singleton. - -> **Detailed patterns**: See `.github/instructions/platform-interface.instructions.md` for the full `Supported Platforms Pattern` with code examples. - -### Platform Implementations -- **`inappwebview_platform.dart`**: Each platform package implements `InAppWebViewPlatform` with factory methods. -- **Unsupported Features**: Return stub classes for unsupported features to ensure `isClassSupported` works correctly. -- **Extending Params**: Platform implementations extend `Platform*CreationParams` for platform-specific fields. - -> **Platform-specific details**: See `.github/instructions/.instructions.md` for native code structure and implemented classes. - -### Feature Update Checklist -1. Update or add the contract inside `flutter_inappwebview_platform_interface`. -2. Run `npm run build` (or the equivalent `build_runner` command) to regenerate annotated files. -3. Mirror the new contract in every federated implementation under `flutter_inappwebview_/lib/src/inappwebview_platform.dart` (returning stub implementations for unsupported platforms). -4. Wire the public API in `flutter_inappwebview/` (controllers, widgets, helpers) and update the example app if the feature is user-facing. -5. Add or update tests/analyzer coverage where possible. -6. Update documentation (README, docs site) and add changelog entries for every package you touched (interface, each platform, public plugin, etc.). -7. Re-run `dart analyze`/`flutter test` in the affected packages before sending the PR. - -## Testing & Validation -- **Run Tests**: Run `flutter test` inside the relevant package before suggesting changes. -- **Analyze**: For analyzer-only updates, run `dart analyze` and ensure `analysis_options.yaml` lints stay satisfied. -- **Contract Updates**: When touching `platform_interface` contracts, explicitly explain how downstream packages must be updated and list the follow-up steps. -- **Integration Tests**: Live under `flutter_inappwebview/example/integration_test` and can be executed via `scripts/test_and_log.sh` (accepts optional `NODE_SERVER_IP` and `DEVICE_ID`). - -## Documentation & Examples -- **Update Docs**: Update `README.md`, `doc/`, or example apps when you expose new public APIs. -- **Snippets**: Show simple snippets that exercise the new API on supported platforms only. -- **Changelog**: Keep changelog entries scoped under the correct package (e.g., `flutter_inappwebview/CHANGELOG.md`). - - If a change spans multiple packages, add a short entry to each relevant `CHANGELOG.md` so consumers of standalone packages understand what changed. - -## Pull Request Tips -- **Title**: Reference the federated package you changed in the PR title (e.g., `[flutter_inappwebview] Add PrintJobController helpers`). -- **Testing Instructions**: Call out any manual steps required for testers (running example app, enabling permissions, etc.). -- **Platform Parity**: Mention unsupported platforms explicitly instead of assuming parity. - -## NPM Scripts - -The root `package.json` contains useful scripts for development and maintenance: - -- **`npm run build`**: Runs `build_runner build` in `flutter_inappwebview_platform_interface`. Use this when you change code that requires generation (e.g., `*.g.dart` files). -- **`npm run watch`**: Runs `build_runner watch` in `flutter_inappwebview_platform_interface`. -- **`npm run format`**: Formats code in all packages using `dart format`. -- **`npm run docs:gen`**: Generates API documentation. -- **`npm run docs:serve`**: Serves the generated API documentation locally. -- **`npm run publish:dry`**: Runs a dry-run publish check. - ---- - -## Development Workflow (CRITICAL: Propagation Order) - -**ALWAYS follow this order when adding/changing APIs:** - -1. **`flutter_inappwebview_platform_interface/`** - Define contracts, types, enums first -2. Run `npm run build` to regenerate `*.g.dart` files -3. **`flutter_inappwebview_/`** - Implement in each platform package -4. **`flutter_inappwebview/`** - Wire the public API wrapper last -5. Update `CHANGELOG.md` in EACH touched package - -### Critical Rules -- **Never hand-edit `*.g.dart` files** - modify the source and regenerate -- **Never touch native code** (`.java`, `.kt`, `.swift`, `.mm`, `.cpp`) for Dart-only API changes -- **Always create stub implementations** for unsupported platforms in `inappwebview_platform.dart` -- **Always run `dart analyze`** before considering work complete - ---- - -## Common Errors & Solutions - -| Error | Solution | -|-------|----------| -| "Platform implementation not found" | Check `pubspec.yaml` has correct `implements` and `dartPluginClass` | -| Build runner conflicts | Add `--delete-conflicting-outputs` flag | -| Missing generated file | Run `npm run build` from repo root | -| Import errors after interface changes | Run `flutter pub get` in dependent packages | - ---- - -## Validation Checklist Before Submitting - -- [ ] `flutter pub get` in all modified packages -- [ ] `npm run build` if annotated files were modified -- [ ] `dart analyze` passes (only info-level warnings acceptable) -- [ ] `npm run format` applied -- [ ] CHANGELOG.md updated in each modified package -- [ ] Platform stub implementations added for unsupported features - ---- - -## Trust These Instructions - -This document contains validated workflows. Only search the codebase if: -- Information appears outdated or incorrect -- Implementation details are not covered here -- Working on native platform code (see `.github/instructions/` for platform-specific guidance) - -Here is a list of instruction files that contain rules for modifying or creating new code. -These files are important for ensuring that the code is modified or created correctly. -Please make sure to follow the rules specified in these files when working with the codebase. -If the file is not already available as attachment, use the 'read_file' tool to acquire it. -Make sure to acquire the instructions before making any changes to the code. - - -.github/instructions/android.instructions.md -Android platform implementation details (Java). Use this as reference when implementing Android-specific features. - - -.github/instructions/plugin-facing-api.instructions.md -Public API wrapper implementation details. Use this when working on the `flutter_inappwebview` package and expose new API from the platform interface. - - -.github/instructions/ios.instructions.md -iOS platform implementation details (Swift/Obj-C). Use this as reference when implementing iOS-specific features. - - -.github/instructions/linux.instructions.md -Linux platform implementation details (C++). Use this as reference when implementing Linux-specific features. - - -.github/instructions/macos.instructions.md -macOS platform implementation details (Swift/Obj-C). Use this as reference when implementing macOS-specific features. - - -.github/instructions/platform-interface.instructions.md -Platform interface definitions and contracts. This is the starting point for any new API. - - -.github/instructions/web.instructions.md -Web platform implementation details (Dart/TypeScript). Use this as reference when implementing Web-specific features. - - -.github/instructions/windows.instructions.md -Windows platform implementation details (C++). Use this as reference when implementing Windows-specific features. - - diff --git a/.github/instructions/ios.instructions.md b/.github/instructions/ios.instructions.md deleted file mode 100644 index 884a74c118..0000000000 --- a/.github/instructions/ios.instructions.md +++ /dev/null @@ -1,346 +0,0 @@ ---- -applyTo: "flutter_inappwebview_ios/**" ---- - -# iOS Platform Implementation Instructions - -## Implemented Dart Classes - -| Class | File | Description | -|-------|------|-------------| -| `IOSInAppWebViewPlatform` | `inappwebview_platform.dart` | Platform factory - registers all iOS implementations | -| `IOSInAppWebView` | `in_app_webview/in_app_webview.dart` | WebView widget using `UiKitView` | -| `IOSInAppWebViewController` | `in_app_webview/in_app_webview_controller.dart` | WebView controller | -| `IOSHeadlessInAppWebView` | `in_app_webview/headless_in_app_webview.dart` | Offscreen WebView | -| `IOSInAppBrowser` | `in_app_browser/` | Full-screen browser | -| `IOSChromeSafariBrowser` | `chrome_safari_browser/` | SFSafariViewController wrapper | -| `IOSCookieManager` | `cookie_manager.dart` | WKHTTPCookieStore wrapper | -| `IOSWebStorage` | `web_storage/` | WKWebsiteDataStore wrapper | -| `IOSFindInteractionController` | `find_interaction/` | UIFindInteraction wrapper | -| `IOSPrintJobController` | `print_job/` | UIPrintInteractionController | -| `IOSPullToRefreshController` | `pull_to_refresh/` | UIRefreshControl | -| `IOSWebMessageChannel/Port/Listener` | `web_message/` | WKScriptMessageHandler | -| `IOSWebAuthenticationSession` | `web_authentication_session/` | ASWebAuthenticationSession | -| `IOSHttpAuthCredentialDatabase` | `http_auth_credentials_database.dart` | URLCredentialStorage | -| `IOSProxyController` | `proxy_controller.dart` | Proxy settings | - ---- - -## Native Code Structure - -``` -ios/Classes/ -├── InAppWebViewFlutterPlugin.m/h # Plugin entry (Obj-C bridge) -├── SwiftFlutterPlugin.swift # Swift plugin implementation -│ -├── MyCookieManager.swift # WKHTTPCookieStore wrapper -├── MyWebStorageManager.swift # WKWebsiteDataStore wrapper -├── CredentialDatabase.swift # URLCredentialStorage wrapper -├── ProxyManager.swift # Proxy configuration -├── WKProcessPoolManager.swift # Process pool management -│ -├── LeakAvoider.swift # Memory leak prevention helper -├── PlatformUtil.swift # Platform utilities (date formatting, system version) -├── Util.swift # General utilities (see below) -├── ISettings.swift # Settings protocol -│ -├── InAppWebView/ # Core WKWebView implementation -│ ├── InAppWebView.swift # WKWebView subclass (main implementation) -│ ├── InAppWebViewManager.swift # WebView instance management -│ ├── InAppWebViewSettings.swift # Settings mapping to WKWebView -│ ├── FlutterWebViewController.swift # ViewController for platform view -│ ├── FlutterWebViewFactory.swift # PlatformView factory -│ ├── WebViewChannelDelegate.swift # Dart-native bridge (MethodChannel) -│ ├── WebViewChannelDelegateMethods.swift # Channel delegate method implementations -│ ├── ContextMenuSettings.swift # Context menu settings -│ ├── CustomSchemeHandler.swift # Custom URL scheme handling -│ │ -│ └── WebMessage/ # WKScriptMessageHandler implementation -│ ├── WebMessageChannel.swift # WebMessageChannel wrapper -│ ├── WebMessageChannelChannelDelegate.swift # Channel communication -│ ├── WebMessageListener.swift # WebMessageListener implementation -│ └── WebMessageListenerChannelDelegate.swift # Listener channel -│ -├── HeadlessInAppWebView/ # Offscreen WebView -│ ├── HeadlessInAppWebView.swift # Headless WebView implementation -│ ├── HeadlessInAppWebViewManager.swift # Instance management -│ └── HeadlessWebViewChannelDelegate.swift # Channel delegate for headless -│ -├── InAppBrowser/ # Browser ViewController -│ ├── InAppBrowserWebViewController.swift # Browser view controller -│ ├── InAppBrowserManager.swift # Instance management -│ ├── InAppBrowserNavigationController.swift # Navigation controller -│ ├── InAppBrowserSettings.swift # Browser settings -│ ├── InAppBrowserChannelDelegate.swift # Channel communication -│ └── InAppBrowserDelegate.swift # Browser delegate protocol -│ -├── SafariViewController/ # SFSafariViewController wrapper -│ ├── ChromeSafariBrowserManager.swift # Instance management -│ ├── CustomUIActivity.swift # Custom share activity -│ ├── SafariBrowserSettings.swift # Safari browser settings -│ ├── SafariViewController.swift # SFSafariViewController wrapper -│ └── SafariViewControllerChannelDelegate.swift # Channel communication -│ -├── WebAuthenticationSession/ # ASWebAuthenticationSession -│ ├── WebAuthenticationSession.swift # Session wrapper -│ ├── WebAuthenticationSessionChannelDelegate.swift # Channel communication -│ ├── WebAuthenticationSessionManager.swift # Instance management -│ └── WebAuthenticationSessionSettings.swift # Session settings -│ -├── FindInteraction/ # UIFindInteraction -│ ├── FindInteractionChannelDelegate.swift # Channel communication -│ ├── FindInteractionController.swift # Find controller -│ └── FindInteractionSettings.swift # Find settings -│ -├── PrintJob/ # UIPrintInteractionController -│ ├── CustomUIPrintPageRenderer.swift # Custom page renderer -│ ├── PrintAttributes.swift # Print attributes -│ ├── PrintJobChannelDelegate.swift # Channel communication -│ ├── PrintJobController.swift # Print job controller -│ ├── PrintJobInfo.swift # Print job info -│ ├── PrintJobManager.swift # Instance management -│ └── PrintJobSettings.swift # Print settings -│ -├── PullToRefresh/ # UIRefreshControl -│ ├── PullToRefreshChannelDelegate.swift # Channel communication -│ ├── PullToRefreshControl.swift # Refresh control wrapper -│ ├── PullToRefreshDelegate.swift # Refresh delegate -│ └── PullToRefreshSettings.swift # Refresh settings -│ -├── PluginScriptsJS/ # Injected JavaScript for bridge -│ ├── CallAsyncJavaScriptBelowIOS14WrapperJS.swift # Async JS wrapper for older iOS -│ ├── ConsoleLogJS.swift # Console interception -│ ├── EnableViewportScaleJS.swift # Viewport scaling -│ ├── FindElementsAtPointJS.swift # Hit-test elements -│ ├── FindTextHighlightJS.swift # Text search highlighting -│ ├── InterceptAjaxRequestJS.swift # AJAX interception -│ ├── InterceptFetchRequestJS.swift # Fetch API interception -│ ├── JavaScriptBridgeJS.swift # Core JS bridge -│ ├── LastTouchedAnchorOrImageJS.swift # Touch tracking for context menu -│ ├── OnLoadResourceJS.swift # Resource loading tracking -│ ├── OnWindowBlurEventJS.swift # Window blur event -│ ├── OnWindowFocusEventJS.swift # Window focus event -│ ├── OriginalViewPortMetaTagContentJS.swift # Viewport meta capture -│ ├── PluginScriptsUtil.swift # Script utilities -│ ├── PrintJS.swift # Print handling -│ ├── PromisePolyfillJS.swift # Promise polyfill -│ ├── SupportZoomJS.swift # Zoom control -│ ├── WebMessageChannelJS.swift # WebMessage channel variables -│ ├── WebMessageListenerJS.swift # PostMessage API -│ └── WindowIdJS.swift # Window ID management -│ -├── UIApplication/ # Application utilities -│ └── VisibleViewController.swift # Get visible view controller -│ -└── Types/ # Type definitions -``` - ---- - -## Platform Requirements - -- iOS 12.0+ -- Xcode version >= 15.0 -- Swift language support required - -## Native APIs Used - -- [WKWebView](https://developer.apple.com/documentation/webkit/wkwebview) -- Uses `UiKitView` for rendering - ---- - -## Swift Utilities Reference - -### `Util.swift` - General Utilities - -| Method | Description | -|--------|-------------| -| `Util.getUrlAsset(plugin:assetFilePath:)` | Get URL for Flutter asset file | -| `Util.getAbsPathAsset(plugin:assetFilePath:)` | Get absolute path for Flutter asset | -| `Util.convertToDictionary(text:)` | Convert JSON string to Dictionary | -| `Util.JSONStringify(value:prettyPrinted:)` | Convert value to JSON string | -| `Util.getContentWorld(name:)` | Get WKContentWorld by name (iOS 14+) | -| `Util.getDataDetectorType(type:)` | Convert string to WKDataDetectorTypes | -| `Util.getDataDetectorTypeString(type:)` | Convert WKDataDetectorTypes to strings | -| `Util.getDecelerationRate(type:)` | Get UIScrollView.DecelerationRate | -| `Util.getDecelerationRateString(type:)` | Convert DecelerationRate to string | -| `Util.isIPv4(address:)` | Check if string is IPv4 address | -| `Util.isIPv6(address:)` | Check if string is IPv6 address | -| `Util.isIpAddress(address:)` | Check if string is IP address | -| `Util.normalizeIPv6(address:)` | Normalize IPv6 address to full form | - -**Usage:** -```swift -// Asset loading -let url = try Util.getUrlAsset(plugin: plugin, assetFilePath: "assets/page.html") - -// JSON handling -let dict = Util.convertToDictionary(text: jsonString) -let json = Util.JSONStringify(value: myDict, prettyPrinted: true) - -// Content worlds (iOS 14+) -let world = Util.getContentWorld(name: "myWorld") - -// IP validation -if Util.isIpAddress(address: host) { ... } -``` - ---- - -### `PlatformUtil.swift` - Platform Utilities - -| Method | Description | -|--------|-------------| -| `PlatformUtil.getSystemVersion()` | Get iOS version string | -| `PlatformUtil.getLocaleFromString(locale:)` | Convert locale string to Locale | -| `PlatformUtil.getDateFromMilliseconds(date:)` | Convert milliseconds to Date | -| `PlatformUtil.formatDate(date:format:locale:timezone:)` | Format date with locale/timezone | - -**Usage:** -```swift -let version = UIDevice.current.systemVersion -let locale = PlatformUtil.getLocaleFromString(locale: "en_US") -let formatted = PlatformUtil.formatDate(date: timestamp, format: "yyyy-MM-dd", locale: locale, timezone: .current) -``` - ---- - -### `LeakAvoider.swift` - Memory Leak Prevention - -Used to prevent retain cycles with WKWebView delegates: - -```swift -// LeakAvoider wraps the actual delegate to prevent retain cycles -let leakAvoider = LeakAvoider(delegate: self) -configuration.userContentController.add(leakAvoider, name: "handler") -``` - ---- - -### `WKProcessPoolManager.swift` - Process Pool Management - -Manages shared WKProcessPool instances for session sharing across WebViews: - -| Property/Method | Description | -|-----------------|-------------| -| `WKProcessPoolManager.shared` | Singleton instance | -| `getProcessPool(processPoolId:)` | Get/create process pool by ID | - ---- - -### Common Swift Patterns - -#### FlutterMethodChannel Response - -```swift -public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "myMethod": - let param = arguments?["param"] as? String ?? "" - // Do work... - result(returnValue) - default: - result(FlutterMethodNotImplemented) - } -} -``` - -#### Converting to Flutter Map - -```swift -public func toMap() -> [String: Any?] { - return [ - "field1": field1, - "field2": field2, - "optionalField": optionalField // nil becomes null in Dart - ] -} -``` - -#### Parsing from Flutter Map - -```swift -public static func fromMap(map: [String: Any?]?) -> MyType? { - guard let map = map else { return nil } - return MyType( - field1: map["field1"] as? String ?? "", - field2: map["field2"] as? Int ?? 0, - optionalField: map["optionalField"] as? String - ) -} -``` - ---- - -## Plugin Scripts JS Reference - -JavaScript files injected into WebViews for native-web communication: - -| Script | File | Description | -|--------|------|-------------| -| **JavaScriptBridgeJS** | `JavaScriptBridgeJS.swift` | Core bridge enabling `window.flutter_inappwebview.callHandler()` for Dart-JS communication. Sets up Promise-based message passing via `WKScriptMessageHandler`. | -| **ConsoleLogJS** | `ConsoleLogJS.swift` | Intercepts `console.log/debug/error/info/warn` and forwards messages to `onConsoleMessage` callback. Main frame only. | -| **InterceptAjaxRequestJS** | `InterceptAjaxRequestJS.swift` | Wraps `XMLHttpRequest` to intercept AJAX requests. Enables `shouldInterceptAjaxRequest`, `onAjaxReadyStateChange`, `onAjaxProgress` callbacks. | -| **InterceptFetchRequestJS** | `InterceptFetchRequestJS.swift` | Wraps `window.fetch()` to intercept Fetch API requests. Enables `shouldInterceptFetchRequest` callback. | -| **OnLoadResourceJS** | `OnLoadResourceJS.swift` | Uses `PerformanceObserver` to track resource loading (images, scripts, etc.). Enables `onLoadResource` callback. | -| **PrintJS** | `PrintJS.swift` | Overrides `window.print()` to trigger `onPrintRequest` callback instead of native print dialog. | -| **PromisePolyfillJS** | `PromisePolyfillJS.swift` | Polyfill for `Promise` API on older WebKit versions using RSVP.js library. | -| **FindTextHighlightJS** | `FindTextHighlightJS.swift` | JavaScript-based text search and highlighting for `FindInteractionController`. Highlights matches with CSS spans. | -| **WebMessageListenerJS** | `WebMessageListenerJS.swift` | Implements `FlutterInAppWebViewWebMessageListener` class for `postMessage` API. | -| **WebMessageChannelJS** | `WebMessageChannelJS.swift` | Variable definitions for `WebMessageChannel` ports storage. | -| **EnableViewportScaleJS** | `EnableViewportScaleJS.swift` | Adds viewport meta tag with `width=device-width` when `enableViewportScale` is true. | -| **SupportZoomJS** | `SupportZoomJS.swift` | Modifies viewport meta tag to disable/enable user zooming via `user-scalable=no`. | -| **LastTouchedAnchorOrImageJS** | `LastTouchedAnchorOrImageJS.swift` | Tracks touch events on links/images for context menu. Stores last touched anchor/image info. | -| **FindElementsAtPointJS** | `FindElementsAtPointJS.swift` | Implements hit-test to find elements at coordinates. Returns element type (image, link, input, etc.). | -| **OriginalViewPortMetaTagContentJS** | `OriginalViewPortMetaTagContentJS.swift` | Captures original viewport meta tag content before modifications. | -| **OnWindowBlurEventJS** | `OnWindowBlurEventJS.swift` | Listens for `blur` event on window and triggers `onWindowBlur` callback. | -| **OnWindowFocusEventJS** | `OnWindowFocusEventJS.swift` | Listens for `focus` event on window and triggers `onWindowFocus` callback. | -| **WindowIdJS** | `WindowIdJS.swift` | Manages window ID for multi-window scenarios (e.g., `window.open()`). | -| **CallAsyncJavaScriptBelowIOS14WrapperJS** | `CallAsyncJavaScript...swift` | Wrapper for `callAsyncJavaScript` on iOS versions below 14 that don't support native API. | - ---- - -## Dart-Side Development - -For Dart-only changes: -1. Implement platform interface from `flutter_inappwebview_platform_interface` -2. Extend `Platform*CreationParams` for iOS-specific parameters -3. Register in `IOSInAppWebViewPlatform.registerWith()` -4. iOS-specific features: `WebAuthenticationSession`, Safari-style callbacks - -## Native Code Development - -When modifying Swift/Obj-C code: -- Located in `ios/Classes/` -- Main plugin class: `InAppWebViewFlutterPlugin` -- Use FlutterMethodChannel for Dart-native communication -- Common workarounds exist for SSL certificate handling (see `WebViewChannelDelegate.swift`) - -## Build Commands - -```bash -cd flutter_inappwebview_ios && flutter pub get -cd example && flutter build ios --debug --no-codesign -``` - -## Info.plist Requirements - -Apps may need to add: -- `NSAppTransportSecurity` for HTTP URLs -- Camera/microphone permissions for WebRTC -- `NSFaceIDUsageDescription` if using Face ID authentication - -## Debugging & Inspection - -- **Safari Web Inspector**: - - Enable "Web Inspector" in Safari settings on your Mac (Preferences > Advanced). - - Enable "Web Inspector" on your iOS device (Settings > Safari > Advanced). - - Connect device via USB. - - Open Safari on Mac > Develop > [Device Name] > [Page Title]. -- **Inspectable API**: - - For iOS 16.4+, `isInspectable` setting must be `true` (default in debug builds). -- **Logs**: Use `print()` in Swift or `NSLog` in Obj-C. - diff --git a/.github/instructions/linux.instructions.md b/.github/instructions/linux.instructions.md deleted file mode 100644 index 25d9c5ee56..0000000000 --- a/.github/instructions/linux.instructions.md +++ /dev/null @@ -1,326 +0,0 @@ ---- -applyTo: "flutter_inappwebview_linux/**" ---- - -# Linux Platform Implementation Instructions - -## Implemented Dart Classes - -| Class | File | Description | -|-------|------|-------------| -| \`LinuxInAppWebViewPlatform\` | \`inappwebview_platform.dart\` | Platform factory - registers all Linux implementations | -| \`LinuxInAppWebViewWidget\` | \`in_app_webview/in_app_webview.dart\` | WebView widget using texture-based rendering | -| \`LinuxInAppWebViewController\` | \`in_app_webview/in_app_webview_controller.dart\` | WPE WebKit controller | -| \`LinuxHeadlessInAppWebView\` | \`in_app_webview/headless_in_app_webview.dart\` | Offscreen WebView | -| \`LinuxInAppBrowser\` | \`in_app_browser/\` | Full-screen browser | -| \`LinuxCookieManager\` | \`cookie_manager/\` | WebKit cookie management | -| \`LinuxWebStorageManager\` | \`web_storage/\` | Website data management | -| \`LinuxFindInteractionController\` | \`find_interaction/\` | Find in page | -| \`LinuxWebMessageChannel/Port/Listener\` | \`web_message/\` | WKScriptMessageHandler wrapper | -| \`LinuxJavaScriptReplyProxy\` | \`web_message/\` | JavaScript reply proxy | -| \`LinuxProxyController\` | \`proxy_controller/\` | Proxy configuration | -| \`LinuxHttpAuthCredentialDatabase\` | \`http_auth_credentials_database.dart\` | HTTP auth credentials storage | -| \`LinuxWebViewEnvironment\` | \`webview_environment/\` | WebView environment configuration | - ---- - -## Native Code Structure - -\`\`\` -linux/ -├── CMakeLists.txt # CMake build config (links WPE WebKit) -├── flutter_inappwebview_linux_plugin.cc # Plugin entry point -├── flutter_inappwebview_linux_plugin_private.h -│ -├── plugin_instance.cc/h # Plugin instance management -├── cookie_manager.cc/h # WebKit cookie manager wrapper -├── web_storage_manager.cc/h # WebKit website data manager -├── credential_database.cc/h # HTTP auth credentials storage -├── proxy_manager.cc/h # Proxy configuration -├── webview_environment.cc/h # WebView environment configuration -│ -├── in_app_webview/ # Core WPE WebKit implementation -│ ├── in_app_webview.cc/h # Main WebView wrapper (5000+ lines) -│ ├── in_app_webview_manager.cc/h # WebView instance management -│ ├── in_app_webview_settings.cc/h # Settings mapping to WPE WebKit -│ ├── webview_channel_delegate.cc/h # Dart-native bridge (MethodChannel) -│ ├── user_content_controller.cc/h # Script injection (UserContentManager) -│ ├── custom_platform_view.cc/h # Flutter platform view integration -│ ├── inappwebview_texture.cc/h # Base texture class for rendering -│ ├── inappwebview_egl_texture.cc/h # EGL texture rendering (DMA-BUF) -│ └── simd_convert.h # SIMD color conversion utilities -│ -├── headless_in_app_webview/ # Offscreen WebView (WPE is inherently headless) -│ ├── headless_in_app_webview.cc/h # Headless WebView implementation -│ └── headless_in_app_webview_manager.cc/h # Instance management -│ -├── in_app_browser/ # Browser implementation -│ ├── in_app_browser.cc/h # Browser window implementation -│ ├── in_app_browser_manager.cc/h # Instance management -│ ├── in_app_browser_settings.cc/h # Browser settings -│ └── in_app_browser_channel_delegate.cc/h # Channel communication -│ -├── find_interaction/ # Find in page -│ ├── find_interaction_controller.cc/h # Find controller -│ └── find_interaction_channel_delegate.cc/h # Channel communication -│ -├── web_message/ # WKScriptMessageHandler implementation -│ ├── web_message_channel.cc/h # WebMessageChannel wrapper -│ ├── web_message_listener.cc/h # WebMessageListener implementation -│ └── web_message_listener_channel_delegate.cc/h # Listener channel -│ -├── content_blocker/ # Content blocking -│ └── content_blocker_handler.cc/h # Content blocker handler -│ -├── plugin_scripts_js/ # Injected JavaScript for bridge -│ ├── javascript_bridge_js.h # Core JS bridge -│ ├── console_log_js.h # Console interception -│ ├── intercept_ajax_request_js.h # AJAX interception -│ ├── intercept_fetch_request_js.h # Fetch API interception -│ ├── on_load_resource_js.h # Resource loading tracking -│ ├── print_interception_js.h # Print request handling -│ ├── web_message_listener_js.h # PostMessage API -│ ├── web_message_channel_js.h # WebMessage channel variables -│ ├── window_id_js.h # Window ID management -│ ├── color_input_js.h # Color input handling -│ ├── date_input_js.h # Date input handling -│ └── cursor_detection_js.h # Cursor detection for hover states -│ -├── utils/ # Utility functions -│ ├── flutter.h # FlValue serialization utilities -│ ├── string.h # String utilities -│ ├── map.h # Map utilities -│ ├── vector.h # Vector utilities -│ ├── uri.h # URI utilities -│ ├── log.h # Logging utilities -│ ├── defer.h # RAII cleanup utilities -│ ├── uuid.h # UUID generation -│ ├── util.h # General utilities -│ ├── gl_context.h # OpenGL context utilities -│ └── software_rendering.cc/h # Software rendering fallback -│ -└── types/ # Type definitions -\`\`\` - ---- - -## Platform Requirements - -- **Required**: WPE WebKit libraries (\`libwpe\`, \`wpewebkit\`) -- **Optional**: \`wpebackend-fdo\` (legacy fallback backend - only needed if WPEPlatform is not available) - -## Native APIs Used - -- [WPE WebKit 2.0](https://wpewebkit.org/) for offscreen rendering -- Official documentation: https://wpewebkit.org/reference(zero-copy GPU textures) or SHM (shared memory) as fallback -- Backend: WPEPlatform (default, modern API) or WPEBackend-FDO (legacy fallback)-2.0/index.html -- Uses texture-based platform view rendering via DMA-BUF or SHM as fallback - -### Linux (WPE WebKit 2.0) Key Classes - -For Linux platform implementation, the following WPE WebKit classes are used: - -| Class | Purpose | API Docs | -|-------|---------|----------| -| `WebKitWebView` | Main WebView widget | [WebView](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/class.WebView.html) | -| `WebKitSettings` | WebView configuration | [Settings](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/class.Settings.html) | -| `WebKitUserContentManager` | User scripts/styles injection | [UserContentManager](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/class.UserContentManager.html) | -| `WebKitCookieManager` | Cookie management | [CookieManager](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/class.CookieManager.html) | -| `WebKitWebsiteDataManager` | Website data storage | [WebsiteDataManager](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/class.WebsiteDataManager.html) | -| `WebKitFindController` | Find in page | [FindController](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/class.FindController.html) | -| `WebKitDownload` | Download handling | [Download](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/class.Download.html) | -| `WebKitURISchemeRequest` | Custom URI scheme | [URISchemeRequest](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/class.URISchemeRequest.html) | -| `WebKitWebContext` | Shared browsing context | [WebContext](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/class.WebContext.html) | - -> **Important**: Linux uses **WPE WebKit** (for headless/embedded rendering), NOT WebKitGTK. Always use `https://wpewebkit.org/reference/stable/wpe-webkit-2.0/` for API documentation. - -## Debugging & Inspection - -- **Inspector**: Use `WEBKIT_INSPECTOR_SERVER` environment variable to enable remote inspection. - Then open `inspector://127.0.0.1:9222` in a WebKit-based browser (like Epiphany/GNOME Web) or use `http://127.0.0.1:9222` in Chrome/Edge. -- **Logs**: Use `debugLog()` in C++ which prints to stdout/stderr. -- **GDB**: Standard GDB debugging works for the native plugin code. - ---- - -## C++ Utilities Reference - -### \`utils/flutter.h\` - FlValue Serialization - -**ALWAYS use these utilities** when creating new C++ types or working with FlValue. - -#### FlValue Map Building (\`to_fl_map\`, \`make_fl_value\`) - -\`\`\`cpp -#include "../utils/flutter.h" - -FlValue* SomeType::toFlValue() const { - return to_fl_map({ - {"stringField", make_fl_value(someString)}, - {"intField", make_fl_value(someInt)}, - {"optionalField", make_fl_value(optionalValue)}, // auto handles std::optional - {"nullField", make_fl_value(nullptr)}, - }); -} -\`\`\` - -| \`make_fl_value(T)\` | Result | -|--------------------|--------| -| \`nullptr\`, \`std::nullopt\` | \`fl_value_new_null()\` | -| \`bool\` | \`fl_value_new_bool()\` | -| \`int32_t\`, \`int64_t\` | \`fl_value_new_int()\` | -| \`double\` | \`fl_value_new_float()\` | -| \`const char*\`, \`std::string\` | \`fl_value_new_string()\` | -| \`std::vector\` | \`fl_value_new_uint8_list()\` | -| \`std::vector\` | FlValue list (recursive) | -| \`std::map\` | FlValue map (recursive) | -| \`std::optional\` | Value or null | - -#### FlValue Extraction (\`get_fl_map_value\`, \`get_optional_fl_map_value\`) - -\`\`\`cpp -// Constructor from FlValue map -MyType::MyType(FlValue* map) - : stringField(get_fl_map_value(map, "stringField", "")), - intField(get_fl_map_value(map, "intField", 0)), - optionalField(get_optional_fl_map_value(map, "optionalField")) {} -\`\`\` - -| Template Type | With Default | Optional | -|---------------|--------------|----------| -| \`bool\` | ✅ | ✅ | -| \`int32_t\`, \`int64_t\` | ✅ | ✅ | -| \`double\` | ✅ | ✅ | -| \`std::string\` | ✅ | ✅ | -| \`std::vector\` | ✅ | ✅ | -| \`std::vector\` | ❌ | ✅ | -| \`std::map\` | ❌ | ✅ | - -#### Map Checking - -\`\`\`cpp -if (fl_map_contains(map, "key")) { ... } // Key exists (may be null) -if (fl_map_contains_not_null(map, "key")) { ... } // Key exists and not null -\`\`\` - ---- - -### \`utils/string.h\` - String Utilities - -| Function | Description | -|----------|-------------| -| \`string_equals(s1, s2)\` | Compare strings (supports \`std::string\`, \`const char*\`, \`std::optional\`) | -| \`replace_all(source, from, to)\` | Replace all occurrences in-place | -| \`replace_all_copy(source, from, to)\` | Replace all occurrences, return copy | -| \`join(vec, delim)\` | Join vector of strings with delimiter | -| \`split(s, delimiter)\` | Split string into vector | -| \`to_lowercase(s)\` / \`to_lowercase_copy(s)\` | Convert to lowercase | -| \`to_uppercase(s)\` / \`to_uppercase_copy(s)\` | Convert to uppercase | -| \`starts_with(str, prefix)\` | Check if string starts with prefix | -| \`ends_with(str, suffix)\` | Check if string ends with suffix | -| \`string_hash(data)\` | Compile-time string hash (constexpr) | -| \`trim(str)\` | Trim whitespace from both ends | - ---- - -### \`utils/map.h\` - Map Utilities - -| Function | Description | -|----------|-------------| -| \`map_contains(map, key)\` | Check if key exists in map | -| \`map_at_or_null(map, key)\` | Get value or nullptr if not found | -| \`map_at_optional(map, key)\` | Get value as \`std::optional\` | - ---- - -### \`utils/vector.h\` - Vector Utilities - -| Function | Description | -|----------|-------------| -| \`vector_remove(vec, el)\` | Remove element from vector | -| \`vector_remove_if(vec, predicate)\` | Remove elements matching predicate | -| \`vector_contains(vec, value)\` | Check if vector contains value | -| \`vector_contains_if(vec, predicate)\` | Check if any element matches predicate | -| \`functional_map(iterable, func)\` | Transform iterable (like JS map) | - ---- - -### \`utils/uri.h\` - URI Utilities - -| Function | Description | -|----------|-------------| -| \`get_origin_from_url(url)\` | Extract origin (scheme + host + port) | -| \`is_valid_url(url)\` | Check if URL is valid | -| \`get_scheme_from_url(url)\` | Extract scheme (http, https, etc.) | -| \`get_host_from_url(url)\` | Extract host | -| \`url_encode(value)\` | URL-encode a string | - ---- - -### \`utils/log.h\` - Logging Utilities - -| Function | Description | -|----------|-------------| -| \`debugLog(msg)\` | Log debug message (only in debug builds) | -| \`errorLog(msg)\` | Log error message | -| \`logGError(error)\` | Log GError with details | -| \`succeededOrLog(error)\` | Return true if no error, log if error | -| \`failedAndLog(error)\` | Return true if error, log it | -| \`failedLog(error)\` | Log error without returning status | - -**Usage with macros** (auto-includes file/line): -\`\`\`cpp -debugLog("Message"); // Logs with file:line prefix -if (succeededOrLog(&error)) { ... } // Check and log GError -\`\`\` - ---- - -### \`utils/defer.h\` - RAII Cleanup Utilities - -| Function | Description | -|----------|-------------| -| \`defer(handle, callback)\` | Create shared_ptr with custom deleter | -| \`make_scope_guard(func)\` | RAII guard that calls func on destruction | - -\`\`\`cpp -auto guard = make_scope_guard([&]() { cleanup(); }); -// cleanup() called when guard goes out of scope -\`\`\` - ---- - -### \`utils/uuid.h\` - UUID Generation - -| Function | Description | -|----------|-------------| -| \`get_uuid()\` | Generate UUID v4 string | - ---- - -### \`utils/util.h\` - General Utilities - -| Function | Description | -|----------|-------------| -| \`make_pointer_optional(ptr)\` | Convert pointer to \`std::optional\` | -| \`variant_to_string(var)\` | Convert \`std::variant\` to string | - ---- - -## Dart-Side Development - -ForExtend \`Platform*CreationParams\` for Linux-specific parameters -3. Register in \`LinuxInAppWebViewPlatform.registerWith()\` -4. Linux-specific features: Texture-based rendering, DMA-BUF GPU integration, WPE WebKit backend selectionterface\` -2. Linux implementation is newer and has fewer features than other platforms -3. Check \`LinuxInAppWebViewPlatform\` for currently supported features - -## Native Code Development - -When modifying C++ code: -- Main plugin class: \`FlutterInappwebviewLinuxPlugin\` -- Core WebView class: \`InAppWebView\` (handles WPE WebKit integration) -- WPE WebKit handles headless rendering to texture via EGL or SHM -- Use provided utilities in \`utils/\` for FlValue serialization, string operations, etc. APIs for maintainability -- Plugin class: \`FlutterInappwebviewLinuxPlugin\` -- WPE WebKit handles headless rendering to texture diff --git a/.github/instructions/macos.instructions.md b/.github/instructions/macos.instructions.md deleted file mode 100644 index 1a9ec573d3..0000000000 --- a/.github/instructions/macos.instructions.md +++ /dev/null @@ -1,338 +0,0 @@ ---- -applyTo: "flutter_inappwebview_macos/**" ---- - -# macOS Platform Implementation Instructions - -## Implemented Dart Classes - -| Class | File | Description | -|-------|------|-------------| -| `MacOSInAppWebViewPlatform` | `inappwebview_platform.dart` | Platform factory - registers all macOS implementations | -| `MacOSInAppWebView` | `in_app_webview/in_app_webview.dart` | WebView widget using `AppKitView` | -| `MacOSInAppWebViewController` | `in_app_webview/in_app_webview_controller.dart` | WebView controller | -| `MacOSHeadlessInAppWebView` | `in_app_webview/headless_in_app_webview.dart` | Offscreen WebView | -| `MacOSInAppBrowser` | `in_app_browser/` | Full-screen browser window | -| `MacOSCookieManager` | `cookie_manager.dart` | WKHTTPCookieStore wrapper | -| `MacOSWebStorage` | `web_storage/` | WKWebsiteDataStore wrapper | -| `MacOSFindInteractionController` | `find_interaction/` | NSFindPanelAction wrapper | -| `MacOSPrintJobController` | `print_job/` | NSPrintOperation wrapper | -| `MacOSWebMessageChannel/Port/Listener` | `web_message/` | WKScriptMessageHandler | -| `MacOSHttpAuthCredentialDatabase` | `http_auth_credentials_database.dart` | URLCredentialStorage | - ---- - -## Native Code Structure - -``` -macos/Classes/ -├── InAppWebViewFlutterPlugin.swift # Plugin entry/registration -│ -├── MyCookieManager.swift # WKHTTPCookieStore wrapper -├── MyWebStorageManager.swift # WKWebsiteDataStore wrapper -├── CredentialDatabase.swift # URLCredentialStorage wrapper -├── ProxyManager.swift # Proxy configuration -├── WKProcessPoolManager.swift # Process pool management -│ -├── LeakAvoider.swift # Memory leak prevention helper -├── PlatformUtil.swift # Platform utilities (date formatting, system version) -├── Util.swift # General utilities (see below) -├── ISettings.swift # Settings protocol -│ -├── InAppWebView/ # Core WKWebView implementation -│ ├── InAppWebView.swift # WKWebView subclass (main implementation) -│ ├── InAppWebViewManager.swift # WebView instance management -│ ├── InAppWebViewSettings.swift # Settings mapping to WKWebView -│ ├── FlutterWebViewController.swift # ViewController for platform view -│ ├── FlutterWebViewFactory.swift # PlatformView factory -│ ├── WebViewChannelDelegate.swift # Dart-native bridge (MethodChannel) -│ ├── WebViewChannelDelegateMethods.swift # Channel delegate method implementations -│ ├── ContextMenuSettings.swift # Context menu settings -│ ├── CustomSchemeHandler.swift # Custom URL scheme handling -│ │ -│ └── WebMessage/ # WKScriptMessageHandler implementation -│ ├── WebMessageChannel.swift # WebMessageChannel wrapper -│ ├── WebMessageChannelChannelDelegate.swift # Channel communication -│ ├── WebMessageListener.swift # WebMessageListener implementation -│ └── WebMessageListenerChannelDelegate.swift # Listener channel -│ -├── HeadlessInAppWebView/ # Offscreen WebView -│ ├── HeadlessInAppWebView.swift # Headless WebView implementation -│ ├── HeadlessInAppWebViewManager.swift # Instance management -│ └── HeadlessWebViewChannelDelegate.swift # Channel delegate for headless -│ -├── InAppBrowser/ # Browser NSWindow/NSWindowController -│ ├── InAppBrowserWebViewController.swift # Browser view controller -│ ├── InAppBrowserManager.swift # Instance management -│ ├── InAppBrowserWindow.swift # NSWindow subclass -│ ├── InAppBrowserSettings.swift # Browser settings -│ ├── InAppBrowserChannelDelegate.swift # Channel communication -│ └── InAppBrowserDelegate.swift # Browser delegate protocol -│ -├── FindInteraction/ # NSFindPanelAction -│ ├── FindInteractionChannelDelegate.swift # Channel communication -│ ├── FindInteractionController.swift # Find controller -│ └── FindInteractionSettings.swift # Find settings -│ -├── PrintJob/ # NSPrintOperation -│ ├── CustomUIPrintPageRenderer.swift # Custom page renderer -│ ├── PrintAttributes.swift # Print attributes -│ ├── PrintJobChannelDelegate.swift # Channel communication -│ ├── PrintJobController.swift # Print job controller -│ ├── PrintJobInfo.swift # Print job info -│ ├── PrintJobManager.swift # Instance management -│ └── PrintJobSettings.swift # Print settings -│ -├── WebAuthenticationSession/ # ASWebAuthenticationSession (macOS 10.15+) -│ ├── WebAuthenticationSession.swift # Session wrapper -│ ├── WebAuthenticationSessionChannelDelegate.swift # Channel communication -│ ├── WebAuthenticationSessionManager.swift # Instance management -│ └── WebAuthenticationSessionSettings.swift # Session settings -│ -├── PluginScriptsJS/ # Injected JavaScript for bridge -│ ├── CallAsyncJavaScriptBelowIOS14WrapperJS.swift # Async JS wrapper for older macOS -│ ├── ConsoleLogJS.swift # Console interception -│ ├── EnableViewportScaleJS.swift # Viewport scaling -│ ├── FindElementsAtPointJS.swift # Hit-test elements -│ ├── FindTextHighlightJS.swift # Text search highlighting -│ ├── InterceptAjaxRequestJS.swift # AJAX interception -│ ├── InterceptFetchRequestJS.swift # Fetch API interception -│ ├── JavaScriptBridgeJS.swift # Core JS bridge -│ ├── OnLoadResourceJS.swift # Resource loading tracking -│ ├── OnScrollChangedJS.swift # Scroll event tracking (macOS-specific) -│ ├── OnWindowBlurEventJS.swift # Window blur event -│ ├── OnWindowFocusEventJS.swift # Window focus event -│ ├── OriginalViewPortMetaTagContentJS.swift # Viewport meta capture -│ ├── PluginScriptsUtil.swift # Script utilities -│ ├── PrintJS.swift # Print handling -│ ├── PromisePolyfillJS.swift # Promise polyfill -│ ├── SupportZoomJS.swift # Zoom control -│ ├── WebMessageChannelJS.swift # WebMessage channel variables -│ ├── WebMessageListenerJS.swift # PostMessage API -│ └── WindowIdJS.swift # Window ID management -│ -└── Types/ # Type definitions -``` - ---- - -## Platform Requirements - -- macOS 10.14+ -- Xcode version >= 15.0 -- Swift language support required - -## Native APIs Used - -- [WKWebView](https://developer.apple.com/documentation/webkit/wkwebview) -- Uses `AppKitView` for rendering (not UiKitView like iOS) - ---- - -## Swift Utilities Reference - -### `Util.swift` - General Utilities - -| Method | Description | -|--------|-------------| -| `Util.getUrlAsset(plugin:assetFilePath:)` | Get URL for Flutter asset file | -| `Util.getAbsPathAsset(plugin:assetFilePath:)` | Get absolute path for Flutter asset | -| `Util.convertToDictionary(text:)` | Convert JSON string to Dictionary | -| `Util.JSONStringify(value:prettyPrinted:)` | Convert value to JSON string | -| `Util.getContentWorld(name:)` | Get WKContentWorld by name (macOS 11+) | -| `Util.isIPv4(address:)` | Check if string is IPv4 address | -| `Util.isIPv6(address:)` | Check if string is IPv6 address | -| `Util.isIpAddress(address:)` | Check if string is IP address | -| `Util.normalizeIPv6(address:)` | Normalize IPv6 address to full form | - -**Usage:** -```swift -// Asset loading -let url = try Util.getUrlAsset(plugin: plugin, assetFilePath: "assets/page.html") - -// JSON handling -let dict = Util.convertToDictionary(text: jsonString) -let json = Util.JSONStringify(value: myDict, prettyPrinted: true) - -// Content worlds (macOS 11+) -let world = Util.getContentWorld(name: "myWorld") - -// IP validation -if Util.isIpAddress(address: host) { ... } -``` - -**Note:** macOS does not have `UIScrollView.DecelerationRate` or `WKDataDetectorTypes`, so those utilities are iOS-only. - ---- - -### `PlatformUtil.swift` - Platform Utilities - -| Method | Description | -|--------|-------------| -| `PlatformUtil.getSystemVersion()` | Get macOS version string | -| `PlatformUtil.getLocaleFromString(locale:)` | Convert locale string to Locale | -| `PlatformUtil.getDateFromMilliseconds(date:)` | Convert milliseconds to Date | -| `PlatformUtil.formatDate(date:format:locale:timezone:)` | Format date with locale/timezone | - -**Usage:** -```swift -let version = ProcessInfo.processInfo.operatingSystemVersionString -let locale = PlatformUtil.getLocaleFromString(locale: "en_US") -let formatted = PlatformUtil.formatDate(date: timestamp, format: "yyyy-MM-dd", locale: locale, timezone: .current) -``` - ---- - -### `LeakAvoider.swift` - Memory Leak Prevention - -Used to prevent retain cycles with WKWebView delegates: - -```swift -// LeakAvoider wraps the actual delegate to prevent retain cycles -let leakAvoider = LeakAvoider(delegate: self) -configuration.userContentController.add(leakAvoider, name: "handler") -``` - ---- - -### `WKProcessPoolManager.swift` - Process Pool Management - -Manages shared WKProcessPool instances for session sharing across WebViews: - -| Property/Method | Description | -|-----------------|-------------| -| `WKProcessPoolManager.shared` | Singleton instance | -| `getProcessPool(processPoolId:)` | Get/create process pool by ID | - ---- - -### Common Swift Patterns - -#### FlutterMethodChannel Response - -```swift -public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? [String: Any] - - switch call.method { - case "myMethod": - let param = arguments?["param"] as? String ?? "" - // Do work... - result(returnValue) - default: - result(FlutterMethodNotImplemented) - } -} -``` - -#### Converting to Flutter Map - -```swift -public func toMap() -> [String: Any?] { - return [ - "field1": field1, - "field2": field2, - "optionalField": optionalField // nil becomes null in Dart - ] -} -``` - -#### Parsing from Flutter Map - -```swift -public static func fromMap(map: [String: Any?]?) -> MyType? { - guard let map = map else { return nil } - return MyType( - field1: map["field1"] as? String ?? "", - field2: map["field2"] as? Int ?? 0, - optionalField: map["optionalField"] as? String - ) -} -``` - ---- - -## macOS vs iOS Differences - -| Aspect | iOS | macOS | -|--------|-----|-------| -| View Type | `UiKitView` | `AppKitView` | -| Browser Window | UIViewController | NSWindow/NSWindowController | -| Find Panel | UIFindInteraction | NSFindPanelAction | -| Print | UIPrintInteractionController | NSPrintOperation | -| Scroll Deceleration | UIScrollView.DecelerationRate | Not applicable | -| Data Detectors | WKDataDetectorTypes | Not applicable | -| Safari Browser | SFSafariViewController | Not available | -| WebAuthSession | ASWebAuthenticationSession | Not implemented | - ---- - -## Plugin Scripts JS Reference - -JavaScript files injected into WebViews for native-web communication: - -| Script | File | Description | -|--------|------|-------------| -| **JavaScriptBridgeJS** | `JavaScriptBridgeJS.swift` | Core bridge enabling `window.flutter_inappwebview.callHandler()` for Dart-JS communication. | -| **ConsoleLogJS** | `ConsoleLogJS.swift` | Intercepts `console.log/debug/error/info/warn` and forwards to `onConsoleMessage`. | -| **InterceptAjaxRequestJS** | `InterceptAjaxRequestJS.swift` | Wraps `XMLHttpRequest` to intercept AJAX requests. | -| **InterceptFetchRequestJS** | `InterceptFetchRequestJS.swift` | Wraps `window.fetch()` to intercept Fetch API requests. | -| **OnLoadResourceJS** | `OnLoadResourceJS.swift` | Uses `PerformanceObserver` to track resource loading. | -| **OnScrollChangedJS** | `OnScrollChangedJS.swift` | Listens for scroll events and triggers `onScrollChanged` callback (macOS-specific). | -| **PrintJS** | `PrintJS.swift` | Overrides `window.print()` to trigger `onPrintRequest` callback. | -| **PromisePolyfillJS** | `PromisePolyfillJS.swift` | Polyfill for `Promise` API on older WebKit versions. | -| **FindTextHighlightJS** | `FindTextHighlightJS.swift` | JavaScript-based text search and highlighting. | -| **WebMessageListenerJS** | `WebMessageListenerJS.swift` | Implements `FlutterInAppWebViewWebMessageListener` for `postMessage` API. | -| **WebMessageChannelJS** | `WebMessageChannelJS.swift` | Variable definitions for `WebMessageChannel` ports. | -| **EnableViewportScaleJS** | `EnableViewportScaleJS.swift` | Adds viewport meta tag for viewport scaling. | -| **SupportZoomJS** | `SupportZoomJS.swift` | Modifies viewport meta tag for zoom control. | -| **FindElementsAtPointJS** | `FindElementsAtPointJS.swift` | Hit-test to find elements at coordinates. | -| **OriginalViewPortMetaTagContentJS** | `OriginalViewPortMetaTagContentJS.swift` | Captures original viewport meta tag. | -| **OnWindowBlurEventJS** | `OnWindowBlurEventJS.swift` | Triggers `onWindowBlur` callback. | -| **OnWindowFocusEventJS** | `OnWindowFocusEventJS.swift` | Triggers `onWindowFocus` callback. | -| **WindowIdJS** | `WindowIdJS.swift` | Manages window ID for multi-window scenarios. | -| **CallAsyncJavaScriptBelowIOS14WrapperJS** | `CallAsyncJavaScript...swift` | Wrapper for `callAsyncJavaScript` on older macOS. | - -**Note:** macOS does not have `LastTouchedAnchorOrImageJS` (touch-specific) but adds `OnScrollChangedJS` for scroll tracking. - ---- - -## Dart-Side Development - -For Dart-only changes: -1. Implement platform interface from `flutter_inappwebview_platform_interface` -2. Extend `Platform*CreationParams` for macOS-specific parameters -3. Register in `MacOSInAppWebViewPlatform.registerWith()` -4. Note: macOS lacks `ChromeSafariBrowser` and `WebAuthenticationSession` - -## Native Code Development - -When modifying Swift code: -- Located in `macos/Classes/` -- Main plugin class: `InAppWebViewFlutterPlugin` -- Use FlutterMethodChannel for Dart-native communication -- macOS uses AppKit (NSWindow, NSView) vs iOS UIKit (UIWindow, UIView) - -## Build Commands - -```bash -cd flutter_inappwebview_macos && flutter pub get -cd example && flutter build macos --debug -``` - -## Entitlements - -Apps may need to add entitlements: -- `com.apple.security.network.client` - Network access -- `com.apple.security.network.server` - Local server access -- App Sandbox entitlements for file access - -## Debugging & Inspection - -- **Safari Web Inspector**: - - Enable "Web Inspector" in Safari settings (Preferences > Advanced). - - Open Safari > Develop > [Computer Name] > [Page Title]. -- **Inspectable API**: - - For macOS 13.3+, `isInspectable` setting must be `true` (default in debug builds). -- **Logs**: Use `print()` in Swift. - diff --git a/.github/instructions/platform-interface.instructions.md b/.github/instructions/platform-interface.instructions.md deleted file mode 100644 index e66b8750f7..0000000000 --- a/.github/instructions/platform-interface.instructions.md +++ /dev/null @@ -1,181 +0,0 @@ ---- -applyTo: "flutter_inappwebview_platform_interface/**" ---- - -# Platform Interface Package Instructions - -This is the **source of truth** for the entire plugin. All types, enums, and platform contracts are defined here. -Used by all platform implementations and the main plugin-facing-API package. -When adding new features here, you must propagate them also to the main `flutter_inappwebview` package. - -## Main Platform Contracts - -| Contract Class | File | Description | -|----------------|------|-------------| -| `InAppWebViewPlatform` | `inappwebview_platform.dart` | Factory interface - creates all platform-specific instances | -| `PlatformInAppWebViewWidget` | `in_app_webview/platform_inappwebview_widget.dart` | WebView widget contract | -| `PlatformInAppWebViewController` | `in_app_webview/platform_inappwebview_controller.dart` | WebView controller contract | -| `PlatformHeadlessInAppWebView` | `in_app_webview/platform_headless_in_app_webview.dart` | Offscreen WebView contract | -| `PlatformWebView` | `in_app_webview/platform_webview.dart` | Base WebView interface | -| `PlatformInAppBrowser` | `in_app_browser/platform_in_app_browser.dart` | Browser window contract | -| `PlatformChromeSafariBrowser` | `chrome_safari_browser/platform_chrome_safari_browser.dart` | Chrome Custom Tabs / SFSafariViewController | -| `PlatformCookieManager` | `platform_cookie_manager.dart` | Cookie management contract | -| `PlatformWebStorage` | `web_storage/platform_web_storage.dart` | Storage APIs contract | -| `PlatformFindInteractionController` | `find_interaction/platform_find_interaction_controller.dart` | Find-in-page contract | -| `PlatformPrintJobController` | `print_job/platform_print_job_controller.dart` | Print functionality contract | -| `PlatformPullToRefreshController` | `pull_to_refresh/platform_pull_to_refresh_controller.dart` | Pull-to-refresh contract | -| `PlatformWebMessageChannel/Port/Listener` | `web_message/` | postMessage API contracts | -| `PlatformWebAuthenticationSession` | `web_authentication_session/platform_web_authentication_session.dart` | Auth session contract | -| `PlatformHttpAuthCredentialDatabase` | `platform_http_auth_credentials_database.dart` | Credential storage contract | -| `PlatformProcessGlobalConfig` | `platform_process_global_config.dart` | Process configuration contract | -| `PlatformProxyController` | `platform_proxy_controller.dart` | Proxy settings contract | -| `PlatformServiceWorkerController` | `platform_service_worker_controller.dart` | Service worker contract | -| `PlatformTracingController` | `platform_tracing_controller.dart` | Tracing contract | -| `PlatformWebViewEnvironment` | `webview_environment/platform_webview_environment.dart` | WebView2 environment (Windows) | -| `PlatformWebViewFeature` | `platform_webview_feature.dart` | Feature detection contract | - -## Directory Structure - -``` -lib/src/ -├── inappwebview_platform.dart # Main factory interface -├── main.dart # Exports -├── in_app_webview/ # Core WebView contracts -│ ├── platform_inappwebview_widget.dart/.g.dart -│ ├── platform_inappwebview_controller.dart/.g.dart -│ ├── platform_headless_in_app_webview.dart/.g.dart -│ ├── platform_webview.dart/.g.dart -│ ├── in_app_webview_settings.dart/.g.dart # InAppWebViewSettings -│ ├── android/ # Android-specific settings -│ └── apple/ # iOS/macOS-specific settings -├── in_app_browser/ # InAppBrowser contracts -├── chrome_safari_browser/ # Chrome/Safari browser contracts -├── find_interaction/ # Find-in-page contracts -├── print_job/ # Print job contracts -├── pull_to_refresh/ # Pull-to-refresh contracts -├── web_message/ # WebMessage contracts -├── web_storage/ # WebStorage contracts -├── web_authentication_session/ # Auth session contracts -├── webview_environment/ # WebView2 environment (Windows) -├── context_menu/ # Context menu types -├── x509_certificate/ # X509 certificate parsing -├── types/ # 200+ shared types & enums -│ ├── navigation_action.dart # Navigation types -│ ├── url_request.dart # Request types -│ ├── permission_*.dart # Permission types -│ ├── ssl_*.dart # SSL types -│ └── ... # Many more types -├── platform_cookie_manager.dart/.g.dart -├── platform_http_auth_credentials_database.dart/.g.dart -├── platform_process_global_config.dart/.g.dart -├── platform_proxy_controller.dart/.g.dart -├── platform_service_worker_controller.dart/.g.dart -├── platform_tracing_controller.dart/.g.dart -├── platform_webview_asset_loader.dart/.g.dart -├── platform_webview_feature.dart/.g.dart -├── content_blocker.dart # Content blocking rules -├── web_uri.dart # URI utilities -└── util.dart # General utilities -``` - -## Key Rules - -1. **Code Generation**: Files with `@ExchangeableObject`, `@ExchangeableEnum`, or `@SupportedPlatforms` annotations generate `*.g.dart` files. After modifying, always run: - ```bash - npm run build - # Or directly: - cd flutter_inappwebview_platform_interface - flutter pub run build_runner build --delete-conflicting-outputs - ``` - -2. **Never Edit Generated Files**: Files ending in `.g.dart` are auto-generated. Modify the source file (same name without `.g`) instead. - -3. **Propagation**: Changes here require updates to ALL platform packages AND the main `flutter_inappwebview` package. - -## InAppWebViewSettings - -The main settings class for WebView configuration: - -- **Source**: `lib/src/in_app_webview/in_app_webview_settings.dart` (`InAppWebViewSettings_` → generates `InAppWebViewSettings`) -- **Role**: Exhaustive configuration bag for `InAppWebView`/`InAppBrowser`. Mirrors platform capabilities via `@SupportedPlatforms`. -- **Defaults**: Flags like `useShouldOverrideUrlLoading`, `useOnLoadResource`, `useShouldInterceptRequest` auto-infer to `true` when callbacks are implemented. -- **Deprecated fields**: Use `@ExchangeableObjectProperty(leaveDeprecatedInToMapMethod: true)` for backward compatibility. -- **Complex types**: Uses exchangeable enums/objects like `MixedContentMode_`, `WebViewAssetLoader_`, `RendererPriorityPolicy_`. - -## Adding New Features - -1. Define the contract class (`Platform*`) extending `PlatformInterface` -2. Create corresponding `Platform*CreationParams` class -3. Add `@SupportedPlatforms` annotations to document platform availability -4. Use `{@template}` and `{@macro}` for documentation -5. Add factory methods to `InAppWebViewPlatform` class -6. Run code generation: `npm run build` -7. **Propagate** to all platform packages and the app-facing package - -## Supported Platforms Pattern - -When implementing a new platform interface class: - -### 1. Creation Params Class (`Platform*CreationParams`) - -```dart -@SupportedPlatforms(platforms: [WindowsPlatform()]) -@immutable -class PlatformWebViewEnvironmentCreationParams { - const PlatformWebViewEnvironmentCreationParams({this.settings}); - - ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.settings} - /// WebView Environment settings. - ///{@endtemplate} - @SupportedPlatforms(platforms: [WindowsPlatform()]) - final WebViewEnvironmentSettings? settings; - - bool isClassSupported({TargetPlatform? platform}) => - PlatformWebViewEnvironment.isClassSupported(platform: platform); - - bool isPropertySupported(dynamic property, {TargetPlatform? platform}) => - PlatformWebViewEnvironment.isPropertySupported(property, platform: platform); -} -``` - -### 2. Main Interface Class (`Platform*`) - -```dart -@SupportedPlatforms(platforms: [WindowsPlatform()]) -abstract class PlatformWebViewEnvironment extends PlatformInterface implements Disposable { - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.settings} - WebViewEnvironmentSettings? get settings => params.settings; - - bool isClassSupported({TargetPlatform? platform}) => - params.isClassSupported(platform: platform); - - bool isPropertySupported(dynamic property, {TargetPlatform? platform}) => - property is PlatformWebViewEnvironmentCreationParamsProperty - ? params.isPropertySupported(property, platform: platform) - : _PlatformWebViewEnvironmentPropertySupported.isPropertySupported( - property, platform: platform); - - bool isMethodSupported(PlatformWebViewEnvironmentMethod method, - {TargetPlatform? platform}) => - _PlatformWebViewEnvironmentMethodSupported.isMethodSupported(method, - platform: platform); -} -``` - -**Key rules**: -- Use `{@template}` in CreationParams, `{@macro}` in Platform class -- **Don't** repeat `@SupportedPlatforms` on getters that use macros -- `isPropertySupported` must handle both CreationParams and class properties -- Reference implementations: `PlatformPrintJobController`, `PlatformFindInteractionController`, `PlatformCookieManager` - -## Annotations Reference - -```dart -@ExchangeableObject() // Generates toMap(), fromMap(), copy() -@ExchangeableEnum() // Generates enum serialization -@SupportedPlatforms(platforms: [ - AndroidPlatform(available: "21", apiName: "WebView.setAlpha", apiUrl: "..."), - IOSPlatform(available: "12.0", apiName: "WKWebView", note: "Requires iOS 12+"), -]) -@ExchangeableObjectProperty(leaveDeprecatedInToMapMethod: true) // For deprecated fields -``` diff --git a/.github/instructions/plugin-facing-api.instructions.md b/.github/instructions/plugin-facing-api.instructions.md deleted file mode 100644 index 3ff8e9f0fd..0000000000 --- a/.github/instructions/plugin-facing-api.instructions.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -applyTo: "flutter_inappwebview/lib/**,flutter_inappwebview/example/**" ---- - -# App-Facing Package Instructions - -This is the **public API** package that developers depend on. It wraps all platform implementations. - -## Key Rules - -1. **No Platform Logic Here**: This package only wraps platform implementations. Never add platform-specific code. - -2. **Delegate to Platform Interface**: All functionality must delegate to `flutter_inappwebview_platform_interface` types. - -3. **Avoid Breaking Changes**: Public API changes affect all users. Maintain backward compatibility. - -## Directory Structure - -- `lib/flutter_inappwebview.dart` - Main export file -- `lib/src/` - Public API wrappers -- `example/` - Example app and integration tests -- `example/integration_test/` - Integration test suite - -### Source Code Structure (`lib/src/`) - -``` -lib/src/ -├── in_app_webview/ # Core WebView widgets & controllers -│ ├── in_app_webview.dart # InAppWebView widget -│ ├── in_app_webview_controller.dart # Controller -│ ├── headless_in_app_webview.dart # Headless WebView -│ └── ... -├── in_app_browser/ # InAppBrowser -├── chrome_safari_browser/ # ChromeCustomTabs / SFSafariViewController -├── find_interaction/ # Find interaction controller -├── print_job/ # Print job controller -├── pull_to_refresh/ # Pull-to-refresh controller -├── web_message/ # Web Message channels/ports -├── web_storage/ # Web Storage (Local/Session) -├── web_authentication_session/ # Web Authentication Session -├── webview_environment/ # WebView Environment (Windows) -├── cookie_manager.dart # Cookie Manager -├── http_auth_credentials_database.dart # Auth Database -├── process_global_config.dart # Process Global Config -├── proxy_controller.dart # Proxy Controller -├── service_worker_controller.dart # Service Worker Controller -├── tracing_controller.dart # Tracing Controller -└── webview_asset_loader.dart # Asset Loader -``` - -## Adding Public API Classes - -1. Create wrapper class in `lib/src/` -2. Use constructor helpers: `fromPlatformCreationParams`, `fromPlatform` -3. Delegate all methods to the platform implementation -4. Add support check helpers: `isClassSupported`, `isPropertySupported`, `isMethodSupported` - -## Example Pattern - -```dart -class MyFeature { - MyFeature.fromPlatformCreationParams( - PlatformMyFeatureCreationParams params, - ) : this.fromPlatform(platform: PlatformMyFeature(params)); - - MyFeature.fromPlatform({required this.platform}); - - final PlatformMyFeature platform; - - static bool isClassSupported({TargetPlatform? platform}) => - PlatformMyFeature.static().isClassSupported(platform: platform); -} -``` - -## Integration Tests - -Located in `example/integration_test/`: -```bash -# Run with device/emulator -cd flutter_inappwebview/example -NODE_SERVER_IP= flutter driver --driver=test_driver/integration_test.dart \ - --target=integration_test/webview_flutter_test.dart -``` - -Requires `test_node_server/` to be running for full test coverage. diff --git a/.github/instructions/web.instructions.md b/.github/instructions/web.instructions.md deleted file mode 100644 index b95f7315c6..0000000000 --- a/.github/instructions/web.instructions.md +++ /dev/null @@ -1,253 +0,0 @@ ---- -applyTo: "flutter_inappwebview_web/**" ---- - -# Web Platform Implementation Instructions - -## Implemented Dart Classes - -| Class | File | Description | -|-------|------|-------------| -| `WebPlatformInAppWebViewPlatform` | `inappwebview_platform.dart` | Platform factory - registers Web implementations | -| `WebPlatformInAppWebView` | `in_app_webview/in_app_webview.dart` | WebView widget using iframe | -| `WebPlatformInAppWebViewController` | `in_app_webview/in_app_webview_controller.dart` | WebView controller | -| `WebPlatformHeadlessInAppWebView` | `in_app_webview/headless_in_app_webview.dart` | Offscreen iframe | -| `WebPlatformCookieManager` | `cookie_manager.dart` | document.cookie wrapper | -| `WebPlatformWebStorage` | `web_storage/` | localStorage/sessionStorage | - ---- - -## Source Code Structure - -### Dart Side (`flutter_inappwebview_web/lib/src/`) - -``` -lib/src/ -├── inappwebview_platform.dart # Platform factory/registration -├── main.dart # Package entry point -├── platform_util.dart # Platform utilities -├── cookie_manager.dart # Document.cookie wrapper -│ -├── in_app_webview/ # Core iframe-based WebView -│ ├── _static_channel.dart # Static method channel -│ ├── in_app_webview.dart # Widget (HtmlElementView with iframe) -│ ├── in_app_webview_controller.dart # Controller implementation -│ ├── headless_in_app_webview.dart # Offscreen iframe -│ └── main.dart # Barrel file -│ -└── web_storage/ # localStorage/sessionStorage - ├── main.dart # Barrel file - └── web_storage.dart # Storage implementation -``` - -### TypeScript Side (`web_support/src/`) - -``` -web_support/src/ -├── index.ts # Main JavaScript bridge (flutter_inappwebview_plugin) -└── types.ts # TypeScript type definitions -``` - ---- - -## Platform Limitations - -The Web platform has significant limitations compared to native platforms: - -| Feature | Status | Notes | -|---------|--------|-------| -| InAppWebView | ✅ | iframe-based, same-origin restrictions | -| HeadlessInAppWebView | ✅ | Hidden iframe | -| InAppBrowser | ❌ | Not implemented | -| ChromeSafariBrowser | ❌ | Not applicable | -| CookieManager | ✅ | Same-origin only | -| WebStorage | ✅ | localStorage/sessionStorage | -| WebMessageChannel/Port | ❌ | Not implemented | -| FindInteractionController | ❌ | Not implemented | -| PrintJobController | ❌ | Not implemented | -| PullToRefreshController | ❌ | Not implemented | - -### Same-Origin Restrictions - -Due to browser security (CORS), the Web platform cannot: -- Access iframe content from different origins -- Inject JavaScript into cross-origin iframes -- Read/modify cookies for other domains -- Access cross-origin document properties - ---- - -## JavaScript Bridge Architecture - -### `web_support/src/index.ts` - -The TypeScript module provides the `flutter_inappwebview_plugin` global object: - -```typescript -window.flutter_inappwebview_plugin = { - createFlutterInAppWebView(viewId, iframe, iframeContainer, bridgeSecret), - getCookieExpirationDate(timestamp), - nativeAsyncCommunication(method, viewId, args), - nativeSyncCommunication(method, viewId, args), - nativeCommunication(method, viewId, args), -}; -``` - -### InAppWebView Methods (iframe wrapper) - -| Method | Description | -|--------|-------------| -| `prepare(settings)` | Initialize iframe with settings and event listeners | -| `setSettings(newSettings)` | Update iframe settings dynamically | -| `reload()` | Reload iframe content | -| `goBack()` | Navigate back in iframe history | -| `goForward()` | Navigate forward in iframe history | -| `goBackOrForward(steps)` | Navigate by number of steps | -| `evaluateJavascript(source)` | Execute JS in iframe (same-origin only) | -| `stopLoading()` | Stop iframe loading | -| `getUrl()` | Get current iframe URL | -| `getTitle()` | Get iframe document title | -| `injectJavascriptFileFromUrl(url, attrs)` | Inject script tag | -| `injectCSSCode(source)` | Inject style element | -| `injectCSSFileFromUrl(url, attrs)` | Inject link element | -| `scrollTo(x, y, animated)` | Scroll to position | -| `scrollBy(x, y, animated)` | Scroll by offset | -| `printCurrentPage()` | Trigger print dialog | -| `getContentHeight()` | Get document scroll height | -| `getContentWidth()` | Get document scroll width | -| `getSelectedText()` | Get selected text | -| `getScrollX()` / `getScrollY()` | Get scroll position | -| `isSecureContext()` | Check if HTTPS context | -| `canScrollVertically()` / `canScrollHorizontally()` | Check scrollability | -| `getSize()` | Get iframe container size | - -### Events Forwarded to Dart - -| Event | Trigger | -|-------|---------| -| `onLoadStart` | iframe load event start | -| `onLoadStop` | iframe load event complete | -| `onTitleChanged` | Document title mutation | -| `onConsoleMessage` | Console method intercept | -| `onUpdateVisitedHistory` | pushState/replaceState/popstate | -| `onScrollChanged` | scroll event | -| `onZoomScaleChanged` | devicePixelRatio change | -| `onEnterFullscreen` / `onExitFullscreen` | Fullscreen API | -| `onCreateWindow` | window.open() intercept | -| `onCloseWindow` | window.close() intercept | -| `onPrintRequest` | window.print() intercept | -| `onCallJsHandler` | JavaScript bridge handler call | -| `onWindowFocus` / `onWindowBlur` | Focus events | - ---- - -## Dart Utilities Reference - -### `platform_util.dart` - Platform Utilities - -| Method | Description | -|--------|-------------| -| `PlatformUtil.instance()` | Get singleton instance | -| `getSystemVersion()` | Get browser/platform version | -| `getWebCookieExpirationDate(date)` | Format date for cookie expiration | - -**Usage:** -```dart -final util = PlatformUtil.instance(); -final version = await util.getSystemVersion(); -final expiry = await util.getWebCookieExpirationDate(date: expiryDate); -``` - ---- - -## Development Workflow - -### Building TypeScript - -The `web_support/` folder contains TypeScript that compiles to JavaScript: - -```bash -cd web_support -npm install -npm run build # Compiles TypeScript to JavaScript -``` - -The compiled output is used by the Dart web plugin. - -### Dart-Side Development - -For Dart-only changes: -1. Implement platform interface from `flutter_inappwebview_platform_interface` -2. Register in `WebPlatformInAppWebViewPlatform.registerWith()` -3. Use `dart:js_interop` for JavaScript interop -4. Use `dart:html` for DOM manipulation - -### Adding New Features - -1. Update TypeScript in `web_support/src/` if JS bridge changes needed -2. Run `npm run build` in `web_support/` -3. Update Dart wrappers in `flutter_inappwebview_web/lib/src/` -4. Implement platform interface methods - ---- - -## Common Web Patterns - -### Calling Native (Dart) from JavaScript - -```typescript -// In TypeScript -_nativeCommunication('methodName', viewId, [arg1, arg2]); -``` - -### Calling JavaScript from Dart - -```dart -// Using js_interop -@JS('flutter_inappwebview_plugin') -external FlutterInAppWebViewPlugin get flutterInAppWebViewPlugin; -``` - -### Handling Same-Origin Restrictions - -```typescript -try { - // Attempt cross-origin access - const title = iframe.contentDocument?.title; -} catch (e) { - // SecurityError: blocked by same-origin policy - console.log(e); -} -``` - ---- - -## Build Commands - -```bash -# Dart package -cd flutter_inappwebview_web && flutter pub get - -# TypeScript (if modified) -cd web_support && npm install && npm run build - -# Example app -cd flutter_inappwebview_web/example && flutter run -d chrome -``` - -## Testing Considerations - -- Test with same-origin iframes for full functionality -- Cross-origin iframes will have limited capabilities -- Use `--disable-web-security` Chrome flag for development testing (not production) -- Browser console shows CORS errors for blocked operations - -## Debugging & Inspection - -- **Browser DevTools**: - - Right-click > Inspect. - - Console tab for logs and errors. - - Network tab for request inspection. - - Elements tab to inspect the iframe structure. -- **Logs**: Use `console.log()` in TypeScript/JavaScript or `print()` in Dart. -- **Source Maps**: `npm run build` generates source maps for debugging TypeScript in the browser. diff --git a/.github/instructions/windows.instructions.md b/.github/instructions/windows.instructions.md deleted file mode 100644 index 3c8e09ee02..0000000000 --- a/.github/instructions/windows.instructions.md +++ /dev/null @@ -1,380 +0,0 @@ ---- -applyTo: "flutter_inappwebview_windows/**" ---- - -# Windows Platform Implementation Instructions - -## Implemented Dart Classes - -| Class | File | Description | -|-------|------|-------------| -| `WindowsInAppWebViewPlatform` | `inappwebview_platform.dart` | Platform factory - registers all Windows implementations | -| `WindowsInAppWebView` | `in_app_webview/in_app_webview.dart` | WebView widget using texture | -| `WindowsInAppWebViewController` | `in_app_webview/in_app_webview_controller.dart` | WebView2 controller | -| `WindowsHeadlessInAppWebView` | `in_app_webview/headless_in_app_webview.dart` | Offscreen WebView2 | -| `WindowsInAppBrowser` | `in_app_browser/` | Browser window | -| `WindowsCookieManager` | `cookie_manager.dart` | ICoreWebView2CookieManager | -| `WindowsWebStorage` | `web_storage/` | WebView2 storage APIs | -| `WindowsFindInteractionController` | `find_interaction/` | ICoreWebView2Find | -| `WindowsPrintJobController` | `print_job/` | ICoreWebView2PrintSettings | -| `WindowsHttpAuthCredentialDatabase` | `http_auth_credentials_database.dart` | Credential storage | -| `WindowsWebViewEnvironment` | `webview_environment/` | ICoreWebView2Environment (session isolation) | - ---- - -## Native Code Structure - -``` -windows/ -├── CMakeLists.txt # CMake build config (fetches WebView2 NuGet) -├── flutter_inappwebview_windows_plugin.cpp # Plugin entry point -├── flutter_inappwebview_windows_plugin.h -├── flutter_inappwebview_windows_plugin_c_api.cpp # C API wrapper -│ -├── cookie_manager.cpp/h # ICoreWebView2CookieManager wrapper -├── platform_util.cpp/h # Platform utilities -│ -├── in_app_webview/ # Core WebView2 implementation -│ ├── in_app_webview.cpp/h # Main WebView2 wrapper class -│ ├── in_app_webview_manager.cpp/h # WebView instance management -│ ├── in_app_webview_settings.cpp/h # Settings mapping to WebView2 -│ ├── webview_channel_delegate.cpp/h # Dart-native bridge (MethodChannel) -│ └── user_content_controller.cpp/h # Script injection -│ -├── headless_in_app_webview/ # Offscreen WebView2 -│ ├── headless_in_app_webview.cpp/h # Headless implementation -│ ├── headless_in_app_webview_manager.cpp/h # Instance management -│ ├── headless_webview_channel_delegate.cpp/h # Channel delegate for headless -│ -├── in_app_browser/ # Browser window (HWND-based) -│ ├── in_app_browser.cpp/h # Browser window class -│ ├── in_app_browser_channel_delegate.cpp/h # Channel communication -│ ├── in_app_browser_manager.cpp/h # Instance management -│ └── in_app_browser_settings.cpp/h # Browser settings -│ -├── webview_environment/ # ICoreWebView2Environment -│ ├── webview_environment.cpp/h # Environment management -│ ├── webview_environment_channel_delegate.cpp/h # Channel communication -│ ├── webview_environment_manager.cpp/h # Instance management -│ └── webview_environment_settings.cpp/h # Environment settings -│ -├── custom_platform_view/ # Texture-based rendering -│ ├── custom_platform_view.cc/h # Platform view implementation -│ ├── graphics_context.cc/h # Graphics context management -│ ├── texture_bridge.cc/h # Base texture bridge -│ ├── texture_bridge_fallback.cc/h # CPU fallback renderer -│ ├── texture_bridge_gpu.cc/h # GPU-accelerated renderer -│ │ -│ └── util/ # Platform view utilities -│ ├── composition.desktop.interop.h # Desktop composition interop -│ ├── d3dutil.h # Direct3D utilities -│ ├── direct3d11.interop.cc/h # D3D11 interop -│ ├── rohelper.cc/h # WinRT helper -│ ├── string_converter.cc/h # String conversion -│ ├── swizzle.h # Texture swizzle operations -│ └── cpuid/ # CPU identification -│ -├── plugin_scripts_js/ # Injected JavaScript -│ ├── javascript_bridge_js.h # Core JS bridge -│ └── plugin_scripts_util.h # Script utilities -│ -└── utils/ # Utility functions - ├── base64.cpp/h # Base64 encoding/decoding - ├── defer.h # RAII cleanup utilities - ├── flutter.h # EncodableValue utilities - ├── log.h # Logging and HRESULT handling - ├── map.h # Map utilities - ├── strconv.h # String encoding conversion - ├── string.h # String utilities - ├── timer.h # Timer utilities - ├── uri.h # URI utilities - ├── util.h # General utilities - ├── uuid.h # UUID generation - └── vector.h # Vector utilities -``` - ---- - -## Platform Requirements - -- Windows 10/11 -- [NuGet CLI](https://learn.microsoft.com/en-us/nuget/install-nuget-client-tools) on PATH -- WebView2 Runtime (auto-installed on modern Windows) - -## Native APIs Used - -- [WebView2](https://learn.microsoft.com/en-us/microsoft-edge/webview2/) -- Uses texture-based platform view rendering - ---- - -## C++ Utilities Reference - -### `utils/flutter.h` - EncodableValue Serialization - -**ALWAYS use these utilities** when creating new C++ types or working with Flutter's EncodableValue. - -#### EncodableValue Building (`make_fl_value`) - -```cpp -#include "../utils/flutter.h" - -flutter::EncodableMap SomeType::toEncodableMap() const { - return flutter::EncodableMap{ - {"stringField", make_fl_value(someString)}, - {"intField", make_fl_value(someInt)}, - {"optionalField", make_fl_value(optionalValue)}, // auto handles std::optional - {"nullField", make_fl_value()}, // null value - }; -} -``` - -| `make_fl_value(T)` | Result | -|--------------------|--------| -| `(no args)` | `EncodableValue()` (null) | -| `T` (any basic type) | `EncodableValue(val)` | -| `T*` | null if nullptr, else `EncodableValue(*val)` | -| `std::vector` | `EncodableList` (recursive) | -| `std::map` | `EncodableMap` (recursive) | -| `std::optional` | Value or null | -| `std::optional>` | List or null | -| `std::optional>` | Map or null | - -#### EncodableValue Extraction (`get_fl_map_value`, `get_optional_fl_map_value`) - -```cpp -// Extract with type -std::string str = get_fl_map_value(map, "key"); -int64_t num = get_fl_map_value(map, "key"); // Use LongValue() internally - -// Extract with default -std::string str = get_fl_map_value(map, "key", "default"); -std::vector vec = get_fl_map_value(map, "key", std::vector{}); - -// Extract optional -auto opt_str = get_optional_fl_map_value(map, "key"); -auto opt_map = get_optional_fl_map_value>(map, "key"); -``` - -#### Map Checking - -```cpp -if (fl_map_contains(map, "key")) { ... } // Key exists (may be null) -if (fl_map_contains_not_null(map, "key")) { ... } // Key exists and not null -``` - ---- - -### `utils/strconv.h` - String Encoding Conversion (Windows-specific) - -Essential for Windows Unicode handling: - -| Function | Description | -|----------|-------------| -| `utf8_to_wide(s)` | Convert UTF-8 string to `std::wstring` | -| `wide_to_utf8(s)` | Convert `std::wstring` to UTF-8 | -| `ansi_to_wide(s)` | Convert ANSI to wide string | -| `wide_to_ansi(s)` | Convert wide to ANSI | -| `ansi_to_utf8(s)` | Convert ANSI to UTF-8 | -| `utf8_to_ansi(s)` | Convert UTF-8 to ANSI | -| `cp_to_wide(s, codepage)` | Convert any codepage to wide | -| `wide_to_cp(s, codepage)` | Convert wide to any codepage | -| `format(format, ...)` | Printf-style string formatting | -| `dbgmsg(title, format, ...)` | Show MessageBox with formatted text | -| `dbgout(ostrm, format, ...)` | Debug output to stream | - -**Usage:** -```cpp -#include "../utils/strconv.h" - -// WebView2 requires wide strings -std::wstring wideUrl = utf8_to_wide(url); -webview->Navigate(wideUrl.c_str()); - -// Convert back from WebView2 -std::string utf8Title = wide_to_utf8(title); -``` - ---- - -### `utils/log.h` - Logging and HRESULT Handling - -| Function | Description | -|----------|-------------| -| `debugLog(msg)` | Log debug message (only in debug builds) | -| `debugLog(hr)` | Log HRESULT with error message | -| `getHRMessage(hr)` | Get human-readable HRESULT message | -| `succeededOrLog(hr)` | Return true if SUCCEEDED, log if failed | -| `failedAndLog(hr)` | Return true if FAILED, log it | -| `failedLog(hr)` | Log HRESULT if failed | - -**Usage with macros** (auto-includes file/line): -```cpp -debugLog("Message"); // Logs with file:line prefix -if (succeededOrLog(hr)) { ... } // Check and log HRESULT -if (failedAndLog(hr)) { return; } // Early return on failure -``` - ---- - -### `utils/timer.h` - Timer Utilities (Windows SetTimer wrapper) - -| Function | Description | -|----------|-------------| -| `Timer::setTimeout(callback, delay)` | One-shot timer, returns timer ID | -| `Timer::setInterval(callback, delay)` | Repeating timer, returns timer ID | -| `Timer::clearTimeout(timerId)` | Cancel one-shot timer | -| `Timer::clearInterval(timerId)` | Cancel repeating timer | - -```cpp -auto timerId = Timer::setTimeout([&]() { - // Called once after delay -}, 1000); // 1 second - -Timer::clearTimeout(timerId); // Cancel if needed -``` - ---- - -### `utils/base64.h` - Base64 Encoding/Decoding - -| Function | Description | -|----------|-------------| -| `base64_encode(s)` | Encode string to base64 | -| `base64_encode(data, len)` | Encode bytes to base64 | -| `base64_encode_pem(s)` | Encode with PEM line breaks | -| `base64_encode_mime(s)` | Encode with MIME line breaks | -| `base64_decode(s)` | Decode base64 string | - ---- - -### `utils/string.h` - String Utilities - -| Function | Description | -|----------|-------------| -| `string_equals(s1, s2)` | Compare strings (supports optional) | -| `replace_all(source, from, to)` | Replace all occurrences in-place | -| `replace_all_copy(source, from, to)` | Replace all, return copy | -| `join(vec, delim)` | Join vector with delimiter | -| `split(s, delimiter)` | Split string into vector | -| `to_lowercase(s)` / `to_lowercase_copy(s)` | Convert to lowercase | -| `to_uppercase(s)` / `to_uppercase_copy(s)` | Convert to uppercase | -| `starts_with(str, prefix)` | Check prefix | -| `ends_with(str, suffix)` | Check suffix | -| `string_hash(data)` | Compile-time hash (constexpr) | -| `trim(str)` | Trim whitespace | - ---- - -### `utils/map.h` - Map Utilities - -| Function | Description | -|----------|-------------| -| `map_contains(map, key)` | Check if key exists | -| `map_at_or_null(map, key)` | Get value or nullptr | -| `map_at_optional(map, key)` | Get as `std::optional` | - ---- - -### `utils/vector.h` - Vector Utilities - -| Function | Description | -|----------|-------------| -| `vector_remove(vec, el)` | Remove element | -| `vector_remove_if(vec, pre# `utils/uri.h` - URI Utilities - -| Function | Description | -|----------|-------------| -| `get_origin_from_url(url)` | Extract origin | -| `is_valid_url(url)` | Validate URL | -| `get_scheme_from_url(url)` | Extract scheme | -| `get_host_from_url(url)` | Extract host | -| `url_encode(value)` | URL-encode string | - ---- - -### `utils/defer.h` - RAII Cleanup - -| Function | Description | -|----------|-------------| -| `defer(handle, callback)` | shared_ptr with custom deleter | -| `make_scope_guard(func)` | RAII guard | - ---- - -### `utils/uuid.h` - UUID Generation - -| Function | Description | -|----------|-------------| -| `get_uuid()` | Generate UUID v4 string | - ---- - -### `utils/util.h` - General Utilities - -| Function | Description | -|----------|-------------| -| `make_pointer_optional(ptr)` | Pointer to optional | -| `variant_to_string(var)` | Variant to string | - ---- - -## Plugin Scripts JS Reference - -JavaScript files injected into WebViews for native-web communication: - -| Script | File | Description | -|--------|------|-------------| -| **JavaScriptBridgeJS** | `javascript_bridge_js.h` | Core bridge enabling `window.flutter_inappwebview.callHandler()` for Dart-JS communication. Uses `chrome.webview.postMessage` for WebView2 communication. | - -**Helper class:** `plugin_scripts_util.h` contains utility functions for script management. - -**Note:** Windows implementation currently has fewer plugin scripts than iOS/macOS. Most functionality is handled natively through WebView2 APIs: -- Console messages: `ICoreWebView2.add_ConsoleMessage` -- Resource loading: `ICoreWebView2.add_WebResourceRequested` -- Navigation: `ICoreWebView2.add_NavigationStarting`, `add_NavigationCompleted` -- Print: `ICoreWebView2PrintSettings` - -Additional scripts may be needed for features not natively supported by WebView2 (e.g., AJAX/Fetch interception). - ---- - -## Dart-Side Development - -For Dart-only changes: -1. Implement platform interface from `flutter_inappwebview_platform_interface` -2. Windows-specific features: `WebViewEnvironment` for session isolation -3. `WebViewInterface` enum maps to ICoreWebView2 interface versions - -## Native Code Development - -When modifying C++ code: -- Located in `windows/` -- **Prefer standard C++17** over Windows-specific APIs for maintainability -- Plugin class: `FlutterInappwebviewWindowsPluginCApi` -- Uses Flutter texture for rendering WebView2 content - -## Build Commands - -```bash -cd flutter_inappwebview_windows && flutter pub get -cd example && flutter build windows --debug -``` - -## Key C++ Files - -- `flutter_inappwebview_windows_plugin.cpp` - Plugin entry point -- `in_app_webview/in_app_webview.cpp` - WebView2 wrapper -- `webview_environment/webview_environment.cpp` - Environment management - -## Debugging & Inspection - -- **Edge DevTools**: - - Enable debugging in your app: - ```dart - InAppWebViewSettings(isInspectable: true) // or areDevToolsEnabled: true - ``` - - Right-click in the WebView and select "Inspect". - - Or open `edge://inspect` in Edge browser. -- **Logs**: Use `debugLog()` in C++ which prints to the Output window in Visual Studio. -- **Visual Studio**: Attach debugger to the running process for C++ debugging. diff --git a/.github/workflows/lock.yaml b/.github/workflows/lock.yaml deleted file mode 100644 index e4f6f41265..0000000000 --- a/.github/workflows/lock.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# Configuration for Lock Threads - https://github.com/dessant/lock-threads - -name: 'Lock Threads' - -# By specifying the access of one of the scopes, all of those that are not -# specified are set to 'none'. -permissions: - issues: write - -on: - schedule: - - cron: '0 0 * * *' # Run every day at midnight - -jobs: - lock: - permissions: - issues: write - runs-on: ubuntu-latest - steps: - - uses: dessant/lock-threads@v5.0.1 - with: - process-only: 'issues' - github-token: ${{ github.token }} - # Number of days of inactivity before a closed issue is locked. - issue-inactive-days: 14 - issue-comment: > - This thread has been automatically locked since there has not been - any recent activity after it was closed. If you are still experiencing a - similar issue, please open a new bug and a minimal reproduction of the issue. \ No newline at end of file diff --git a/.github/workflows/no-response.yaml b/.github/workflows/no-response.yaml deleted file mode 100644 index b353a97287..0000000000 --- a/.github/workflows/no-response.yaml +++ /dev/null @@ -1,38 +0,0 @@ - -name: No Response - -# Both `issue_comment` and `scheduled` event types are required for this Action -# to work properly. -on: - issue_comment: - types: [created] - schedule: - - cron: '0 0 * * *' # Run every day at midnight - -# By specifying the access of one of the scopes, all of those that are not -# specified are set to 'none'. -permissions: - issues: write - -jobs: - noResponse: - runs-on: ubuntu-latest - steps: - - uses: godofredoc/no-response@0ce2dc0e63e1c7d2b87752ceed091f6d32c9df09 - with: - token: ${{ github.token }} - # Comment to post when closing an Issue for lack of response. Set to `false` to disable - closeComment: > - Without additional information, we are unfortunately not sure how to - resolve this issue. We are therefore reluctantly going to close this - bug for now. - - If you find this problem please file a new issue with the same description, - what happens and logs. It's always better to open new issues and reference - the related ones. - - Thanks for your contribution. - # Number of days of inactivity before an issue is closed for lack of response. - daysUntilClose: 21 - # Label requiring a response. - responseRequiredLabel: "waiting for customer response" diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml deleted file mode 100644 index 13ffa0832d..0000000000 --- a/.github/workflows/stale.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: Close Stale Issues - -on: - schedule: - - cron: '0 0 * * *' # Run every day at midnight - -jobs: - close-issues: - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - name: Close stale issues - uses: actions/stale@v9.0.0 - with: - days-before-issue-stale: 365 - days-before-issue-close: 0 - stale-issue-label: "stale" - stale-issue-message: "This issue is stale and has been automatically closed because it has been open for more than 365 days with no activity. Please reopen a new issue if you still have it." - days-before-pr-stale: -1 - days-before-pr-close: -1 - repo-token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore deleted file mode 100755 index 5fab91a7bc..0000000000 --- a/.gitignore +++ /dev/null @@ -1,36 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock -doc/api/ -.dart_tool/ -.packages -build/ -.fvm/ - -flutter_driver_tests.log -tool/chromedriver -tool/chromedriver.* - -plans/ \ No newline at end of file diff --git a/.metadata b/.metadata deleted file mode 100644 index b0199f3a28..0000000000 --- a/.metadata +++ /dev/null @@ -1,39 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled. - -version: - revision: 18a827f3933c19f51862dde3fa472197683249d6 - channel: stable - -project_type: plugin - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: 18a827f3933c19f51862dde3fa472197683249d6 - base_revision: 18a827f3933c19f51862dde3fa472197683249d6 - - platform: android - create_revision: 18a827f3933c19f51862dde3fa472197683249d6 - base_revision: 18a827f3933c19f51862dde3fa472197683249d6 - - platform: ios - create_revision: 18a827f3933c19f51862dde3fa472197683249d6 - base_revision: 18a827f3933c19f51862dde3fa472197683249d6 - - platform: macos - create_revision: 18a827f3933c19f51862dde3fa472197683249d6 - base_revision: 18a827f3933c19f51862dde3fa472197683249d6 - - platform: web - create_revision: 18a827f3933c19f51862dde3fa472197683249d6 - base_revision: 18a827f3933c19f51862dde3fa472197683249d6 - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 229674fe59..0000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,334 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "flutter_inappwebview", - "cwd": "flutter_inappwebview", - "request": "launch", - "type": "dart" - }, - { - "name": "flutter_inappwebview (profile mode)", - "cwd": "flutter_inappwebview", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "flutter_inappwebview (release mode)", - "cwd": "flutter_inappwebview", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "flutter_inappwebview_android", - "cwd": "flutter_inappwebview_android", - "request": "launch", - "type": "dart" - }, - { - "name": "flutter_inappwebview_android (profile mode)", - "cwd": "flutter_inappwebview_android", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "flutter_inappwebview_android (release mode)", - "cwd": "flutter_inappwebview_android", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "flutter_inappwebview_ios", - "cwd": "flutter_inappwebview_ios", - "request": "launch", - "type": "dart" - }, - { - "name": "flutter_inappwebview_ios (profile mode)", - "cwd": "flutter_inappwebview_ios", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "flutter_inappwebview_ios (release mode)", - "cwd": "flutter_inappwebview_ios", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "flutter_inappwebview_linux", - "cwd": "flutter_inappwebview_linux", - "request": "launch", - "type": "dart" - }, - { - "name": "flutter_inappwebview_linux (profile mode)", - "cwd": "flutter_inappwebview_linux", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "flutter_inappwebview_linux (release mode)", - "cwd": "flutter_inappwebview_linux", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "flutter_inappwebview_macos", - "cwd": "flutter_inappwebview_macos", - "request": "launch", - "type": "dart" - }, - { - "name": "flutter_inappwebview_macos (profile mode)", - "cwd": "flutter_inappwebview_macos", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "flutter_inappwebview_macos (release mode)", - "cwd": "flutter_inappwebview_macos", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "flutter_inappwebview_platform_interface", - "cwd": "flutter_inappwebview_platform_interface", - "request": "launch", - "type": "dart" - }, - { - "name": "flutter_inappwebview_platform_interface (profile mode)", - "cwd": "flutter_inappwebview_platform_interface", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "flutter_inappwebview_platform_interface (release mode)", - "cwd": "flutter_inappwebview_platform_interface", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "flutter_inappwebview_web", - "cwd": "flutter_inappwebview_web", - "request": "launch", - "type": "dart" - }, - { - "name": "flutter_inappwebview_web (profile mode)", - "cwd": "flutter_inappwebview_web", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "flutter_inappwebview_web (release mode)", - "cwd": "flutter_inappwebview_web", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "flutter_inappwebview_windows", - "cwd": "flutter_inappwebview_windows", - "request": "launch", - "type": "dart" - }, - { - "name": "flutter_inappwebview_windows (profile mode)", - "cwd": "flutter_inappwebview_windows", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "flutter_inappwebview_windows (release mode)", - "cwd": "flutter_inappwebview_windows", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "flutter_inappwebview_internal_annotations", - "cwd": "dev_packages/flutter_inappwebview_internal_annotations", - "request": "launch", - "type": "dart" - }, - { - "name": "generators", - "cwd": "dev_packages/generators", - "request": "launch", - "type": "dart" - }, - { - "name": "generators (profile mode)", - "cwd": "dev_packages/generators", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "generators (release mode)", - "cwd": "dev_packages/generators", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "example", - "cwd": "flutter_inappwebview/example", - "request": "launch", - "type": "dart" - }, - { - "name": "example (profile mode)", - "cwd": "flutter_inappwebview/example", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "example (release mode)", - "cwd": "flutter_inappwebview/example", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "android example", - "cwd": "flutter_inappwebview_android/example", - "request": "launch", - "type": "dart" - }, - { - "name": "android example (profile mode)", - "cwd": "flutter_inappwebview_android/example", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "android example (release mode)", - "cwd": "flutter_inappwebview_android/example", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "ios example", - "cwd": "flutter_inappwebview_ios/example", - "request": "launch", - "type": "dart" - }, - { - "name": "ios example (profile mode)", - "cwd": "flutter_inappwebview_ios/example", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "ios example (release mode)", - "cwd": "flutter_inappwebview_ios/example", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "linux example", - "cwd": "flutter_inappwebview_linux/example", - "request": "launch", - "type": "dart" - }, - { - "name": "linux example (profile mode)", - "cwd": "flutter_inappwebview_linux/example", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "linux example (release mode)", - "cwd": "flutter_inappwebview_linux/example", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "macos example", - "cwd": "flutter_inappwebview_macos/example", - "request": "launch", - "type": "dart" - }, - { - "name": "macos example (profile mode)", - "cwd": "flutter_inappwebview_macos/example", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "macos example (release mode)", - "cwd": "flutter_inappwebview_macos/example", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "web example", - "cwd": "flutter_inappwebview_web/example", - "request": "launch", - "type": "dart" - }, - { - "name": "web example (profile mode)", - "cwd": "flutter_inappwebview_web/example", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "web example (release mode)", - "cwd": "flutter_inappwebview_web/example", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "windows example", - "cwd": "flutter_inappwebview_windows/example", - "request": "launch", - "type": "dart" - }, - { - "name": "windows example (profile mode)", - "cwd": "flutter_inappwebview_windows/example", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "windows example (release mode)", - "cwd": "flutter_inappwebview_windows/example", - "request": "launch", - "type": "dart", - "flutterMode": "release" - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index f08edc2aaf..0000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "cmake.configureOnOpen": false, - "files.associations": { - "algorithm": "cpp", - "any": "cpp", - "array": "cpp", - "atomic": "cpp", - "bit": "cpp", - "cctype": "cpp", - "charconv": "cpp", - "chrono": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "compare": "cpp", - "concepts": "cpp", - "coroutine": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "exception": "cpp", - "format": "cpp", - "forward_list": "cpp", - "functional": "cpp", - "initializer_list": "cpp", - "iomanip": "cpp", - "ios": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "iterator": "cpp", - "limits": "cpp", - "list": "cpp", - "locale": "cpp", - "map": "cpp", - "memory": "cpp", - "new": "cpp", - "optional": "cpp", - "ostream": "cpp", - "ratio": "cpp", - "set": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "stop_token": "cpp", - "streambuf": "cpp", - "string": "cpp", - "system_error": "cpp", - "thread": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "typeinfo": "cpp", - "unordered_map": "cpp", - "utility": "cpp", - "variant": "cpp", - "vector": "cpp", - "xfacet": "cpp", - "xhash": "cpp", - "xiosbase": "cpp", - "xlocale": "cpp", - "xlocbuf": "cpp", - "xlocinfo": "cpp", - "xlocmes": "cpp", - "xlocmon": "cpp", - "xlocnum": "cpp", - "xloctime": "cpp", - "xmemory": "cpp", - "xstring": "cpp", - "xtr1common": "cpp", - "xtree": "cpp", - "xutility": "cpp" - }, - "dart.flutterSdkPath": ".fvm/flutter_sdk/bin" -} \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100755 index 6ccd8da42c..0000000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2023 Lorenzo Pichilli - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/README.md b/README.md deleted file mode 100755 index f6cafe5f44..0000000000 --- a/README.md +++ /dev/null @@ -1,226 +0,0 @@ -
- -# Flutter InAppWebView Plugin [![Share on Twitter](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Flutter%20InAppBrowser%20plugin!&url=https://github.com/pichillilorenzo/flutter_inappwebview&hashtags=flutter,flutterio,dart,dartlang,webview) [![Share on Facebook](https://img.shields.io/badge/share-facebook-blue.svg?longCache=true&style=flat&colorB=%234267b2)](https://www.facebook.com/sharer/sharer.php?u=https%3A//github.com/pichillilorenzo/flutter_inappwebview) - -![InAppWebView-logo](https://user-images.githubusercontent.com/5956938/195422744-bdcfed16-73f0-4bc9-94ab-ecf10771a1c4.png) - - -[![All Contributors](https://img.shields.io/badge/all_contributors-100-orange.svg?style=flat-square)](#contributors-) - - -[![flutter_inappwebview version](https://img.shields.io/pub/v/flutter_inappwebview?include_prereleases)](https://pub.dartlang.org/packages/flutter_inappwebview) -[![Pub Points](https://img.shields.io/pub/points/flutter_inappwebview)](https://pub.dev/packages/flutter_inappwebview/score) -[![Pub Popularity](https://img.shields.io/pub/popularity/flutter_inappwebview)](https://pub.dev/packages/flutter_inappwebview/score) -[![Pub Likes](https://img.shields.io/pub/likes/flutter_inappwebview)](https://pub.dev/packages/flutter_inappwebview/score) -[![Awesome Flutter](https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square)](https://stackoverflow.com/questions/tagged/flutter-inappwebview) -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](/LICENSE) - -[![Donate to this project](https://img.shields.io/badge/support-donate-yellow.svg)](https://inappwebview.dev/donate/) -[![GitHub forks](https://img.shields.io/github/forks/pichillilorenzo/flutter_inappwebview?style=social)](https://github.com/pichillilorenzo/flutter_inappwebview) -[![GitHub stars](https://img.shields.io/github/stars/pichillilorenzo/flutter_inappwebview?style=social)](https://github.com/pichillilorenzo/flutter_inappwebview) - -###### Supported Platforms - -[![flutter_inappwebview_platform_interface version](https://img.shields.io/pub/v/flutter_inappwebview_platform_interface?include_prereleases&label=Platform%20Interface)](https://pub.dartlang.org/packages/flutter_inappwebview_platform_interface) -[![flutter_inappwebview_android version](https://img.shields.io/pub/v/flutter_inappwebview_android?include_prereleases&label=Android)](https://pub.dartlang.org/packages/flutter_inappwebview_android) -[![flutter_inappwebview_ios version](https://img.shields.io/pub/v/flutter_inappwebview_ios?include_prereleases&label=iOS)](https://pub.dartlang.org/packages/flutter_inappwebview_ios) -[![flutter_inappwebview_macos version](https://img.shields.io/pub/v/flutter_inappwebview_macos?include_prereleases&label=macOS)](https://pub.dartlang.org/packages/flutter_inappwebview_macos) -[![flutter_inappwebview_windows version](https://img.shields.io/pub/v/flutter_inappwebview_windows?include_prereleases&label=Windows)](https://pub.dartlang.org/packages/flutter_inappwebview_windows) -[![flutter_inappwebview_linux version](https://img.shields.io/pub/v/flutter_inappwebview_linux?include_prereleases&label=linux)](https://pub.dartlang.org/packages/flutter_inappwebview_linux) -[![flutter_inappwebview_web version](https://img.shields.io/pub/v/flutter_inappwebview_web?include_prereleases&label=Web)](https://pub.dartlang.org/packages/flutter_inappwebview_web) - -A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window. - -
- -## Articles/Resources - -- [Official documentation: inappwebview.dev/docs](https://inappwebview.dev/docs/intro) -- Read the online [API Reference](https://pub.dartlang.org/documentation/flutter_inappwebview/latest/) to get the **full API documentation**. -- [Official blog: inappwebview.dev/blog](https://inappwebview.dev/blog/) -- Find open source projects on the [Official Showcase page: inappwebview.dev/showcase](https://inappwebview.dev/showcase/) -- Check the [flutter_inappwebview_examples](https://github.com/pichillilorenzo/flutter_inappwebview_examples) repository for project examples -- Check the [flutter_inappwebview/example/integration_test/webview_flutter_test.dart](https://github.com/pichillilorenzo/flutter_inappwebview/blob/master/flutter_inappwebview/example/integration_test/webview_flutter_test.dart) file for other code examples -- [Flutter Browser App](https://github.com/pichillilorenzo/flutter_browser_app): A Full-Featured Mobile Browser App (such as the Google Chrome mobile browser) created using Flutter and the features offered by the flutter_inappwebview plugin - -## Showcase - Who use it - -Check the [Showcase](https://inappwebview.dev/showcase/) page to see an open list of Apps built with **Flutter** and **Flutter InAppWebView**. - -#### Are you using the **Flutter InAppWebView** plugin and would you like to add your App there? - -Send a submission request to the [Submit App](https://inappwebview.dev/submit-app/) page! - -## Requirements - -- Dart sdk: "^3.8.0" -- Flutter: ">=3.32.0" -- Android: `minSdkVersion >= 19`, [AGP](https://developer.android.com/build/releases/gradle-plugin) version `>= 7.3.0` (use [Android Studio - Android Gradle plugin Upgrade Assistant](https://developer.android.com/build/agp-upgrade-assistant) for help) -- iOS 12.0+, Xcode version `>= 15.0` -- MacOS 10.14+: Xcode version `>= 15.0` -- Windows: [NuGet CLI](https://learn.microsoft.com/en-us/nuget/install-nuget-client-tools?tabs=windows#nugetexe-cli) available on your PATH environment variable -- Linux: WPE 2.0 WebKit built - -## Installation - -Add `flutter_inappwebview` as a [dependency in your pubspec.yaml file](https://flutter.io/using-packages/). - -### Platform Installation Setup: -- [Android](https://inappwebview.dev/docs/intro/#setup-android) -- [iOS](https://inappwebview.dev/docs/intro/#setup-ios) -- [macOS](https://inappwebview.dev/docs/intro/#setup-macos) -- [Windows](https://inappwebview.dev/docs/intro/#setup-windows) -- [Web](https://inappwebview.dev/docs/intro/#setup-web) - -## Support - -Did you find this plugin useful? Please consider to [make a donation](https://inappwebview.dev/donate/) to help improve it! - -## Contributors ✨ - -Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Alex Li
Alex Li

💻
1/2
1/2

💻
Christofer Bodin
Christofer Bodin

💻
Matthew Lloyd
Matthew Lloyd

💻
C E
C E

💻
Robson Araujo
Robson Araujo

💻
Ryan
Ryan

💻
CodeEagle
CodeEagle

💻
Tanay Neotia
Tanay Neotia

💻
Jamie Joost
Jamie Joost

💻
Matias de Andrea
Matias de Andrea

💻
YouCii
YouCii

💻
Salnikov Sergey
Salnikov Sergey

💻
Po-Jui Chen
Po-Jui Chen

💻
Manuito
Manuito

💻
setcy
setcy

💻
EArminjon
EArminjon

💻
Ashank Bharati
Ashank Bharati

💻
Michael Chow
Michael Chow

💻
Osvaldo Saez
Osvaldo Saez

💻
rsydor
rsydor

💻
Le Minh Hoang
Le Minh Hoang

💻
Michael Kao
Michael Kao

💻
cloudygeek
cloudygeek

💻
Christoph Eck
Christoph Eck

💻
Ser1ous
Ser1ous

💻
Caleb Jones
Caleb Jones

💻
Saverio Murgia
Saverio Murgia

💻
Trần Đức Tâm
Trần Đức Tâm

💻
Joker
Joker

💻
Yash Chandra Verma
Yash Chandra Verma

💻
Arne Kepp
Arne Kepp

💻
Ömral Cörüt
Ömral Cörüt

💻
LrdHelmchen
LrdHelmchen

💻
Steven Gunanto
Steven Gunanto

💻
Michael Rittmeister
Michael Rittmeister

💻
Akira Aratani
Akira Aratani

💻
Doflatango
Doflatango

💻
Edmund Tay
Edmund Tay

💻
Andrei Diaconu
Andrei Diaconu

💻
Daniel Kao
Daniel Kao

💻
xuty
xuty

💻
Ben Bieker
Ben Bieker

💻
Phạm Như Vũ
Phạm Như Vũ

💻
SebastienBtr
SebastienBtr

💻
NeZha
NeZha

💻
Jan Klinge
Jan Klinge

💻
PauloDurrerMelo
PauloDurrerMelo

💻
benmeemo
benmeemo

💻
cinos
cinos

💻
Rex Raphael
Rex Raphael

💻
Jan Henrik Høiland
Jan Henrik Høiland

💻
Iguchi Tomokatsu
Iguchi Tomokatsu

💻
Jonas Uekötter
Jonas Uekötter

📖 💻
emakar
emakar

💻
liasica
liasica

💻
Eiichiro Adachi
Eiichiro Adachi

💻
Kamil Powałowski
Kamil Powałowski

💻
Akio Yamamoto
Akio Yamamoto

💻
mohenaxiba
mohenaxiba

💻
Ben Anderson
Ben Anderson

💻
Daan Poron
Daan Poron

🛡️
ふぁ
ふぁ

💻
perffecto
perffecto

💻
Chandra Abdul Fattah
Chandra Abdul Fattah

💻
Aleksandar Lugonja
Aleksandar Lugonja

💻
Alexandre Richonnier
Alexandre Richonnier

💻
Sunbreak
Sunbreak

💻
Eric Lee
Eric Lee

📖
KhatibFX
KhatibFX

💻
Guide.inc
Guide.inc

💻
Niraj Nandish
Niraj Nandish

💻
nesquikm
nesquikm

💻
Andreas Gangsø
Andreas Gangsø

💻
Alexandru Terente
Alexandru Terente

💻
Dango Mango
Dango Mango

💻
Max Zimmermann
Max Zimmermann

💻
Alexandru Dochioiu
Alexandru Dochioiu

💻
YumengNevix
YumengNevix

💻
lrorpilla
lrorpilla

💻
Michal Šrůtek
Michal Šrůtek

💻
daisukeueta
daisukeueta

💻
Gray Mackall
Gray Mackall

💻
Pavel Mazhnik
Pavel Mazhnik

💻
nlog (solrin)
nlog (solrin)

💻
Murmurl912
Murmurl912

💻
Benjamin Schulz
Benjamin Schulz

🤔
seal-app
seal-app

💻
Takuya Tominaga
Takuya Tominaga

💻
Sergey
Sergey

💻
yuanbo li
yuanbo li

💻
Ryan Feline
Ryan Feline

💻
Jeff Ward
Jeff Ward

⚠️
Yelzhan Yerkebulan
Yelzhan Yerkebulan

💻
GooRingX
GooRingX

💻
Robodoh
Robodoh

💻
imoyakin
imoyakin

💻
laishere
laishere

💻
Marco Muccinelli
Marco Muccinelli

💻
momadvisor
momadvisor

💻
- - - - - - -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! diff --git a/dev_packages/flutter_inappwebview_internal_annotations/.gitignore b/dev_packages/flutter_inappwebview_internal_annotations/.gitignore deleted file mode 100755 index cac255942f..0000000000 --- a/dev_packages/flutter_inappwebview_internal_annotations/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock -**/doc/api/ -.dart_tool/ -.packages -build/ -.fvm/ - -flutter_driver_tests.log -tool/chromedriver -tool/chromedriver.* \ No newline at end of file diff --git a/dev_packages/flutter_inappwebview_internal_annotations/CHANGELOG.md b/dev_packages/flutter_inappwebview_internal_annotations/CHANGELOG.md deleted file mode 100755 index dc2825f477..0000000000 --- a/dev_packages/flutter_inappwebview_internal_annotations/CHANGELOG.md +++ /dev/null @@ -1,19 +0,0 @@ -## 1.3.0 - -- Updated linux platform name - -## 1.2.0 - -- Updated `ExchangeableEnum` and `ExchangeableObjectProperty`. - -## 1.1.1 - -- Added `ExchangeableObject.fromMapForceAllInline`. - -## 1.1.0 - -- Added `ExchangeableObject.copyMethod`. - -## 1.0.0 - -Initial release. \ No newline at end of file diff --git a/dev_packages/flutter_inappwebview_internal_annotations/LICENSE b/dev_packages/flutter_inappwebview_internal_annotations/LICENSE deleted file mode 100755 index 6ccd8da42c..0000000000 --- a/dev_packages/flutter_inappwebview_internal_annotations/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2023 Lorenzo Pichilli - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/dev_packages/flutter_inappwebview_internal_annotations/README.md b/dev_packages/flutter_inappwebview_internal_annotations/README.md deleted file mode 100644 index 2576dc56c4..0000000000 --- a/dev_packages/flutter_inappwebview_internal_annotations/README.md +++ /dev/null @@ -1 +0,0 @@ -Internal annotations used by the generator of [flutter_inappwebview](https://github.com/pichillilorenzo/flutter_inappwebview) plugin. \ No newline at end of file diff --git a/dev_packages/flutter_inappwebview_internal_annotations/lib/flutter_inappwebview_internal_annotations.dart b/dev_packages/flutter_inappwebview_internal_annotations/lib/flutter_inappwebview_internal_annotations.dart deleted file mode 100644 index 1ff80f76ae..0000000000 --- a/dev_packages/flutter_inappwebview_internal_annotations/lib/flutter_inappwebview_internal_annotations.dart +++ /dev/null @@ -1,11 +0,0 @@ -library flutter_inappwebview_internal_annotations; - -export 'src/exchangeable_object.dart'; -export 'src/exchangeable_object_constructor.dart'; -export 'src/exchangeable_object_property.dart'; -export 'src/exchangeable_object_method.dart'; -export 'src/exchangeable_enum.dart'; -export 'src/exchangeable_enum_custom_value.dart'; -export 'src/supported_platforms.dart'; -export 'src/enum_supported_platforms.dart'; -export 'src/constants.dart'; \ No newline at end of file diff --git a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/constants.dart b/dev_packages/flutter_inappwebview_internal_annotations/lib/src/constants.dart deleted file mode 100644 index ee3ddc7eb1..0000000000 --- a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/constants.dart +++ /dev/null @@ -1,29 +0,0 @@ -const kPlatformNameAndroid = "Android WebView"; -const kPlatformNameIOS = "iOS WKWebView"; -const kPlatformNameMacOS = "macOS WKWebView"; -const kPlatformNameWindows = "Windows WebView2"; -const kPlatformNameLinux = "Linux WPE WebKit"; -const kPlatformNameWeb = "Web \\"; -const kPlatformNameValues = [ - kPlatformNameAndroid, - kPlatformNameIOS, - kPlatformNameMacOS, - kPlatformNameWindows, - kPlatformNameLinux, - kPlatformNameWeb, -]; - -const kTargetPlatformNameAndroid = "android"; -const kTargetPlatformNameIOS = "iOS"; -const kTargetPlatformNameMacOS = "macOS"; -const kTargetPlatformNameWindows = "windows"; -const kTargetPlatformNameLinux = "linux"; -const kTargetPlatformNameWeb = "web"; -const kTargetPlatformNameValues = [ - kTargetPlatformNameAndroid, - kTargetPlatformNameIOS, - kTargetPlatformNameMacOS, - kTargetPlatformNameWindows, - kTargetPlatformNameLinux, - kTargetPlatformNameWeb, -]; diff --git a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/enum_supported_platforms.dart b/dev_packages/flutter_inappwebview_internal_annotations/lib/src/enum_supported_platforms.dart deleted file mode 100644 index 2115a644a7..0000000000 --- a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/enum_supported_platforms.dart +++ /dev/null @@ -1,153 +0,0 @@ -import 'constants.dart'; -import 'supported_platforms.dart'; - -abstract class EnumPlatform implements Platform { - final String? available; - final String? apiName; - final String? apiUrl; - final String? note; - final String name; - final String targetPlatformName; - final dynamic value; - - const EnumPlatform({ - this.available, - this.apiName, - this.apiUrl, - this.note, - this.name = '', - this.targetPlatformName = '', - this.value, - }); -} - -class EnumAndroidPlatform implements EnumPlatform, AndroidPlatform { - final String? available; - final String? apiName; - final String? apiUrl; - final String? note; - final String name; - final String targetPlatformName; - final dynamic value; - - const EnumAndroidPlatform({ - this.available, - this.apiName, - this.apiUrl, - this.note, - this.name = kPlatformNameAndroid, - this.targetPlatformName = kTargetPlatformNameAndroid, - this.value, - }); -} - -class EnumIOSPlatform implements EnumPlatform, IOSPlatform { - final String? available; - final String? apiName; - final String? apiUrl; - final String? note; - final String name; - final String targetPlatformName; - final dynamic value; - - const EnumIOSPlatform({ - this.available, - this.apiName, - this.apiUrl, - this.note, - this.name = kPlatformNameIOS, - this.targetPlatformName = kTargetPlatformNameIOS, - this.value, - }); -} - -class EnumMacOSPlatform implements EnumPlatform, MacOSPlatform { - final String? available; - final String? apiName; - final String? apiUrl; - final String? note; - final String name; - final String targetPlatformName; - final dynamic value; - - const EnumMacOSPlatform({ - this.available, - this.apiName, - this.apiUrl, - this.note, - this.name = kPlatformNameMacOS, - this.targetPlatformName = kTargetPlatformNameMacOS, - this.value, - }); -} - -class EnumWindowsPlatform implements EnumPlatform, WindowsPlatform { - final String? available; - final String? apiName; - final String? apiUrl; - final String? note; - final String name; - final String targetPlatformName; - final dynamic value; - - const EnumWindowsPlatform({ - this.available, - this.apiName, - this.apiUrl, - this.note, - this.name = kPlatformNameWindows, - this.targetPlatformName = kTargetPlatformNameWindows, - this.value, - }); -} - -class EnumLinuxPlatform implements EnumPlatform, LinuxPlatform { - final String? available; - final String? apiName; - final String? apiUrl; - final String? note; - final String name; - final String targetPlatformName; - final dynamic value; - - const EnumLinuxPlatform({ - this.available, - this.apiName, - this.apiUrl, - this.note, - this.name = kPlatformNameLinux, - this.targetPlatformName = kTargetPlatformNameLinux, - this.value, - }); -} - -class EnumWebPlatform implements EnumPlatform, WebPlatform { - final String? available; - final String? apiName; - final String? apiUrl; - final String? note; - final String name; - final String targetPlatformName; - final dynamic value; - final bool requiresSameOrigin; - - const EnumWebPlatform( - {this.available, - this.apiName, - this.apiUrl, - this.note, - this.value, - this.name = kPlatformNameWeb, - this.targetPlatformName = kTargetPlatformNameWeb, - this.requiresSameOrigin = true}); -} - -class EnumSupportedPlatforms { - final List platforms; - final dynamic defaultValue; - - const EnumSupportedPlatforms({ - required this.platforms, - this.defaultValue, - }); -} diff --git a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_enum.dart b/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_enum.dart deleted file mode 100644 index ea66483b45..0000000000 --- a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_enum.dart +++ /dev/null @@ -1,31 +0,0 @@ -class ExchangeableEnum { - final bool valuesProperty; - final bool toValueMethod; - final bool fromValueMethod; - final bool toNativeValueMethod; - final bool fromNativeValueMethod; - final bool nameMethod; - final bool toNameMethod; - final bool byNameMethod; - final bool asNameMapMethod; - final bool toStringMethod; - final bool hashCodeMethod; - final bool equalsOperator; - final bool bitwiseOrOperator; - - const ExchangeableEnum({ - this.valuesProperty = true, - this.toValueMethod = true, - this.fromValueMethod = true, - this.toNativeValueMethod = true, - this.fromNativeValueMethod = true, - this.nameMethod = true, - this.toNameMethod = true, - this.byNameMethod = true, - this.asNameMapMethod = true, - this.toStringMethod = true, - this.hashCodeMethod = true, - this.equalsOperator = true, - this.bitwiseOrOperator = false - }); -} \ No newline at end of file diff --git a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_enum_custom_value.dart b/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_enum_custom_value.dart deleted file mode 100644 index 309efa399d..0000000000 --- a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_enum_custom_value.dart +++ /dev/null @@ -1,3 +0,0 @@ -class ExchangeableEnumCustomValue { - const ExchangeableEnumCustomValue(); -} diff --git a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_object.dart b/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_object.dart deleted file mode 100644 index e98206ef8f..0000000000 --- a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_object.dart +++ /dev/null @@ -1,19 +0,0 @@ -class ExchangeableObject { - final bool toMapMethod; - final bool toJsonMethod; - final bool fromMapFactory; - final bool fromMapForceAllInline; - final bool nullableFromMapFactory; - final bool toStringMethod; - final bool copyMethod; - - const ExchangeableObject({ - this.toMapMethod = true, - this.toJsonMethod = true, - this.fromMapFactory = true, - this.fromMapForceAllInline = false, - this.nullableFromMapFactory = true, - this.toStringMethod = true, - this.copyMethod = false - }); -} diff --git a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_object_constructor.dart b/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_object_constructor.dart deleted file mode 100644 index 13c89ce6b1..0000000000 --- a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_object_constructor.dart +++ /dev/null @@ -1,3 +0,0 @@ -class ExchangeableObjectConstructor { - const ExchangeableObjectConstructor(); -} diff --git a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_object_method.dart b/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_object_method.dart deleted file mode 100644 index d922ca6b79..0000000000 --- a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_object_method.dart +++ /dev/null @@ -1,9 +0,0 @@ -class ExchangeableObjectMethod { - final bool ignore; - final bool toMapMergeWith; - - const ExchangeableObjectMethod({ - this.ignore = false, - this.toMapMergeWith = false - }); -} diff --git a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_object_property.dart b/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_object_property.dart deleted file mode 100644 index 9ffd839555..0000000000 --- a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/exchangeable_object_property.dart +++ /dev/null @@ -1,17 +0,0 @@ -class ExchangeableObjectProperty { - final Function? serializer; - final Function? deserializer; - final bool deprecatedUseNewFieldNameInConstructor; - final bool deprecatedUseNewFieldNameInFromMapMethod; - final bool leaveDeprecatedInFromMapMethod; - final bool leaveDeprecatedInToMapMethod; - - const ExchangeableObjectProperty({ - this.serializer, - this.deserializer, - this.deprecatedUseNewFieldNameInConstructor = true, - this.deprecatedUseNewFieldNameInFromMapMethod = true, - this.leaveDeprecatedInFromMapMethod = false, - this.leaveDeprecatedInToMapMethod = false, - }); -} diff --git a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/supported_platforms.dart b/dev_packages/flutter_inappwebview_internal_annotations/lib/src/supported_platforms.dart deleted file mode 100644 index 9bb54c50ce..0000000000 --- a/dev_packages/flutter_inappwebview_internal_annotations/lib/src/supported_platforms.dart +++ /dev/null @@ -1,151 +0,0 @@ -import 'constants.dart'; - -abstract class Platform { - final String? available; - final String? apiName; - final String? apiUrl; - final String? note; - final String name; - final String targetPlatformName; - - const Platform({ - this.available, - this.apiName, - this.apiUrl, - this.note, - this.name = '', - this.targetPlatformName = '', - }); -} - -class AndroidPlatform implements Platform { - final String? available; - final String? apiName; - final String? apiUrl; - final String? note; - final String name; - final String targetPlatformName; - - const AndroidPlatform({ - this.available, - this.apiName, - this.apiUrl, - this.note, - this.name = kPlatformNameAndroid, - this.targetPlatformName = kTargetPlatformNameAndroid, - }); -} - -class IOSPlatform implements Platform { - final String? available; - final String? apiName; - final String? apiUrl; - final String? note; - final String name; - final String targetPlatformName; - - const IOSPlatform({ - this.available, - this.apiName, - this.apiUrl, - this.note, - this.name = kPlatformNameIOS, - this.targetPlatformName = kTargetPlatformNameIOS, - }); -} - -class MacOSPlatform implements Platform { - final String? available; - final String? apiName; - final String? apiUrl; - final String? note; - final String name; - final String targetPlatformName; - - const MacOSPlatform({ - this.available, - this.apiName, - this.apiUrl, - this.note, - this.name = kPlatformNameMacOS, - this.targetPlatformName = kTargetPlatformNameMacOS, - }); -} - -class WindowsPlatform implements Platform { - final String? available; - final String? apiName; - final String? apiUrl; - final String? note; - final String name; - final String targetPlatformName; - - const WindowsPlatform({ - this.available, - this.apiName, - this.apiUrl, - this.note, - this.name = kPlatformNameWindows, - this.targetPlatformName = kTargetPlatformNameWindows, - }); -} - -class LinuxPlatform implements Platform { - final String? available; - final String? apiName; - final String? apiUrl; - final String? note; - final String name; - final String targetPlatformName; - - const LinuxPlatform({ - this.available, - this.apiName, - this.apiUrl, - this.note, - this.name = kPlatformNameLinux, - this.targetPlatformName = kTargetPlatformNameLinux, - }); -} - -class WebPlatform implements Platform { - final String? available; - final String? apiName; - final String? apiUrl; - final String? note; - final String name; - final String targetPlatformName; - final bool requiresSameOrigin; - - const WebPlatform({ - this.available, - this.apiName, - this.apiUrl, - this.note, - this.requiresSameOrigin = true, - this.name = kPlatformNameWeb, - this.targetPlatformName = kTargetPlatformNameWeb, - }); -} - -class SupportedPlatforms { - final List platforms; - final bool ignore; - final List ignorePropertyNames; - final List ignoreMethodNames; - final List ignoreParameterNames; - - /// Workaround for @SupportedPlatforms annotation not working - /// on parameters of a class fields which type is a function. - /// https://github.com/dart-lang/sdk/issues/59670 - final Map> parameterPlatforms; - - const SupportedPlatforms({ - required this.platforms, - this.ignore = false, - this.ignorePropertyNames = const [], - this.ignoreMethodNames = const [], - this.ignoreParameterNames = const [], - this.parameterPlatforms = const {}, - }); -} diff --git a/dev_packages/flutter_inappwebview_internal_annotations/pubspec.yaml b/dev_packages/flutter_inappwebview_internal_annotations/pubspec.yaml deleted file mode 100755 index 206c9d3619..0000000000 --- a/dev_packages/flutter_inappwebview_internal_annotations/pubspec.yaml +++ /dev/null @@ -1,10 +0,0 @@ -name: flutter_inappwebview_internal_annotations -description: Internal annotations used by the generator of flutter_inappwebview plugin -version: 1.3.0 -homepage: https://github.com/pichillilorenzo/flutter_inappwebview - -environment: - sdk: ">=3.7.0 <4.0.0" - -dev_dependencies: - test: ^1.25.8 \ No newline at end of file diff --git a/dev_packages/generators/.gitignore b/dev_packages/generators/.gitignore deleted file mode 100755 index cac255942f..0000000000 --- a/dev_packages/generators/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock -**/doc/api/ -.dart_tool/ -.packages -build/ -.fvm/ - -flutter_driver_tests.log -tool/chromedriver -tool/chromedriver.* \ No newline at end of file diff --git a/dev_packages/generators/build.yaml b/dev_packages/generators/build.yaml deleted file mode 100644 index 802b77c537..0000000000 --- a/dev_packages/generators/build.yaml +++ /dev/null @@ -1,21 +0,0 @@ -targets: - $default: - builders: - generators|flutter_inappwebview_internal_annotations: - enabled: true - -builders: - generators: - target: ":generators" - # 1 - import: "package:generators/builder.dart" - # 2 - builder_factories: ["generateExchangeableObject", "generateExchangeableEnum", "generateSupportedPlatforms"] - # 3 - build_extensions: { ".dart": [".g.part"] } - auto_apply: dependents - build_to: cache - applies_builders: ["source_gen|combining_builder"] - defaults: - generate_for: - - lib/src/**.dart diff --git a/dev_packages/generators/lib/builder.dart b/dev_packages/generators/lib/builder.dart deleted file mode 100644 index c0d7cc08ed..0000000000 --- a/dev_packages/generators/lib/builder.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:build/build.dart'; -import 'package:source_gen/source_gen.dart'; -import 'src/exchangeable_object_generator.dart'; -import 'src/exchangeable_enum_generator.dart'; -import 'src/supported_platforms_generator.dart'; - -Builder generateExchangeableObject(BuilderOptions options) => - SharedPartBuilder([ExchangeableObjectGenerator()], 'exchangeable_object'); - -Builder generateExchangeableEnum(BuilderOptions options) => - SharedPartBuilder([ExchangeableEnumGenerator()], 'exchangeable_enum'); - -Builder generateSupportedPlatforms(BuilderOptions options) => - SharedPartBuilder([SupportedPlatformsGenerator()], 'supported_platforms'); diff --git a/dev_packages/generators/lib/generators.dart b/dev_packages/generators/lib/generators.dart deleted file mode 100644 index a436ea17e2..0000000000 --- a/dev_packages/generators/lib/generators.dart +++ /dev/null @@ -1 +0,0 @@ -library generators; diff --git a/dev_packages/generators/lib/src/exchangeable_enum_generator.dart b/dev_packages/generators/lib/src/exchangeable_enum_generator.dart deleted file mode 100644 index f7a6baa326..0000000000 --- a/dev_packages/generators/lib/src/exchangeable_enum_generator.dart +++ /dev/null @@ -1,511 +0,0 @@ -import 'package:build/build.dart'; -import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer/dart/element/type.dart'; -import 'package:analyzer/dart/analysis/results.dart'; -import 'package:source_gen/source_gen.dart'; -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; -import 'package:analyzer/dart/constant/value.dart'; - -import 'model_visitor.dart'; -import 'util.dart'; - -const _annotationsPackage = 'flutter_inappwebview_internal_annotations'; - -final _coreCheckerEnumSupportedPlatforms = TypeChecker.typeNamedLiterally( - 'EnumSupportedPlatforms', - inPackage: _annotationsPackage, -); -final _coreCheckerDeprecated = TypeChecker.typeNamedLiterally( - 'Deprecated', - inSdk: true, -); -final _coreCheckerEnumCustomValue = TypeChecker.typeNamedLiterally( - 'ExchangeableEnumCustomValue', - inPackage: _annotationsPackage, -); - -class ExchangeableEnumGenerator - extends GeneratorForAnnotation { - /// Returns the type string with nullable suffix if not already nullable - String _makeNullable(DartType type) { - final typeStr = type.toString(); - if (Util.typeIsNullable(type)) { - return typeStr; - } - return '$typeStr?'; - } - - /// Returns the base type string without nullable suffix - String _getBaseType(DartType type) { - final typeStr = type.toString(); - if (typeStr.endsWith('?')) { - return typeStr.substring(0, typeStr.length - 1); - } - return typeStr; - } - - @override - String generateForAnnotatedElement( - Element element, - ConstantReader annotation, - BuildStep buildStep, - ) { - final visitor = ModelVisitor(); - // Visits all the children of element in no particular order. - element.visitChildren(visitor); - - final className = visitor.constructor.returnType.element.name ?? ''; - // remove "_" to generate the correct class name - final extClassName = className.replaceFirst("_", ""); - - final classBuffer = StringBuffer(); - final classDocs = - visitor.constructor.returnType.element.documentationComment; - if (classDocs != null) { - classBuffer.writeln(classDocs); - } - final classSupportedDocs = Util.getSupportedDocs( - _coreCheckerEnumSupportedPlatforms, - visitor.constructor.returnType.element, - ); - if (classSupportedDocs != null) { - classBuffer.writeln(classSupportedDocs); - } - if (visitor.constructor.returnType.element.metadata.hasDeprecated) { - classBuffer.writeln( - "@Deprecated('${_coreCheckerDeprecated.firstAnnotationOfExact(visitor.constructor.returnType.element)?.getField("message")?.toStringValue()}')", - ); - } - classBuffer.writeln('class $extClassName {'); - - final fieldEntriesSorted = visitor.fields.entries.toList(); - fieldEntriesSorted.sort((a, b) => a.key.compareTo(b.key)); - - final methodEntriesSorted = visitor.methods.entries.toList(); - fieldEntriesSorted.sort((a, b) => a.key.compareTo(b.key)); - - final FieldElement enumValue = fieldEntriesSorted - .firstWhere((element) => element.key == "_value") - .value; - final FieldElement enumNativeValue = fieldEntriesSorted - .firstWhere( - (element) => element.key == "_nativeValue", - orElse: () => MapEntry("_nativeValue", enumValue), - ) - .value; - - final nativeValueNullableType = _makeNullable(enumNativeValue.type); - - classBuffer.writeln("final ${enumValue.type} _value;"); - classBuffer.writeln("final $nativeValueNullableType _nativeValue;"); - - classBuffer.writeln( - "const $extClassName._internal(this._value, this._nativeValue);", - ); - classBuffer.writeln("// ignore: unused_element"); - classBuffer.writeln( - "factory $extClassName._internalMultiPlatform(${enumValue.type} value, Function nativeValue) => $extClassName._internal(value, nativeValue());", - ); - - for (final entry in fieldEntriesSorted) { - final fieldName = entry.key; - final fieldElement = entry.value; - if (fieldName == "_value" || fieldName == "_nativeValue") { - continue; - } - final isEnumCustomValue = - _coreCheckerEnumCustomValue.firstAnnotationOf(fieldElement) != null; - if (isEnumCustomValue) { - final fieldLibrary = fieldElement.library; - if (fieldLibrary != null) { - ParsedLibraryResult parsed = - fieldLibrary.session.getParsedLibraryByElement(fieldLibrary) - as ParsedLibraryResult; - final fieldBody = parsed - .getFragmentDeclaration(fieldElement.firstFragment) - ?.node - .toString() - .replaceAll(className, extClassName); - if (fieldBody != null) { - final docs = fieldElement.documentationComment; - if (docs != null) { - classBuffer.writeln(docs); - } - if (fieldElement.isStatic) { - classBuffer.write("static "); - } - if (fieldElement.isLate) { - classBuffer.write("late "); - } - if (fieldElement.isFinal) { - classBuffer.write("final "); - } - if (fieldElement.isConst) { - classBuffer.write("const "); - } - classBuffer.writeln("$fieldBody;"); - } - } - continue; - } - final docs = fieldElement.documentationComment; - if (docs != null) { - classBuffer.writeln(docs); - } - final fieldSupportedDocs = Util.getSupportedDocs( - _coreCheckerEnumSupportedPlatforms, - fieldElement, - ); - if (fieldSupportedDocs != null) { - classBuffer.writeln(fieldSupportedDocs); - } - if (fieldName == '_value' || fieldName == '_nativeValue') { - classBuffer.writeln( - "final ${fieldElement.type.toString().replaceFirst("_", "")} $fieldName;", - ); - } else { - final fieldValue = fieldElement.computeConstantValue()?.getField( - "_value", - ); - final constantValue = fieldValue != null && !fieldValue.isNull - ? fieldValue.toIntValue() ?? "\'${fieldValue.toStringValue()}\'" - : null; - - final fieldAnnotation = _coreCheckerEnumSupportedPlatforms - .firstAnnotationOfExact(fieldElement); - if (fieldAnnotation != null) { - final defaultField = fieldAnnotation.getField('defaultValue')!; - final defaultValue = !defaultField.isNull - ? defaultField.toIntValue() ?? "'${defaultField.toStringValue()}'" - : null; - - var nativeValueBody = "() {"; - nativeValueBody += "switch (defaultTargetPlatform) {"; - final platforms = - fieldAnnotation.getField('platforms')?.toListValue() ?? - []; - var hasWebSupport = false; - var webSupportValue = null; - if (platforms.isNotEmpty) { - for (var platform in platforms) { - final targetPlatformName = platform - .getField("targetPlatformName")! - .toStringValue(); - final platformValueField = platform.getField('value'); - final platformValue = - platformValueField != null && !platformValueField.isNull - ? platformValueField.toIntValue() ?? - "'${platformValueField.toStringValue()}'" - : constantValue; - if (targetPlatformName == "web") { - hasWebSupport = true; - webSupportValue = platformValue; - continue; - } - nativeValueBody += "case TargetPlatform.$targetPlatformName:"; - nativeValueBody += "return $platformValue;"; - } - nativeValueBody += "default:"; - nativeValueBody += "break;"; - } - nativeValueBody += "}"; - if (hasWebSupport) { - nativeValueBody += "if (kIsWeb) {"; - nativeValueBody += "return $webSupportValue;"; - nativeValueBody += "}"; - } - nativeValueBody += "return $defaultValue;"; - nativeValueBody += "}"; - - classBuffer.writeln( - "static final $fieldName = $extClassName._internalMultiPlatform($constantValue, $nativeValueBody);", - ); - } else { - classBuffer.writeln( - "static const $fieldName = $extClassName._internal($constantValue, $constantValue);", - ); - } - } - } - - if (annotation.read("valuesProperty").boolValue) { - classBuffer.writeln('///Set of all values of [$extClassName].'); - classBuffer.writeln('static final Set<$extClassName> values = ['); - for (final entry in fieldEntriesSorted) { - final fieldName = entry.key; - final fieldElement = entry.value; - final isEnumCustomValue = - _coreCheckerEnumCustomValue.firstAnnotationOf(fieldElement) != null; - if (!fieldElement.isPrivate && - fieldElement.isStatic && - !isEnumCustomValue) { - classBuffer.writeln('$extClassName.$fieldName,'); - } - } - classBuffer.writeln('].toSet();'); - } - - if (annotation.read("fromValueMethod").boolValue && - (!visitor.methods.containsKey("fromValue") || - Util.methodHasIgnore(visitor.methods['fromValue']!))) { - final hasBitwiseOrOperator = annotation - .read("bitwiseOrOperator") - .boolValue; - classBuffer.writeln(""" - ///Gets a possible [$extClassName] instance from [${enumValue.type}] value. - static $extClassName? fromValue(${enumValue.type}${!Util.typeIsNullable(enumValue.type) ? '?' : ''} value) { - if (value != null) { - try { - return $extClassName.values - .firstWhere((element) => element.toValue() == value); - } catch (e) { - return ${!hasBitwiseOrOperator ? 'null' : "$extClassName._internal(value, value)"}; - } - } - return null; - } - """); - } - - if (annotation.read("fromNativeValueMethod").boolValue && - (!visitor.methods.containsKey("fromNativeValue") || - Util.methodHasIgnore(visitor.methods['fromNativeValue']!))) { - classBuffer.writeln(""" - ///Gets a possible [$extClassName] instance from a native value. - static $extClassName? fromNativeValue($nativeValueNullableType value) { - if (value != null) { - try { - return $extClassName.values - .firstWhere((element) => element.toNativeValue() == value); - } catch (e) { - return null; - } - } - return null; - } - """); - } - - if (annotation.read("nameMethod").boolValue && - annotation.read("byNameMethod").boolValue && - (!visitor.methods.containsKey("byName") || - Util.methodHasIgnore(visitor.methods['byName']!))) { - classBuffer.writeln(""" - /// Gets a possible [$extClassName] instance value with name [name]. - /// - /// Goes through [$extClassName.values] looking for a value with - /// name [name], as reported by [$extClassName.name]. - /// Returns the first value with the given name, otherwise `null`. - static $extClassName? byName(String? name) { - if (name != null) { - try { - return $extClassName.values - .firstWhere((element) => element.name() == name); - } catch (e) { - return null; - } - } - return null; - } - """); - } - - if (annotation.read("nameMethod").boolValue && - annotation.read("asNameMapMethod").boolValue && - (!visitor.methods.containsKey("asNameMap") || - Util.methodHasIgnore(visitor.methods['asNameMap']!))) { - classBuffer.writeln(""" - /// Creates a map from the names of [$extClassName] values to the values. - /// - /// The collection that this method is called on is expected to have - /// values with distinct names, like the `values` list of an enum class. - /// Only one value for each name can occur in the created map, - /// so if two or more values have the same name (either being the - /// same value, or being values of different enum type), at most one of - /// them will be represented in the returned map. - static Map asNameMap() => - {for (final value in $extClassName.values) value.name(): value}; - """); - } - - for (final entry in methodEntriesSorted) { - final methodElement = entry.value; - if (Util.methodHasIgnore(methodElement)) { - continue; - } - final methodLibrary = methodElement.library; - if (methodLibrary == null) continue; - ParsedLibraryResult parsed = - methodLibrary.session.getParsedLibraryByElement(methodLibrary) - as ParsedLibraryResult; - final methodBodyRaw = parsed - .getFragmentDeclaration(methodElement.firstFragment) - ?.node - .toString(); - if (methodBodyRaw != null) { - // Replace type names: first className, then type references ending with _ - var methodBody = methodBodyRaw - .replaceAll(className, extClassName) - .replaceAll("_.", ".") - .replaceAll("_?", "?") - .replaceAll("_>", ">") - .replaceAllMapped( - RegExp(r'([A-Z][a-zA-Z0-9]*)_\b'), - (match) => match.group(1)!, - ); - - final docs = methodElement.documentationComment; - if (docs != null) { - classBuffer.writeln(docs); - } - final fieldSupportedDocs = Util.getSupportedDocs( - _coreCheckerEnumSupportedPlatforms, - methodElement, - ); - if (fieldSupportedDocs != null) { - classBuffer.writeln(fieldSupportedDocs); - } - classBuffer.writeln(methodBody); - } - } - - if (annotation.read("toValueMethod").boolValue && - (!visitor.methods.containsKey("toValue") || - Util.methodHasIgnore(visitor.methods['toValue']!))) { - classBuffer.writeln(""" - ///Gets [${enumValue.type}] value. - ${enumValue.type} toValue() => _value; - """); - } - - if (annotation.read("toNativeValueMethod").boolValue && - (!visitor.methods.containsKey("toNativeValue") || - Util.methodHasIgnore(visitor.methods['toNativeValue']!))) { - final nativeValueBaseType = _getBaseType(enumNativeValue.type); - classBuffer.writeln(""" - ///Gets [$nativeValueBaseType] native value if supported by the current platform, otherwise `null`. - $nativeValueNullableType toNativeValue() => _nativeValue; - """); - } - - if (annotation.read("nameMethod").boolValue && - (!visitor.methods.containsKey("name") || - Util.methodHasIgnore(visitor.methods['name']!))) { - classBuffer.writeln('///Gets the name of the value.'); - classBuffer.writeln('String name() {'); - classBuffer.writeln('switch(_value) {'); - - // Track unique case values to avoid duplicates - final Set addedCases = {}; - - for (final entry in fieldEntriesSorted) { - final fieldName = entry.key; - final fieldElement = entry.value; - - // Skip custom values using ExchangeableEnumCustomValue - final isEnumCustomValue = - _coreCheckerEnumCustomValue.firstAnnotationOf(fieldElement) != null; - if (isEnumCustomValue) { - continue; - } - - if (!fieldElement.isPrivate && fieldElement.isStatic) { - final fieldValue = fieldElement.computeConstantValue()?.getField( - "_value", - ); - dynamic constantValue = fieldValue?.toIntValue(); - String caseValueStr; - - if (enumValue.type.isDartCoreString) { - final stringValue = fieldValue?.toStringValue(); - if (stringValue == null) { - // For nullable String types with null value - constantValue = 'null'; - caseValueStr = 'null'; - } else { - constantValue = "'$stringValue'"; - caseValueStr = stringValue; - } - } else { - caseValueStr = constantValue.toString(); - } - - // Only add unique case values - if (!addedCases.contains(caseValueStr)) { - addedCases.add(caseValueStr); - classBuffer.writeln("case $constantValue: return '$fieldName';"); - } - } - } - classBuffer.writeln('}'); - classBuffer.writeln('return _value.toString();'); - classBuffer.writeln('}'); - } - - if (annotation.read("hashCodeMethod").boolValue && - (!visitor.fields.containsKey("hashCode") || - Util.methodHasIgnore(visitor.methods['hashCode']!))) { - classBuffer.writeln(""" - @override - int get hashCode => _value.hashCode; - """); - } - - if (annotation.read("equalsOperator").boolValue) { - classBuffer.writeln(""" - @override - bool operator ==(value) => value == _value; - """); - } - - if (annotation.read("bitwiseOrOperator").boolValue) { - classBuffer.writeln( - "$extClassName operator |($extClassName value) => $extClassName._internal(value.toValue() | _value, ", - ); - classBuffer.write( - "value.toNativeValue() != null && _nativeValue != null ? value.toNativeValue()! | _nativeValue! : null", - ); - classBuffer.write(");"); - } - - classBuffer.writeln( - '///Checks if the value is supported by the [defaultTargetPlatform].', - ); - classBuffer.writeln('bool isSupported() {'); - classBuffer.writeln('return _nativeValue != null;'); - classBuffer.writeln('}'); - - if (annotation.read("toStringMethod").boolValue && - (!visitor.methods.containsKey("toString") || - Util.methodHasIgnore(visitor.methods['toString']!))) { - classBuffer.writeln('@override'); - classBuffer.writeln('String toString() {'); - if (enumValue.type.isDartCoreString) { - classBuffer.writeln('return _value;'); - } else { - if (annotation.read("nameMethod").boolValue) { - classBuffer.writeln('return name();'); - } else { - classBuffer.writeln('switch(_value) {'); - for (final entry in fieldEntriesSorted) { - final fieldName = entry.key; - final fieldElement = entry.value; - if (!fieldElement.isPrivate && fieldElement.isStatic) { - final fieldValue = fieldElement.computeConstantValue()?.getField( - "_value", - ); - final constantValue = fieldValue?.toIntValue(); - classBuffer.writeln("case $constantValue: return '$fieldName';"); - } - } - classBuffer.writeln('}'); - classBuffer.writeln('return _value.toString();'); - } - } - classBuffer.writeln('}'); - } - - classBuffer.writeln('}'); - return classBuffer.toString(); - } -} diff --git a/dev_packages/generators/lib/src/exchangeable_object_generator.dart b/dev_packages/generators/lib/src/exchangeable_object_generator.dart deleted file mode 100644 index 9b38ca50d7..0000000000 --- a/dev_packages/generators/lib/src/exchangeable_object_generator.dart +++ /dev/null @@ -1,1185 +0,0 @@ -import 'package:analyzer/dart/analysis/results.dart'; -import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer/dart/element/type.dart'; -import 'package:build/build.dart'; -import 'package:collection/collection.dart'; -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; -import 'package:source_gen/source_gen.dart'; - -import 'model_visitor.dart'; -import 'util.dart'; - -const _annotationsPackage = 'flutter_inappwebview_internal_annotations'; - -final _coreChecker = TypeChecker.typeNamedLiterally( - 'ExchangeableObject', - inPackage: _annotationsPackage, -); -final _coreCheckerObjectConstructor = TypeChecker.typeNamedLiterally( - 'ExchangeableObjectConstructor', - inPackage: _annotationsPackage, -); -final _coreCheckerObjectProperty = TypeChecker.typeNamedLiterally( - 'ExchangeableObjectProperty', - inPackage: _annotationsPackage, -); -final _coreCheckerObjectMethod = TypeChecker.typeNamedLiterally( - 'ExchangeableObjectMethod', - inPackage: _annotationsPackage, -); -final _coreCheckerEnum = TypeChecker.typeNamedLiterally( - 'ExchangeableEnum', - inPackage: _annotationsPackage, -); -final _coreCheckerDeprecated = TypeChecker.typeNamedLiterally( - 'Deprecated', - inSdk: true, -); -final _coreCheckerSupportedPlatforms = TypeChecker.typeNamedLiterally( - 'SupportedPlatforms', - inPackage: _annotationsPackage, -); - -class ExchangeableObjectGenerator - extends GeneratorForAnnotation { - @override - String generateForAnnotatedElement( - Element element, - ConstantReader annotation, - BuildStep buildStep, - ) { - final visitor = ModelVisitor(); - // Visits all the children of element in no particular order. - element.visitChildren(visitor); - - final className = visitor.constructor.returnType.element.name; - final superClass = - visitor.constructor.returnType.superclass?.element.name != 'Object' - ? visitor.constructor.returnType.superclass - : null; - final interfaces = visitor.constructor.returnType.interfaces; - final superClassName = superClass?.element.name?.replaceFirst("_", ""); - // remove "_" to generate the correct class name - final extClassName = (className ?? '').replaceFirst("_", ""); - - final classBuffer = StringBuffer(); - final classDocs = - visitor.constructor.returnType.element.documentationComment; - if (classDocs != null) { - classBuffer.writeln(classDocs); - } - final classSupportedDocs = Util.getSupportedDocs( - _coreCheckerSupportedPlatforms, - visitor.constructor.returnType.element, - ); - if (classSupportedDocs != null) { - classBuffer.writeln(classSupportedDocs); - } - if (visitor.constructor.returnType.element.metadata.hasDeprecated) { - classBuffer.writeln( - "@Deprecated('${_coreCheckerDeprecated.firstAnnotationOfExact(visitor.constructor.returnType.element)?.getField("message")?.toStringValue()}')", - ); - } - - classBuffer.write( - '${(visitor.constructor.enclosingElement as ClassElement).isAbstract ? 'abstract ' : ''}class $extClassName', - ); - if (interfaces.isNotEmpty) { - classBuffer.writeln( - ' implements ${interfaces.map((i) => (i.element.name ?? '').replaceFirst("_", "")).join(', ')}', - ); - } - if (superClass != null) { - classBuffer.writeln(' extends ${superClassName}'); - } - classBuffer.writeln(' {'); - - final deprecatedFields = []; - final constructorFields = []; - final superConstructorFields = []; - final initializerAssignments = []; - - final fieldEntriesSorted = visitor.fields.entries.toList(); - fieldEntriesSorted.sort((a, b) => a.key.compareTo(b.key)); - - final fieldValuesSorted = visitor.fields.values.toList(); - fieldValuesSorted.sort((a, b) => (a.name ?? '').compareTo(b.name ?? '')); - - final methodEntriesSorted = visitor.methods.entries.toList(); - fieldEntriesSorted.sort((a, b) => a.key.compareTo(b.key)); - - // Check if constructor is custom before processing fields - final hasCustomConstructor = _coreCheckerObjectConstructor.hasAnnotationOf( - visitor.constructor, - ); - - for (final entry in fieldEntriesSorted) { - final fieldName = entry.key; - final fieldElement = entry.value; - if (!fieldElement.isPrivate) { - final isNullable = Util.typeIsNullable(fieldElement.type); - final constructorParameter = visitor.constructorParameters[fieldName]; - if (constructorParameter != null) { - // remove class reference terminating with "_" - var defaultValueCode = constructorParameter.defaultValueCode - ?.replaceFirst("_.", "."); - - // Check if the field type is an ExchangeableEnum (non-const default) - // Only apply this logic for generated constructors, not custom ones - final fieldTypeElement = fieldElement.type.element; - final isExchangeableEnum = - !hasCustomConstructor && - fieldTypeElement != null && - _coreCheckerEnum.hasAnnotationOf(fieldTypeElement); - - // If default value references an ExchangeableEnum, use initializer list - final useInitializerList = - isExchangeableEnum && defaultValueCode != null; - - var constructorField = ''; - if (useInitializerList) { - // Use regular parameter (not this.field) with nullable type - final baseType = fieldElement.type.toString().replaceFirst("_", ""); - final nullableType = isNullable ? baseType : '$baseType?'; - constructorField = '$nullableType $fieldName'; - // Add to initializer list - initializerAssignments.add( - '$fieldName = $fieldName ?? $defaultValueCode', - ); - } else { - constructorField = - '${!isNullable && defaultValueCode == null ? 'required ' : ''}this.$fieldName${defaultValueCode != null ? ' = $defaultValueCode' : ''}'; - } - - if (fieldElement.metadata.hasDeprecated) { - deprecatedFields.add(fieldElement); - constructorField = - "@Deprecated('${_coreCheckerDeprecated.firstAnnotationOfExact(fieldElement)?.getField("message")?.toStringValue()}') " + - constructorField; - } - constructorFields.add(constructorField); - } - } - final docs = fieldElement.documentationComment; - if (docs != null) { - classBuffer.writeln(docs); - } - final fieldSupportedDocs = Util.getSupportedDocs( - _coreCheckerSupportedPlatforms, - fieldElement, - ); - if (fieldSupportedDocs != null) { - classBuffer.writeln(fieldSupportedDocs); - } - if (fieldElement.metadata.hasDeprecated) { - classBuffer.writeln( - "@Deprecated('${_coreCheckerDeprecated.firstAnnotationOfExact(fieldElement)?.getField("message")?.toStringValue()}')", - ); - } - if (fieldElement.isStatic) { - classBuffer.write("static "); - } - if (fieldElement.isLate) { - classBuffer.write("late "); - } - if (fieldElement.isFinal) { - classBuffer.write("final "); - } - if (fieldElement.isConst) { - classBuffer.write("const "); - } - // remove class reference terminating with "_" - classBuffer.write( - "${fieldElement.type.toString().replaceFirst("_", "")} ", - ); - if (!fieldElement.hasInitializer) { - classBuffer.writeln("$fieldName;"); - } else { - final fieldLibrary = fieldElement.library; - if (fieldLibrary != null) { - ParsedLibraryResult parsed = - fieldLibrary.session.getParsedLibraryByElement(fieldLibrary) - as ParsedLibraryResult; - final fieldBody = parsed - .getFragmentDeclaration(fieldElement.firstFragment) - ?.node - .toString() - .replaceAll(className ?? '', extClassName); - classBuffer.writeln("$fieldBody;"); - } - } - } - - if (superClass != null) { - ConstructorElement superConstructor = superClass.constructors.first; - for (final parameter in superConstructor.formalParameters) { - final parameterName = parameter.name ?? ''; - final parameterType = parameter.type; - final isNullable = Util.typeIsNullable(parameter.type); - // remove class reference terminating with "_" - var defaultValueCode = parameter.defaultValueCode?.replaceFirst( - "_.", - ".", - ); - var constructorField = - '${!isNullable && defaultValueCode == null ? 'required ' : ''}${parameterType.toString().replaceFirst("_", "")} $parameterName${defaultValueCode != null ? ' = $defaultValueCode' : ''}'; - if (parameter.metadata.hasDeprecated) { - deprecatedFields.add(parameter); - constructorField = - "@Deprecated('${_coreCheckerDeprecated.firstAnnotationOfExact(parameter)?.getField("message")?.toStringValue()}') " + - constructorField; - } - constructorFields.add(constructorField); - superConstructorFields.add("$parameterName: $parameterName"); - } - } - - final constructorDocs = visitor.constructor.documentationComment; - if (constructorDocs != null) { - classBuffer.writeln(constructorDocs); - } - var constructorSupportedDocs = Util.getSupportedDocs( - _coreCheckerSupportedPlatforms, - visitor.constructor, - ); - if (constructorSupportedDocs == null) { - constructorSupportedDocs = Util.getSupportedDocs( - _coreCheckerSupportedPlatforms, - visitor.constructor.returnType.element, - ); - } - if (constructorSupportedDocs != null) { - classBuffer.writeln(constructorSupportedDocs); - } - if (hasCustomConstructor) { - final library = visitor.constructor.library; - if (library != null) { - ParsedLibraryResult parsed = - library.session.getParsedLibraryByElement(library) - as ParsedLibraryResult; - final constructorBody = parsed - .getFragmentDeclaration(visitor.constructor.firstFragment) - ?.node; - if (constructorBody != null) { - var generatedConstructor = constructorBody - .toString() - .replaceAll(className ?? '', extClassName) - .replaceAll("@ExchangeableObjectConstructor()", ""); - - // Replace type names ending with _ (e.g., CompressFormat_? -> CompressFormat?) - // First replace _. (type access) then _? (nullable type) then _ (type name) - generatedConstructor = generatedConstructor - .replaceAll("_.", ".") - .replaceAll("_?", "?") - .replaceAll("_>", ">") - .replaceAllMapped( - RegExp(r'([A-Z][a-zA-Z0-9]*)_\b'), - (match) => match.group(1)!, - ); - - classBuffer.writeln(generatedConstructor); - } - } - } else if (constructorFields.length > 0) { - if (visitor.constructor.isConst) { - classBuffer.write('const '); - } - classBuffer.writeln('$extClassName({'); - classBuffer.writeln(constructorFields.join(', ')); - } else { - if (visitor.constructor.isConst) { - classBuffer.write('const '); - } - classBuffer.writeln('$extClassName('); - } - - if (!hasCustomConstructor && constructorFields.length > 0) { - classBuffer.write('})'); - } else if (!hasCustomConstructor) { - classBuffer.write(')'); - } - - // Add initializer list (super + field initializers) - final hasInitializers = - superClass != null || initializerAssignments.isNotEmpty; - if (hasInitializers) { - classBuffer.write(' : '); - final initializers = []; - - if (superClass != null) { - initializers.add('super(${superConstructorFields.join(", ")})'); - } - - initializers.addAll(initializerAssignments); - classBuffer.write(initializers.join(', ')); - } - - // Add constructor body for deprecated fields only - final hasConstructorBody = - !hasCustomConstructor && deprecatedFields.length > 0; - - if (hasConstructorBody) { - classBuffer.writeln(' {'); - for (final deprecatedField in deprecatedFields) { - final deprecatedUseNewFieldNameInConstructor = - _coreCheckerObjectProperty - .firstAnnotationOf(deprecatedField) - ?.getField("deprecatedUseNewFieldNameInConstructor") - ?.toBoolValue() ?? - true; - if (!deprecatedUseNewFieldNameInConstructor) { - continue; - } - - final message = _coreCheckerDeprecated - .firstAnnotationOfExact(deprecatedField)! - .getField("message")! - .toStringValue()! - .trim(); - if (!message.startsWith("Use ") && !message.endsWith(" instead")) { - continue; - } - - final newFieldName = message - .replaceFirst("Use ", "") - .replaceFirst(" instead", "") - .trim(); - - final newFieldElement = visitor.fields[newFieldName]; - final shouldUseNewFieldName = newFieldElement != null; - if (shouldUseNewFieldName) { - final deprecatedFieldName = deprecatedField.name; - final fieldTypeElement = newFieldElement.type.element; - final deprecatedFieldTypeElement = deprecatedField.type.element; - - final isNullable = Util.typeIsNullable(newFieldElement.type); - var hasDefaultValue = (newFieldElement is FormalParameterElement) - ? (newFieldElement as FormalParameterElement).hasDefaultValue - : false; - if (!isNullable && hasDefaultValue) { - continue; - } - - classBuffer.write('$newFieldName = $newFieldName ?? '); - if (fieldTypeElement != null && deprecatedFieldTypeElement != null) { - final deprecatedIsNullable = Util.typeIsNullable( - deprecatedField.type, - ); - final hasFromMap = hasFromMapMethod(fieldTypeElement); - final hasFromNativeValue = hasFromNativeValueMethod( - fieldTypeElement, - ); - final hasFromValue = hasFromValueMethod(fieldTypeElement); - final deprecatedHasToMap = hasFromMapMethod( - deprecatedFieldTypeElement, - ); - final deprecatedHasToNativeValue = hasToNativeValueMethod( - deprecatedFieldTypeElement, - ); - final deprecatedHasToValue = hasToValueMethod( - deprecatedFieldTypeElement, - ); - if (hasFromMap && deprecatedHasToMap) { - final hasNullableFromMap = hasNullableFromMapFactory( - fieldTypeElement, - ); - classBuffer.write( - fieldTypeElement.name!.replaceFirst("_", "") + - ".fromMap($deprecatedFieldName${deprecatedIsNullable ? '?' : ''}.toMap())${!isNullable && hasNullableFromMap ? '!' : ''}", - ); - } else if (hasFromNativeValue && deprecatedHasToNativeValue) { - classBuffer.write( - fieldTypeElement.name!.replaceFirst("_", "") + - '.fromNativeValue($deprecatedFieldName${deprecatedIsNullable ? '?' : ''}.toNativeValue())${!isNullable ? '!' : ''}', - ); - } else if (hasFromValue && deprecatedHasToValue) { - classBuffer.write( - fieldTypeElement.name!.replaceFirst("_", "") + - '.fromValue($deprecatedFieldName${deprecatedIsNullable ? '?' : ''}.toValue())${!isNullable ? '!' : ''}', - ); - } else if (deprecatedField.type.getDisplayString( - withNullability: false, - ) == - "Uri" && - newFieldElement.type.getDisplayString(withNullability: false) == - "WebUri") { - if (deprecatedIsNullable) { - classBuffer.write( - "($deprecatedFieldName != null ? WebUri.uri($deprecatedFieldName!) : ${isNullable ? "null" : "WebUri('')"})", - ); - } else { - classBuffer.write("WebUri.uri($deprecatedFieldName)"); - } - } else { - classBuffer.write(deprecatedFieldName); - } - } else { - classBuffer.write(deprecatedFieldName); - } - classBuffer.writeln(';'); - } - } - classBuffer.writeln('}'); // Close constructor body - } else if (!hasCustomConstructor) { - classBuffer.writeln(';'); - } - - if (annotation.read("fromMapFactory").boolValue && - (!visitor.methods.containsKey("fromMap") || - Util.methodHasIgnore(visitor.methods['fromMap']!))) { - classBuffer.writeln( - '///Gets a possible [$extClassName] instance from a [Map] value.', - ); - final nullable = annotation.read("nullableFromMapFactory").boolValue; - classBuffer.writeln( - 'static $extClassName${nullable ? '?' : ''} fromMap(', - ); - classBuffer.writeln( - 'Map${nullable ? '?' : ''} map, {EnumMethod? enumMethod}', - ); - classBuffer.writeln(') {'); - if (nullable) { - classBuffer.writeln('if (map == null) { return null; }'); - } - classBuffer.writeln('final instance = $extClassName('); - final fieldElements = []; - if (superClass != null) { - fieldElements.addAll(superClass.element.fields); - } - fieldElements.addAll(fieldValuesSorted); - final nonRequiredFields = []; - final requiredFields = []; - for (final fieldElement in fieldElements) { - final fieldName = fieldElement.name; - if (!fieldElement.isPrivate && - !fieldElement.isStatic && - !(fieldElement.type.isDartCoreFunction || - fieldElement.type is FunctionType)) { - var value = "map['$fieldName']"; - - if (fieldElement.metadata.hasDeprecated) { - final deprecatedUseNewFieldNameInFromMapMethod = - _coreCheckerObjectProperty - .firstAnnotationOf(fieldElement) - ?.getField("deprecatedUseNewFieldNameInFromMapMethod") - ?.toBoolValue() ?? - true; - - final deprecationMessage = _coreCheckerDeprecated - .firstAnnotationOfExact(fieldElement) - ?.getField("message") - ?.toStringValue() - ?.trim(); - if (deprecationMessage != null && - deprecationMessage.startsWith("Use ") && - deprecationMessage.endsWith(" instead") && - deprecatedUseNewFieldNameInFromMapMethod) { - final newFieldName = deprecationMessage - .replaceFirst("Use ", "") - .replaceFirst(" instead", "") - .trim(); - final newFieldElement = fieldElements.firstWhereOrNull( - (element) => element.name == newFieldName, - ); - final shouldUseNewFieldName = - newFieldElement != null && - (newFieldElement.type == fieldElement.type || - ((fieldElement.name ?? '').startsWith( - RegExp(r'android|ios'), - ) && - (fieldElement.name ?? '').toLowerCase().replaceFirst( - RegExp(r'android|ioswk|ios'), - "", - ) == - newFieldName.toLowerCase()) || - (newFieldElement.type.element != null && - fieldElement.type.element != null && - ((hasFromNativeValueMethod( - newFieldElement.type.element!, - ) && - hasFromNativeValueMethod( - fieldElement.type.element!, - ) || - (hasFromMapMethod( - newFieldElement.type.element!, - ) && - hasFromMapMethod( - fieldElement.type.element!, - )))))); - if (shouldUseNewFieldName) { - value = "map['$newFieldName']"; - } - } else { - final leaveDeprecatedInFromMapMethod = - _coreCheckerObjectProperty - .firstAnnotationOf(fieldElement) - ?.getField("leaveDeprecatedInFromMapMethod") - ?.toBoolValue() ?? - false; - if (!leaveDeprecatedInFromMapMethod) { - continue; - } - } - } - - final mapValue = value; - - final customDeserializer = _coreCheckerObjectProperty - .firstAnnotationOf(fieldElement) - ?.getField("deserializer") - ?.toFunctionValue(); - if (customDeserializer != null) { - final deserializerClassName = - customDeserializer.enclosingElement?.name; - if (deserializerClassName != null && - deserializerClassName.isNotEmpty) { - value = - "$deserializerClassName.${customDeserializer.name}($value, enumMethod: enumMethod)"; - } else { - value = - "${customDeserializer.name}($value, enumMethod: enumMethod)"; - } - } else { - value = getFromMapValue(value, fieldElement.type); - } - final constructorParameter = visitor.constructorParameters[fieldName]; - final isRequiredParameter = - constructorParameter != null && - (constructorParameter.isRequiredNamed || - constructorParameter.isFinal || - fieldElement.isFinal || - !Util.typeIsNullable(constructorParameter.type)) && - !constructorParameter.hasDefaultValue; - if (isRequiredParameter || - fieldElement.isFinal || - annotation.read("fromMapForceAllInline").boolValue) { - requiredFields.add('$fieldName: $value,'); - } else { - final isFieldNullable = Util.typeIsNullable(fieldElement.type); - if (!isFieldNullable) { - nonRequiredFields.add("if ($mapValue != null) {"); - } - nonRequiredFields.add("instance.$fieldName = $value;"); - if (!isFieldNullable) { - nonRequiredFields.add("}"); - } - } - } - } - classBuffer.writeln(requiredFields.join("\n") + ');'); - if (nonRequiredFields.isNotEmpty) { - classBuffer.writeln(nonRequiredFields.join("\n")); - } - classBuffer.writeln('return instance;'); - classBuffer.writeln('}'); - } - - for (final entry in methodEntriesSorted) { - final methodElement = entry.value; - if (Util.methodHasIgnore(methodElement)) { - continue; - } - final methodLibrary = methodElement.library; - if (methodLibrary != null) { - ParsedLibraryResult parsed = - methodLibrary.session.getParsedLibraryByElement(methodLibrary) - as ParsedLibraryResult; - final methodBody = parsed - .getFragmentDeclaration(methodElement.firstFragment) - ?.node; - if (methodBody != null) { - final docs = methodElement.documentationComment; - if (docs != null) { - classBuffer.writeln(docs); - } - final fieldSupportedDocs = Util.getSupportedDocs( - _coreCheckerSupportedPlatforms, - methodElement, - ); - if (fieldSupportedDocs != null) { - classBuffer.writeln(fieldSupportedDocs); - } - classBuffer.writeln( - methodBody.toString().replaceAll(className ?? '', extClassName), - ); - } - } - } - - if (annotation.read("toMapMethod").boolValue && - (!visitor.methods.containsKey("toMap") || - Util.methodHasIgnore(visitor.methods['toMap']!))) { - classBuffer.writeln('///Converts instance to a map.'); - classBuffer.writeln( - 'Map toMap({EnumMethod? enumMethod}) {', - ); - classBuffer.writeln('return {'); - final fieldElements = []; - if (superClass != null) { - for (final fieldElement in superClass.element.fields) { - if (!fieldElement.isPrivate && - !fieldElement.isStatic && - !(fieldElement.type.isDartCoreFunction || - fieldElement.type is FunctionType)) { - fieldElements.add(fieldElement); - } - } - } - for (final entry in fieldEntriesSorted) { - final fieldElement = entry.value; - if (!fieldElement.isPrivate && - !fieldElement.isStatic && - !(fieldElement.type.isDartCoreFunction || - fieldElement.type is FunctionType)) { - fieldElements.add(fieldElement); - } - } - for (final fieldElement in fieldElements) { - if (!fieldElement.isPrivate && - !fieldElement.isStatic && - !(fieldElement.type.isDartCoreFunction || - fieldElement.type is FunctionType)) { - if (fieldElement.metadata.hasDeprecated) { - final leaveDeprecatedInToMapMethod = - _coreCheckerObjectProperty - .firstAnnotationOf(fieldElement) - ?.getField("leaveDeprecatedInToMapMethod") - ?.toBoolValue() ?? - false; - if (!leaveDeprecatedInToMapMethod) { - continue; - } - } - - final fieldName = fieldElement.name ?? ''; - var mapValue = fieldName; - final customSerializer = _coreCheckerObjectProperty - .firstAnnotationOf(fieldElement) - ?.getField("serializer") - ?.toFunctionValue(); - if (customSerializer != null) { - final serializerClassName = customSerializer.enclosingElement?.name; - if (serializerClassName != null && serializerClassName.isNotEmpty) { - mapValue = - "$serializerClassName.${customSerializer.name}($mapValue, enumMethod: enumMethod)"; - } else { - mapValue = - "${customSerializer.name}($mapValue, enumMethod: enumMethod)"; - } - } else { - mapValue = getToMapValue(fieldName, fieldElement.type); - } - - classBuffer.writeln('"$fieldName": $mapValue,'); - } - } - for (final entry in methodEntriesSorted) { - final methodElement = entry.value; - final toMapMergeWith = _coreCheckerObjectMethod - .firstAnnotationOf(methodElement) - ?.getField("toMapMergeWith") - ?.toBoolValue(); - if (toMapMergeWith == true) { - classBuffer.writeln( - '...${methodElement.name}(enumMethod: enumMethod),', - ); - } - } - classBuffer.writeln('};'); - classBuffer.writeln('}'); - } - - if (annotation.read("toJsonMethod").boolValue && - (!visitor.methods.containsKey("toJson") || - Util.methodHasIgnore(visitor.methods['toJson']!))) { - classBuffer.writeln('///Converts instance to a map.'); - classBuffer.writeln('Map toJson() {'); - classBuffer.writeln('return toMap();'); - classBuffer.writeln('}'); - } - - if (annotation.read("copyMethod").boolValue && - (!visitor.methods.containsKey("copy") || - Util.methodHasIgnore(visitor.methods['copy']!))) { - classBuffer.writeln('///Returns a copy of $extClassName.'); - classBuffer.writeln('$extClassName copy() {'); - classBuffer.writeln( - 'return $extClassName.fromMap(toMap()) ?? $extClassName();', - ); - classBuffer.writeln('}'); - } - - if (annotation.read("toStringMethod").boolValue && - (!visitor.methods.containsKey("toString") || - Util.methodHasIgnore(visitor.methods['toString']!))) { - classBuffer.writeln('@override'); - classBuffer.writeln('String toString() {'); - classBuffer.write('return \'$extClassName{'); - final fieldNames = []; - if (superClass != null) { - for (final fieldElement in superClass.element.fields) { - final fieldName = fieldElement.name; - if (!fieldElement.isPrivate && - !fieldElement.metadata.hasDeprecated && - !fieldElement.isStatic && - !(fieldElement.type.isDartCoreFunction || - fieldElement.type is FunctionType)) { - fieldNames.add('$fieldName: \$$fieldName'); - } - } - } - for (final entry in fieldEntriesSorted) { - final fieldName = entry.key; - final fieldElement = entry.value; - if (!fieldElement.isPrivate && - !fieldElement.metadata.hasDeprecated && - !fieldElement.isStatic && - !(fieldElement.type.isDartCoreFunction || - fieldElement.type is FunctionType)) { - fieldNames.add('$fieldName: \$$fieldName'); - } - } - classBuffer.write(fieldNames.join(', ')); - classBuffer.writeln('}\';'); - classBuffer.writeln('}'); - } - - classBuffer.writeln('}'); - return classBuffer.toString(); - } - - String getFromMapValue(String value, DartType elementType) { - final fieldTypeElement = elementType.element; - // remove class reference terminating with "_" - final classNameReference = fieldTypeElement?.name?.replaceFirst("_", ""); - final isNullable = Util.typeIsNullable(elementType); - final displayString = elementType.getDisplayString(withNullability: false); - if (displayString == "Uri") { - if (!isNullable) { - return "(Uri.tryParse($value) ?? Uri())"; - } else { - return "$value != null ? Uri.tryParse($value) : null"; - } - } else if (displayString == "WebUri") { - if (!isNullable) { - return "WebUri($value)"; - } else { - return "$value != null ? WebUri($value) : null"; - } - } else if (displayString == "Color" || displayString == "Color_") { - if (!isNullable) { - return "UtilColor.fromStringRepresentation($value)!"; - } else { - return "$value != null ? UtilColor.fromStringRepresentation($value) : null"; - } - } else if (displayString == "EdgeInsets") { - return "MapEdgeInsets.fromMap($value?.cast())${!isNullable ? '!' : ''}"; - } else if (displayString == "Size") { - return "MapSize.fromMap($value?.cast())${!isNullable ? '!' : ''}"; - } else if (displayString == "DateTime") { - if (!isNullable) { - return "DateTime.fromMillisecondsSinceEpoch($value)!"; - } else { - return "$value != null ? DateTime.fromMillisecondsSinceEpoch($value) : null"; - } - } else if (displayString == "Uint8List") { - if (!isNullable) { - return "Uint8List.fromList($value.cast())"; - } else { - return "$value != null ? Uint8List.fromList($value.cast()) : null"; - } - } else if (elementType.isDartCoreList || elementType.isDartCoreSet) { - final genericTypes = Util.getGenericTypes(elementType); - final genericType = genericTypes.isNotEmpty ? genericTypes.first : null; - final genericTypeReplaced = genericType != null - ? genericType.toString().replaceAll("_", "") - : null; - if (genericType != null && !Util.isDartCoreType(genericType)) { - final genericTypeFieldName = 'e'; - return (isNullable ? '$value != null ? ' : '') + - "${elementType.isDartCoreSet ? 'Set' : 'List'}<$genericTypeReplaced>.from(" + - value + - '.map(($genericTypeFieldName) => ' + - getFromMapValue('$genericTypeFieldName', genericType) + - '))' + - (isNullable ? ' : null' : ''); - } else { - if (genericType != null) { - return (isNullable ? '$value != null ? ' : '') + - "${elementType.isDartCoreSet ? 'Set' : 'List'}<$genericTypeReplaced>.from(" + - "$value!.cast<${genericTypeReplaced}>())" + - (isNullable ? ' : null' : ''); - } else { - return value; - } - } - } else if (elementType.isDartCoreMap) { - final genericTypes = Util.getGenericTypes(elementType); - return "$value${isNullable ? '?' : ''}.cast<${genericTypes.elementAt(0)}, ${genericTypes.elementAt(1)}>()"; - } else if (fieldTypeElement != null && hasFromMapMethod(fieldTypeElement)) { - final hasNullableFromMap = hasNullableFromMapFactory(fieldTypeElement); - return classNameReference! + - ".fromMap($value?.cast(), enumMethod: enumMethod)${!isNullable && hasNullableFromMap ? '!' : ''}"; - } else { - final hasFromValue = - fieldTypeElement != null && hasFromValueMethod(fieldTypeElement); - final hasFromNativeValue = - fieldTypeElement != null && - hasFromNativeValueMethod(fieldTypeElement); - final hasByName = - fieldTypeElement != null && hasByNameMethod(fieldTypeElement); - if (fieldTypeElement != null && - (hasFromValue || hasFromNativeValue || hasByName)) { - if ([ - hasFromValue, - hasFromNativeValue, - hasByName, - ].where((e) => e).length > - 1) { - String? defaultEnumMethodValue = null; - if (hasFromNativeValue) { - defaultEnumMethodValue = "EnumMethod.nativeValue"; - } else if (hasFromValue) { - defaultEnumMethodValue = "EnumMethod.value"; - } else { - defaultEnumMethodValue = "EnumMethod.name"; - } - var wrapper = "switch (enumMethod ?? $defaultEnumMethodValue) {"; - wrapper += - "EnumMethod.nativeValue => " + - (hasFromNativeValue - ? classNameReference! + '.fromNativeValue($value)' - : "null") + - ", "; - wrapper += - "EnumMethod.value => " + - (hasFromValue - ? classNameReference! + '.fromValue($value)' - : "null") + - ", "; - wrapper += - "EnumMethod.name => " + - (hasByName ? classNameReference! + '.byName($value)' : "null"); - wrapper += "}"; - value = wrapper; - } else { - if (hasFromNativeValue) { - value = classNameReference! + '.fromNativeValue($value)'; - } else if (hasFromValue) { - value = classNameReference! + '.fromValue($value)'; - } else { - value = classNameReference! + '.byName($value)'; - } - } - if (!isNullable) { - value += '!'; - } - return value; - } - } - - return value; - } - - String getToMapValue(String fieldName, DartType elementType) { - final fieldTypeElement = elementType.element; - final isNullable = Util.typeIsNullable(elementType); - final displayString = elementType.getDisplayString(withNullability: false); - if (displayString == "Uri") { - return fieldName + (isNullable ? '?' : '') + '.toString()'; - } else if (displayString == "WebUri") { - return fieldName + (isNullable ? '?' : '') + '.toString()'; - } else if (displayString == "Color" || displayString == "Color_") { - return fieldName + (isNullable ? '?' : '') + '.toHex()'; - } else if (displayString == "EdgeInsets") { - return fieldName + (isNullable ? '?' : '') + '.toMap()'; - } else if (displayString == "Size") { - return fieldName + (isNullable ? '?' : '') + '.toMap()'; - } else if (displayString == "DateTime") { - return fieldName + (isNullable ? '?' : '') + '.millisecondsSinceEpoch'; - } else if (elementType.isDartCoreList || elementType.isDartCoreSet) { - final genericType = Util.getGenericTypes(elementType).first; - if (!Util.isDartCoreType(genericType)) { - final genericTypeFieldName = 'e'; - return fieldName + - (isNullable ? '?' : '') + - '.map(($genericTypeFieldName) => ' + - getToMapValue('$genericTypeFieldName', genericType) + - ').toList()'; - } else { - return elementType.isDartCoreSet - ? "$fieldName${(isNullable ? '?' : '')}.toList()" - : fieldName; - } - } else if (fieldTypeElement != null && hasToMapMethod(fieldTypeElement)) { - return fieldName + - (Util.typeIsNullable(elementType) ? '?' : '') + - '.toMap(enumMethod: enumMethod)'; - } else { - final hasToValue = - fieldTypeElement != null && hasToValueMethod(fieldTypeElement); - final hasToNativeValue = - fieldTypeElement != null && hasToNativeValueMethod(fieldTypeElement); - final hasName = - fieldTypeElement != null && hasNameMethod(fieldTypeElement); - if (fieldTypeElement != null && - (hasToValue || hasToNativeValue || hasName)) { - if ([hasToValue, hasToNativeValue, hasName].where((e) => e).length > - 1) { - String? defaultEnumMethodValue = null; - if (hasToNativeValue) { - defaultEnumMethodValue = "EnumMethod.nativeValue"; - } else if (hasToValue) { - defaultEnumMethodValue = "EnumMethod.value"; - } else { - defaultEnumMethodValue = "EnumMethod.name"; - } - var wrapper = "switch (enumMethod ?? $defaultEnumMethodValue) {"; - wrapper += - "EnumMethod.nativeValue => " + - (hasToNativeValue - ? (fieldName + (isNullable ? '?' : '') + '.toNativeValue()') - : "null") + - ", "; - wrapper += - "EnumMethod.value => " + - (hasToValue - ? (fieldName + (isNullable ? '?' : '') + '.toValue()') - : "null") + - ", "; - wrapper += - "EnumMethod.name => " + - (hasName - ? (fieldName + (isNullable ? '?' : '') + '.name()') - : "null"); - wrapper += "}"; - return wrapper; - } else { - if (hasToNativeValue) { - return fieldName + (isNullable ? '?' : '') + '.toNativeValue()'; - } else if (hasToValue) { - return fieldName + (isNullable ? '?' : '') + '.toValue()'; - } else { - return fieldName + (isNullable ? '?' : '') + '.name()'; - } - } - } - } - - return fieldName; - } - - bool hasToMapMethod(Element element) { - final hasAnnotation = _coreChecker.hasAnnotationOf(element); - final toMapMethod = - _coreChecker - .firstAnnotationOfExact(element) - ?.getField('toMapMethod') - ?.toBoolValue() ?? - false; - if (hasAnnotation && toMapMethod) { - return true; - } - - final fieldVisitor = ModelVisitor(); - element.visitChildren(fieldVisitor); - for (var entry in fieldVisitor.methods.entries) { - if (entry.key == "toMap") { - return true; - } - } - - return false; - } - - bool hasFromMapMethod(Element element) { - final hasAnnotation = _coreChecker.hasAnnotationOf(element); - final fromMapFactory = - _coreChecker - .firstAnnotationOfExact(element) - ?.getField('fromMapFactory') - ?.toBoolValue() ?? - false; - if (hasAnnotation && fromMapFactory) { - return true; - } - - final fieldVisitor = ModelVisitor(); - element.visitChildren(fieldVisitor); - for (var entry in fieldVisitor.methods.entries) { - if (entry.key == "fromMap") { - return true; - } - } - - return false; - } - - bool hasNullableFromMapFactory(Element element) { - final hasAnnotation = _coreChecker.hasAnnotationOf(element); - final fromMapFactory = - _coreChecker - .firstAnnotationOfExact(element) - ?.getField('fromMapFactory') - ?.toBoolValue() ?? - false; - final nullableFromMapFactory = - _coreChecker - .firstAnnotationOfExact(element) - ?.getField('nullableFromMapFactory') - ?.toBoolValue() ?? - false; - if (hasAnnotation && fromMapFactory && nullableFromMapFactory) { - return true; - } - - final fieldVisitor = ModelVisitor(); - element.visitChildren(fieldVisitor); - for (var entry in fieldVisitor.methods.entries) { - if (entry.key == "fromMap" && - Util.typeIsNullable(entry.value.returnType)) { - return true; - } - } - - return false; - } - - bool hasFromValueMethod(Element element) { - final hasAnnotation = _coreCheckerEnum.hasAnnotationOf(element); - final fromValueMethod = - _coreCheckerEnum - .firstAnnotationOfExact(element) - ?.getField('fromValueMethod') - ?.toBoolValue() ?? - false; - if (hasAnnotation && fromValueMethod) { - return true; - } - - final fieldVisitor = ModelVisitor(); - element.visitChildren(fieldVisitor); - for (var entry in fieldVisitor.methods.entries) { - if (entry.key == "fromValue") { - return true; - } - } - - return false; - } - - bool hasFromNativeValueMethod(Element element) { - final hasAnnotation = _coreCheckerEnum.hasAnnotationOf(element); - final fromNativeValueMethod = - _coreCheckerEnum - .firstAnnotationOfExact(element) - ?.getField('fromNativeValueMethod') - ?.toBoolValue() ?? - false; - if (hasAnnotation && fromNativeValueMethod) { - return true; - } - - final fieldVisitor = ModelVisitor(); - element.visitChildren(fieldVisitor); - for (var entry in fieldVisitor.methods.entries) { - if (entry.key == "fromNativeValue") { - return true; - } - } - - return false; - } - - bool hasByNameMethod(Element element) { - final hasAnnotation = _coreCheckerEnum.hasAnnotationOf(element); - final byNameMethod = - _coreCheckerEnum - .firstAnnotationOfExact(element) - ?.getField('byNameMethod') - ?.toBoolValue() ?? - false; - if (hasAnnotation && byNameMethod) { - return true; - } - - final fieldVisitor = ModelVisitor(); - element.visitChildren(fieldVisitor); - for (var entry in fieldVisitor.methods.entries) { - if (entry.key == "byName") { - return true; - } - } - - return false; - } - - bool hasToValueMethod(Element element) { - final hasAnnotation = _coreCheckerEnum.hasAnnotationOf(element); - final hasToValueMethod = - _coreCheckerEnum - .firstAnnotationOfExact(element) - ?.getField('toValueMethod') - ?.toBoolValue() ?? - false; - if (hasAnnotation && hasToValueMethod) { - return true; - } - - final fieldVisitor = ModelVisitor(); - element.visitChildren(fieldVisitor); - for (var entry in fieldVisitor.methods.entries) { - if (entry.key == "toValue") { - return true; - } - } - - return false; - } - - bool hasToNativeValueMethod(Element element) { - final hasAnnotation = _coreCheckerEnum.hasAnnotationOf(element); - final hasToNativeValueMethod = - _coreCheckerEnum - .firstAnnotationOfExact(element) - ?.getField('toNativeValueMethod') - ?.toBoolValue() ?? - false; - if (hasAnnotation && hasToNativeValueMethod) { - return true; - } - - final fieldVisitor = ModelVisitor(); - element.visitChildren(fieldVisitor); - for (var entry in fieldVisitor.methods.entries) { - if (entry.key == "toNativeValue") { - return true; - } - } - - return false; - } - - bool hasNameMethod(Element element) { - final hasAnnotation = _coreCheckerEnum.hasAnnotationOf(element); - final hasNameMethod = - _coreCheckerEnum - .firstAnnotationOfExact(element) - ?.getField('nameMethod') - ?.toBoolValue() ?? - false; - if (hasAnnotation && hasNameMethod) { - return true; - } - - final fieldVisitor = ModelVisitor(); - element.visitChildren(fieldVisitor); - for (var entry in fieldVisitor.methods.entries) { - if (entry.key == "name") { - return true; - } - } - - return false; - } -} diff --git a/dev_packages/generators/lib/src/model_visitor.dart b/dev_packages/generators/lib/src/model_visitor.dart deleted file mode 100644 index eb0214909e..0000000000 --- a/dev_packages/generators/lib/src/model_visitor.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:analyzer/dart/element/visitor2.dart'; -import 'package:analyzer/dart/element/element.dart'; - -class ModelVisitor extends SimpleElementVisitor2 { - late ConstructorElement constructor; - final constructorParameters = {}; - final fields = {}; - final methods = {}; - - @override - void visitConstructorElement(ConstructorElement element) { - constructor = element; - for (final param in element.formalParameters) { - constructorParameters.putIfAbsent(param.name ?? '', () => param); - } - } - - @override - void visitFieldElement(FieldElement element) { - fields[element.name ?? ''] = element; - } - - @override - void visitMethodElement(MethodElement element) { - methods[element.name ?? ''] = element; - } -} diff --git a/dev_packages/generators/lib/src/supported_platforms_generator.dart b/dev_packages/generators/lib/src/supported_platforms_generator.dart deleted file mode 100644 index d72ef2fabd..0000000000 --- a/dev_packages/generators/lib/src/supported_platforms_generator.dart +++ /dev/null @@ -1,317 +0,0 @@ -import 'package:analyzer/dart/element/element.dart'; -import 'package:source_gen/source_gen.dart'; -import 'package:analyzer/dart/element/type.dart'; -import 'package:analyzer/dart/constant/value.dart'; -import 'package:build/build.dart'; -import 'package:collection/collection.dart'; -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; - -import 'model_visitor.dart'; -import 'util.dart'; - -const _annotationsPackage = 'flutter_inappwebview_internal_annotations'; - -final _coreCheckerDeprecated = TypeChecker.typeNamedLiterally('Deprecated', inSdk: true); -final _coreCheckerSupportedPlatforms = - TypeChecker.typeNamedLiterally('SupportedPlatforms', inPackage: _annotationsPackage); - -class SupportedPlatformsGenerator - extends GeneratorForAnnotation { - @override - String generateForAnnotatedElement( - Element element, ConstantReader annotation, BuildStep buildStep) { - - final visitor = ModelVisitor(); - // Visits all the children of element in no particular order. - element.visitChildren(visitor); - - final classAnnotation = _coreCheckerSupportedPlatforms.firstAnnotationOf(visitor.constructor.returnType.element)!; - final ignoreClass = classAnnotation.getField('ignore')?.toBoolValue() ?? false; - if (ignoreClass) { - return ''; - } - final ignorePropertyNames = (classAnnotation.getField('ignorePropertyNames')?.toListValue()?.map((e) => RegExp(e.toStringValue()!)) ?? []).toList(); - final ignoreMethodNames = (classAnnotation.getField('ignoreMethodNames')?.toListValue()?.map((e) => RegExp(e.toStringValue()!)) ?? []).toList(); - final ignoreParameterNames = (classAnnotation.getField('ignoreParameterNames')?.toListValue()?.map((e) => RegExp(e.toStringValue()!)) ?? []).toList(); - - final fields = visitor.fields.entries.where((e) => !ignorePropertyNames.any((r) => r.hasMatch(e.key))).toList(); - final methods = visitor.methods.entries.where((e) => !ignoreMethodNames.any((r) => r.hasMatch(e.key))).toList(); - - final isClassSupportedFunctionName = 'isClassSupported'; - final isPropertySupportedFunctionName = 'isPropertySupported'; - final isMethodSupportedFunctionName = 'isMethodSupported'; - - final hasClassSupportedFunction = methods - .firstWhereOrNull((m) => m.key == isClassSupportedFunctionName) != - null; - final hasPropertySupportedFunction = methods.firstWhereOrNull( - (m) => m.key == isPropertySupportedFunctionName) != - null; - final hasMethodSupportedFunction = methods - .firstWhereOrNull((m) => m.key == isMethodSupportedFunctionName) != - null; - - if (!hasClassSupportedFunction && - !hasPropertySupportedFunction && - !hasMethodSupportedFunction) { - return ''; - } - - final fieldEntriesSorted = fields.where((e) { - var hasAnnotation = - _coreCheckerSupportedPlatforms.firstAnnotationOf(e.value) != null; - if (!hasAnnotation && e.value.getter != null) { - hasAnnotation = _coreCheckerSupportedPlatforms - .firstAnnotationOf(e.value.getter!) != null; - } - return hasAnnotation; - }).toList(); - fieldEntriesSorted.sort((a, b) => a.key.compareTo(b.key)); - - final methodEntriesSorted = methods.where((e) { - return _coreCheckerSupportedPlatforms.firstAnnotationOf(e.value) != null; - }).toList(); - methodEntriesSorted.sort((a, b) => a.key.compareTo(b.key)); - - if (!hasClassSupportedFunction && fieldEntriesSorted.isEmpty && methodEntriesSorted.isEmpty) { - return ''; - } - - final classBuffer = StringBuffer(); - - final packageName = element.library?.uri.pathSegments.first ?? 'unknown'; - var className = visitor.constructor.returnType.element.name ?? ''; - if (className.endsWith('_')) { - className = className.substring(0, className.length - 1); - } - - if (hasClassSupportedFunction) { - classBuffer.writeln(""" - extension _${className}ClassSupported on $className {"""); - - final classSupportedDocs = - Util.getSupportedDocs(_coreCheckerSupportedPlatforms, visitor.constructor.returnType.element); - if (classSupportedDocs != null) { - classBuffer.writeln( - '///{@template $packageName.$className.supported_platforms}'); - classBuffer.writeln(classSupportedDocs); - classBuffer.writeln('///'); - classBuffer.writeln('///Use the [$className.$isClassSupportedFunctionName] method to check if this class is supported at runtime.'); - classBuffer.writeln('///{@endtemplate}'); - } - if (visitor.constructor.returnType.element.metadata.hasDeprecated) { - classBuffer.writeln( - "@Deprecated('${_coreCheckerDeprecated.firstAnnotationOfExact(visitor.constructor.returnType.element)?.getField("message")?.toStringValue()}')"); - } - - classBuffer.writeln("""static bool $isClassSupportedFunctionName({TargetPlatform? platform}) {"""); - final classAnnotation = _coreCheckerSupportedPlatforms - .firstAnnotationOfExact(visitor.constructor.returnType.element); - - final platforms = - classAnnotation!.getField('platforms')?.toListValue() ?? []; - if (platforms.isEmpty) { - classBuffer.writeln("return false;"); - } else { - final targetPlatforms = platforms - .map((e) => e.getField("targetPlatformName")!.toStringValue()) - .toList(); - final hasWebSupport = targetPlatforms.contains("web"); - - classBuffer.writeln("return "); - if (hasWebSupport) { - classBuffer.writeln("kIsWeb && platform == null ? true :"); - } - classBuffer.writeln( - "((kIsWeb && platform != null) || !kIsWeb) && [${targetPlatforms.where((e) => e != 'web').map((e) => "TargetPlatform.$e").join(', ')}].contains(platform ?? defaultTargetPlatform)"); - classBuffer.writeln(";"); - } - classBuffer.writeln(""" - } - } - """); - } - - if (hasPropertySupportedFunction && !fieldEntriesSorted.isEmpty) { - final enumClassName = '${className}Property'; - - classBuffer.writeln( - "///List of [${className}]'s properties that can be used to check i they are supported or not by the current platform."); - classBuffer.writeln("enum ${enumClassName} {"); - for (final entry in fieldEntriesSorted) { - final fieldName = entry.key; - final field = entry.value; - - classBuffer.writeln('///Can be used to check if the [$className.$fieldName] property is supported at runtime.'); - classBuffer.writeln('///'); - var fieldSupportedDocs = - Util.getSupportedDocs(_coreCheckerSupportedPlatforms, field); - String? parameterSupportedDocs = null; - if (field.type is FunctionType) { - final fieldFunction = field.type as FunctionType; - final List customIgnoreParameterNames = _coreCheckerSupportedPlatforms - .firstAnnotationOfExact(field) - ?.getField('ignoreParameterNames') - ?.toListValue()?.map((e) => RegExp(e.toStringValue()!)).toList() ?? []; - final Map>? parameterPlatforms = _coreCheckerSupportedPlatforms - .firstAnnotationOfExact(field) - ?.getField('parameterPlatforms') - ?.toMapValue()?.map((key, value) => MapEntry(key!.toStringValue()!, value!.toListValue()!)); - final parameters = fieldFunction.formalParameters.where((e) => ![...ignoreParameterNames, ...customIgnoreParameterNames].any((r) => r.hasMatch(e.name ?? ''))).toList(); - parameterSupportedDocs = Util.getParameterSupportedDocs( - _coreCheckerSupportedPlatforms, parameters, parameterPlatforms); - } - if (fieldSupportedDocs == null && field.getter != null) { - fieldSupportedDocs = Util.getSupportedDocs( - _coreCheckerSupportedPlatforms, field.getter!); - } - if (fieldSupportedDocs != null || parameterSupportedDocs != null) { - classBuffer.writeln( - '///{@template $packageName.$className.$fieldName.supported_platforms}'); - if (fieldSupportedDocs != null) { - classBuffer.writeln(fieldSupportedDocs); - } - if (parameterSupportedDocs != null) { - if (fieldSupportedDocs != null) { - classBuffer.writeln('///'); - } - classBuffer.writeln(parameterSupportedDocs); - } - classBuffer.writeln('///'); - classBuffer.writeln('///Use the [$className.$isPropertySupportedFunctionName] method to check if this property is supported at runtime.'); - classBuffer.writeln('///{@endtemplate}'); - } - if (field.metadata.hasDeprecated || field.getter?.metadata.hasDeprecated == true) { - classBuffer.writeln( - "@Deprecated('${_coreCheckerDeprecated.firstAnnotationOfExact(field.metadata.hasDeprecated ? field : field.getter!)?.getField("message")?.toStringValue()}')"); - } - classBuffer.writeln("$fieldName,"); - } - classBuffer.writeln("}"); - - classBuffer.writeln(""" - extension _${className}PropertySupported on $className { - static bool $isPropertySupportedFunctionName($enumClassName property, {TargetPlatform? platform}) { - switch (property) {"""); - for (final entry in fieldEntriesSorted) { - final fieldName = entry.key; - final field = entry.value; - var fieldAnnotation = - _coreCheckerSupportedPlatforms.firstAnnotationOfExact(field); - if (fieldAnnotation == null && field.getter != null) { - fieldAnnotation = _coreCheckerSupportedPlatforms - .firstAnnotationOfExact(field.getter!); - } - - final platforms = - fieldAnnotation!.getField('platforms')?.toListValue() ?? []; - if (platforms.isEmpty) { - continue; - } - - final targetPlatforms = platforms - .map((e) => e.getField("targetPlatformName")!.toStringValue()) - .toList(); - final hasWebSupport = targetPlatforms.contains("web"); - - classBuffer.writeln("case $enumClassName.$fieldName:"); - classBuffer.writeln("return "); - if (hasWebSupport) { - classBuffer.writeln("kIsWeb && platform == null ? true :"); - } - classBuffer.writeln( - "((kIsWeb && platform != null) || !kIsWeb) && [${targetPlatforms.where((e) => e != 'web').map((e) => "TargetPlatform.$e").join(', ')}].contains(platform ?? defaultTargetPlatform)"); - classBuffer.writeln(";"); - } - classBuffer.writeln(""" - } - } - } - """); - } - - if (hasMethodSupportedFunction && !methodEntriesSorted.isEmpty) { - final enumClassName = '${className}Method'; - - classBuffer.writeln( - "///List of [${className}]'s methods that can be used to check if they are supported or not by the current platform."); - classBuffer.writeln("enum ${enumClassName} {"); - for (final entry in methodEntriesSorted) { - final methodName = entry.key; - final method = entry.value; - - classBuffer.writeln('///Can be used to check if the [$className.$methodName] method is supported at runtime.'); - classBuffer.writeln('///'); - final methodSupportedDocs = - Util.getSupportedDocs(_coreCheckerSupportedPlatforms, method); - final List customIgnoreParameterNames = _coreCheckerSupportedPlatforms - .firstAnnotationOfExact(method) - ?.getField('ignoreParameterNames') - ?.toListValue()?.map((e) => RegExp(e.toStringValue()!)).toList() ?? []; - final parameters = method.formalParameters.where((e) => ![...ignoreParameterNames, ...customIgnoreParameterNames].any((r) => r.hasMatch(e.name ?? ''))).toList(); - final parameterSupportedDocs = Util.getParameterSupportedDocs( - _coreCheckerSupportedPlatforms, parameters); - if (methodSupportedDocs != null || parameterSupportedDocs != null) { - classBuffer.writeln( - '///{@template $packageName.$className.$methodName.supported_platforms}'); - if (methodSupportedDocs != null) { - classBuffer.writeln(methodSupportedDocs); - } - if (parameterSupportedDocs != null) { - if (methodSupportedDocs != null) { - classBuffer.writeln('///'); - } - classBuffer.writeln(parameterSupportedDocs); - } - classBuffer.writeln('///'); - classBuffer.writeln('///Use the [$className.$isMethodSupportedFunctionName] method to check if this method is supported at runtime.'); - classBuffer.writeln('///{@endtemplate}'); - } - if (method.metadata.hasDeprecated) { - classBuffer.writeln( - "@Deprecated('${_coreCheckerDeprecated.firstAnnotationOfExact(method)?.getField("message")?.toStringValue()}')"); - } - classBuffer.writeln("$methodName,"); - } - classBuffer.writeln("}"); - - classBuffer.writeln(""" - extension _${className}MethodSupported on $className { - static bool $isMethodSupportedFunctionName($enumClassName method, {TargetPlatform? platform}) { - switch (method) {"""); - for (final entry in methodEntriesSorted) { - final methodName = entry.key; - final method = entry.value; - final methodAnnotation = - _coreCheckerSupportedPlatforms.firstAnnotationOfExact(method); - - final platforms = - methodAnnotation!.getField('platforms')?.toListValue() ?? []; - if (platforms.isEmpty) { - continue; - } - - final targetPlatforms = platforms - .map((e) => e.getField("targetPlatformName")!.toStringValue()) - .toList(); - final hasWebSupport = targetPlatforms.contains("web"); - - classBuffer.writeln("case $enumClassName.$methodName:"); - classBuffer.writeln("return "); - if (hasWebSupport) { - classBuffer.writeln("kIsWeb && platform == null ? true :"); - } - classBuffer.writeln( - "((kIsWeb && platform != null) || !kIsWeb) && [${targetPlatforms.where((e) => e != 'web').map((e) => "TargetPlatform.$e").join(', ')}].contains(platform ?? defaultTargetPlatform)"); - classBuffer.writeln(";"); - } - classBuffer.writeln(""" - } - } - } - """); - } - - return classBuffer.toString(); - } -} diff --git a/dev_packages/generators/lib/src/util.dart b/dev_packages/generators/lib/src/util.dart deleted file mode 100644 index 8c05093754..0000000000 --- a/dev_packages/generators/lib/src/util.dart +++ /dev/null @@ -1,217 +0,0 @@ -import 'package:analyzer/dart/constant/value.dart'; -import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer/dart/element/nullability_suffix.dart'; -import 'package:analyzer/dart/element/type.dart'; -import 'package:collection/collection.dart'; -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; -import 'package:source_gen/source_gen.dart'; - -const _annotationsPackage = 'flutter_inappwebview_internal_annotations'; - -final _coreCheckerObjectMethod = - TypeChecker.typeNamedLiterally('ExchangeableObjectMethod', inPackage: _annotationsPackage); - -abstract class Util { - static bool typeIsNullable(DartType type) { - return type.nullabilitySuffix != NullabilitySuffix.none || - type.toString() == 'dynamic'; - } - - static bool methodHasIgnore(MethodElement method) { - return _coreCheckerObjectMethod - .firstAnnotationOf(method) - ?.getField("ignore") - ?.toBoolValue() == - true; - } - - static ClassElement? getClassElement(Element element) { - if (element is ClassElement) { - return element; - } - if (element.enclosingElement != null) { - return getClassElement(element.enclosingElement!); - } - return null; - } - - static String? getSupportedDocs(TypeChecker checker, Element element) { - final platformSupportedList = []; - final platforms = checker - .firstAnnotationOfExact(element) - ?.getField('platforms') - ?.toListValue() ?? - []; - - final classElement = getClassElement(element); - List classElementPlatforms = []; - if (classElement != null) { - classElementPlatforms = checker - .firstAnnotationOfExact(classElement) - ?.getField('platforms') - ?.toListValue() ?? - []; - } - for (var platform in platforms) { - final classElementPlatform = classElementPlatforms - .firstWhereOrNull((p) => p.type == platform.type); - final classElementPlatformName = - classElementPlatform?.getField("name")!.toStringValue()!; - var platformName = platform.getField("name")!.toStringValue()!; - if (classElementPlatformName != null && - kPlatformNameValues.contains(platformName) && - !kPlatformNameValues.contains(classElementPlatformName)) { - platformName = classElementPlatformName; - } - final apiName = platform.getField("apiName")?.toStringValue(); - final apiUrl = platform.getField("apiUrl")?.toStringValue(); - final available = platform.getField("available")?.toStringValue(); - final requiresSameOrigin = - platform.getField("requiresSameOrigin")?.toBoolValue() ?? false; - var api = available != null ? "$available+ " : ""; - if (requiresSameOrigin) { - api += "but requires same origin"; - if (apiName != null || apiUrl != null) { - api += " "; - } - } - if (apiName != null && apiUrl != null) { - api += "([Official API - $apiName]($apiUrl))"; - } else if (apiName != null) { - api += "(Official API - $apiName)"; - } else if (apiUrl != null) { - api += "([Official API]($apiUrl))"; - } - - var platformNote = ""; - final note = platform.getField("note")?.toStringValue(); - if (note != null) { - final noteLines = note.split("\n"); - platformNote += noteLines[0].trim(); - for (int i = 1; i < noteLines.length; i++) { - platformNote += " ${noteLines[i].trim()}"; - } - } - - platformSupportedList.add( - "///- ${(platformName + ' ' + api).trim()}${platformNote.isNotEmpty ? ":\n/// - " + platformNote : ""}"); - } - if (platformSupportedList.isNotEmpty) { - return """/// - ///**Officially Supported Platforms/Implementations**: - ${platformSupportedList.join("\n")}"""; - } - return null; - } - - static String? getParameterSupportedDocs( - TypeChecker checker, List parameters, - [Map>? workaroundPlatforms]) { - final nonDeprecatedParameters = - parameters.where((p) => !p.metadata.hasDeprecated).toList(); - if (nonDeprecatedParameters.isEmpty) { - return null; - } - - final classElement = getClassElement(nonDeprecatedParameters.first); - List classElementPlatforms = []; - if (classElement != null) { - classElementPlatforms = checker - .firstAnnotationOfExact(classElement) - ?.getField('platforms') - ?.toListValue() ?? - []; - } - - var docs = - "///**Parameters - Officially Supported Platforms/Implementations**:"; - for (final parameter in nonDeprecatedParameters) { - var platforms = checker - .firstAnnotationOfExact(parameter) - ?.getField('platforms') - ?.toListValue() ?? - (workaroundPlatforms?[parameter.name] != null - ? workaroundPlatforms![parameter.name]! - : []); - if (platforms.isEmpty) { - docs += "\n///- [${parameter.name}]: all platforms"; - } else { - docs += "\n///- [${parameter.name}]: "; - - for (var platform in platforms) { - final classElementPlatform = classElementPlatforms - .firstWhereOrNull((p) => p.type == platform.type); - final classElementPlatformName = - classElementPlatform?.getField("name")!.toStringValue()!; - var platformName = platform.getField("name")!.toStringValue(); - if (classElementPlatformName != null && - kPlatformNameValues.contains(platformName) && - !kPlatformNameValues.contains(classElementPlatformName)) { - platformName = classElementPlatformName; - } - final apiName = platform.getField("apiName")?.toStringValue(); - final apiUrl = platform.getField("apiUrl")?.toStringValue(); - final available = platform.getField("available")?.toStringValue(); - final requiresSameOrigin = - platform.getField("requiresSameOrigin")?.toBoolValue() ?? false; - var api = available != null ? "$available+ " : ""; - if (requiresSameOrigin) { - api += "but requires same origin"; - if (apiName != null || apiUrl != null) { - api += " "; - } - } - if (apiName != null && apiUrl != null) { - api += "([Official API - $apiName]($apiUrl))"; - } else if (apiName != null) { - api += "(Official API - $apiName)"; - } else if (apiUrl != null) { - api += "([Official API]($apiUrl))"; - } - docs += "\n/// - $platformName $api"; - - final note = platform.getField("note")?.toStringValue(); - if (note != null) { - docs += ": "; - final noteLines = note.split("\n"); - docs += noteLines[0].trim(); - for (int i = 1; i < noteLines.length; i++) { - docs += " ${noteLines[i].trim()}"; - } - } - } - } - } - return docs; - } - - static Iterable getGenericTypes(DartType type) { - return type is ParameterizedType ? type.typeArguments : const []; - } - - static bool canHaveGenerics(DartType type) { - final element = type.element; - if (element is ClassElement) { - return element.typeParameters.isNotEmpty; - } - return false; - } - - static bool isDartCoreType(DartType type) { - return type.isDartCoreBool || - type.isDartCoreDouble || - type.isDartCoreEnum || - type.isDartCoreFunction || - type.isDartCoreInt || - type.isDartCoreIterable || - type.isDartCoreList || - type.isDartCoreMap || - type.isDartCoreNull || - type.isDartCoreNum || - type.isDartCoreObject || - type.isDartCoreSet || - type.isDartCoreString || - type.isDartCoreSymbol || - type is DynamicType; - } -} diff --git a/dev_packages/generators/pubspec.yaml b/dev_packages/generators/pubspec.yaml deleted file mode 100755 index 10e2916391..0000000000 --- a/dev_packages/generators/pubspec.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: generators -version: 1.0.0 - -publish_to: none - -environment: - sdk: ^3.8.0 - flutter: ">=3.32.0" - -dependencies: - flutter: - sdk: flutter - build: ^4.0.0 - source_gen: ^4.0.0 - analyzer: ^9.0.0 - collection: any - flutter_inappwebview_internal_annotations: ^1.3.0 - # path: ../flutter_inappwebview_internal_annotations - -dev_dependencies: - build_runner: ^2.4.12 - build_test: ^3.0.0 - test: ^1.25.8 \ No newline at end of file diff --git a/flutter_inappwebview/.fvmrc b/flutter_inappwebview/.fvmrc deleted file mode 100644 index f620326375..0000000000 --- a/flutter_inappwebview/.fvmrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "flutter": "3.38.5" -} \ No newline at end of file diff --git a/flutter_inappwebview/.gitignore b/flutter_inappwebview/.gitignore deleted file mode 100644 index 8b0c0a4a99..0000000000 --- a/flutter_inappwebview/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock -**/doc/api/ -.dart_tool/ -.packages -build/ - -# FVM Version Cache -.fvm/ \ No newline at end of file diff --git a/flutter_inappwebview/.metadata b/flutter_inappwebview/.metadata deleted file mode 100644 index f4bdae94a4..0000000000 --- a/flutter_inappwebview/.metadata +++ /dev/null @@ -1,39 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e" - channel: "stable" - -project_type: plugin - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - - platform: android - create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - - platform: ios - create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - - platform: macos - create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - - platform: web - create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/flutter_inappwebview/.vscode/settings.json b/flutter_inappwebview/.vscode/settings.json deleted file mode 100644 index 0f7b5001fd..0000000000 --- a/flutter_inappwebview/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "dart.flutterSdkPath": ".fvm/versions/3.38.5" -} \ No newline at end of file diff --git a/flutter_inappwebview/CHANGELOG.md b/flutter_inappwebview/CHANGELOG.md deleted file mode 100755 index abfd2fd1ec..0000000000 --- a/flutter_inappwebview/CHANGELOG.md +++ /dev/null @@ -1,1488 +0,0 @@ -## 6.2.0-beta.3 - -- Added Linux support -- Updated dependencies to the latest versions for all platform implementations: - - `flutter_inappwebview_platform_interface`: `^1.4.0-beta.2` -> `^1.4.0-beta.3` - - `flutter_inappwebview_android`: `^1.2.0-beta.2` -> `^1.2.0-beta.3` - - `flutter_inappwebview_ios`: `^1.2.0-beta.2` -> `^1.2.0-beta.3` - - `flutter_inappwebview_macos`: `^1.2.0-beta.2` -> `^1.2.0-beta.3` - - `flutter_inappwebview_web`: `^1.2.0-beta.2` -> `^1.2.0-beta.3` - - `flutter_inappwebview_windows`: `^0.7.0-beta.2` -> `^0.7.0-beta.3` - - `flutter_inappwebview_linux`: `^0.1.0-beta.1` -- Added `InAppWebViewController.getFavicon` wrapper with `faviconImageFormat` support. -- Fixed "When useShouldInterceptAjaxRequest is true, some ajax requests doesn't work" [#2197](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2197) -- Mapped `isClassSupported`, `isPropertySupported`, `isMethodSupported` platform interface static methods to the corresponding plugin classes such as `InAppWebViewController`, `InAppWebView`, `InAppBrowser`, etc., in order to check if a class, property, or method is supported by the platform at runtime -- Updated code generator -- Minimum Dart SDK `^3.8.0` -- Minimum Flutter SDK `>=3.32.0` - -#### Platform Interface -- Updated `flutter_inappwebview_internal_annotations` dependency from `^1.2.0` to `^1.3.0` -- Added `isClassSupported`, `isPropertySupported`, `isMethodSupported` static methods for all main classes, such as `PlatformInAppWebViewController`, `InAppWebViewSettings`, `PlatformInAppBrowser`, etc., in order to check if a class, property, or method is supported by the platform at runtime -- Added `isSupported` method to all custom enum classes -- Added `saveState`, `restoreState`, `requestEnterFullscreen`, `requestExitFullscreen`, `setVisible`, `setTargetRefreshRate`, `getTargetRefreshRate`, `requestPointerLock`, `requestPointerUnlock`, `getScreenScale`, `setScreenScale`, `isVisible`, `getFrameId`, `getFavicon`, `showSaveAsUI`, `getMemoryUsageTargetLevel`, `setMemoryUsageTargetLevel` methods to `PlatformInAppWebViewController` class -- Added `useOnAjaxReadyStateChange`, `useOnAjaxProgress`, `useOnShowFileChooser`, `corsAllowlist`, `itpEnabled`, `darkMode`, `disableAnimations`, `fontAntialias`, `fontHintingStyle`, `fontSubpixelLayout`, `fontDPI`, `cursorBlinkTime`, `doubleClickDistance`, `doubleClickTime`, `dragThreshold`, `keyRepeatDelay`, `keyRepeatInterval`, `disableWebSecurity`, `enableWebRTC`, `webRTCUdpPortsRange`, `javaScriptCanAccessClipboard`, `allowModalDialogs`, `enableMedia`, `enableEncryptedMedia`, `enableMediaCapabilities`, `enableMockCaptureDevices`, `mediaContentTypesRequiringHardwareSupport`, `enableJavaScriptMarkup`, `enable2DCanvasAcceleration`, `allowTopNavigationToDataUrls` properties to `InAppWebViewSettings` -- Added `onShowFileChooser`, `onContentLoading`, `onDOMContentLoaded`, `onLaunchingExternalUriScheme`, `onFaviconChanged`, `onNotificationReceived`, `onSaveAsUIShowing`, `onSaveFileSecurityCheckStarting`, `onScreenCaptureStarting` WebView events -- Added `PlatformWebNotificationController` class -- Update code documentation -- Deprecated `onReceivedIcon` in favor of `onFaviconChanged` - -#### Android Platform -- Updated native dependencies: - - implementation from `'androidx.webkit:webkit:1.12.0'` to `'androidx.webkit:webkit:1.14.0'` - - implementation from `'androidx.browser:browser:1.8.0'` to `'androidx.browser:browser:1.9.0'` - - implementation from `'androidx.appcompat:appcompat:1.6.1'` to `'androidx.appcompat:appcompat:1.7.1'` - - implementation from `'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'` to `'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0'` -- Updated android native `compileOptions` to `JavaVersion.VERSION_17` -- Implemented `saveState`, `restoreState` InAppWebViewController methods -- Implemented `onShowFileChooser` WebView event -- Updated InAppBrowser toolbar top -- Merged "Android: implemented PlatformPrintJobController.onComplete" [#2216](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2216) (thanks to [Doflatango](https://github.com/Doflatango)) -- Fixed "When useShouldInterceptAjaxRequest is true, some ajax requests doesn't work" [#2197](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2197) -- Merged "Fixed recursive calling toMap in AndroidInternalStoragePathHandler" [#2452](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2452) (thanks to [roberthofstra](https://github.com/roberthofstra)) -- Fixed recursive `toMap` call for `AndroidInternalStoragePathHandler` [#2451](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2451) -- Fixed "Error when updating webview settings Android in v6.2.0-beta.2" [#2449](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2449) -- Fixed "[Android] Upgrade to AGP 9" [#2765](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2765) -- Fixed "update android apg version to 8.9.1 or higer" [#2761](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2761) -- Fixed "InAppWebViewController.goTo" implementation -- Merged "fix #2484, Remove not-empty assert for Cookie.value" [#2486](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2486) (thanks to [laishere](https://github.com/laishere)) - -#### macOS and iOS Platforms -- Implemented `saveState`, `restoreState` InAppWebViewController methods -- Implemented `PlatformProxyController` class -- Add Swift Package Manager support [#2409](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2409) -- Fixed "[iOS] Webview opened with windowId does not receive javascript handler callback." [#2393](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2393) -- Fixed internal javascript callback handlers when the WebView has windowId not null -- Fixed crash of unhandled `onPrintRequest` WebView event -- Fixed "When useShouldInterceptAjaxRequest is true, some ajax requests doesn't work" [#2197](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2197) -- Fixed "iOS App rejected by apple for violating Guideline 2.5.1 - Performance - Software Requirements | Flutter 3.35.x seems to use non-public or deprecated APIs" [#2754](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2754) -- Fixed "InAppWebViewController.goTo" implementation -- Merged "Add proxy support for iOS" [#2362](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2362) (thanks to [yerkejs](https://github.com/yerkejs)) -- Merged "🐛 fix MacOS: when using the `WebMessageListener` `onPostMessage` method, the message parameter is unexpectedly empty" [#2481](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2481) (thanks to [imoyakin](https://github.com/imoyakin)) -- Merged "fix #2484, Remove not-empty assert for Cookie.value" [#2486](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2486) (thanks to [laishere](https://github.com/laishere)) -- Merged "Fix gesture recognition delay prevention for latest Flutter versions" [#2538](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2538) (thanks to [muccy-timeware](https://github.com/muccy-timeware)) - -### Windows -- Updated Microsoft.Web.WebView2 SDK version from `1.0.2849.39` to `1.0.3650.58` -- Implemented `getFrameId`, `getFavicon`, `showSaveAsUI`, `getMemoryUsageTargetLevel`, `setMemoryUsageTargetLevel` InAppWebViewController method -- Added support for `onEnterFullscreen`, `onExitFullscreen`, `onContentLoading`, `onDOMContentLoaded`, `onLaunchingExternalUriScheme`, `onFaviconChanged`, `onNotificationReceived`, `onSaveAsUIShowing`, `onSaveFileSecurityCheckStarting`, `onScreenCaptureStarting` WebView events. -- Added native FindInteractionController implementation using WebView2 `ICoreWebView2Find`. -- Implemented `setFindOptions` FindInteractionController method -- Implemented `PlatformWebNotificationController` feature -- Merged "windows: fix WebViewEnvironment dispose crash" [#2433](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2433) (thanks to [GooRingX](https://github.com/GooRingX)) -- Merged "fix #2484, Remove not-empty assert for Cookie.value" [#2486](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2486) (thanks to [laishere](https://github.com/laishere)) -- Merged "Prevent Unpredictable Close On Windows" [#2543](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2543) (thanks to [momadvisor](https://github.com/momadvisor)) - -### Web -- Updated `onCreateWindow` WebView event -- Implemented `onCloseWindow`, `onCallJsHandler` WebView events -- Implemented `addJavaScriptHandler`, `removeJavaScriptHandler`, `hasJavaScriptHandler`, `addUserScript`, `addUserScripts`, `removeUserScript`, `removeUserScriptsByGroupName`, `removeUserScripts`, `hasUserScript` InAppWebViewController methods -- Implemented `setJavaScriptBridgeName`, `getJavaScriptBridgeName`, `getDefaultUserAgent` InAppWebViewController static methods -- Implemented `javaScriptHandlersOriginAllowList`, `javaScriptBridgeEnabled`, `javaScriptBridgeOriginAllowList`, `hasJavaScriptHandler`, `addUserScript`, `addUserScripts`, `removeUserScript` of `InAppWebViewSettings` -- Merged "fix #2484, Remove not-empty assert for Cookie.value" [#2486](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2486) (thanks to [laishere](https://github.com/laishere)) - -### Linux -- Initial implementation - -## 6.2.0-beta.2 - -- Updated dependencies to the latest versions for all platform implementations: - - `flutter_inappwebview_platform_interface`: `^1.4.0-beta.1` -> `^1.4.0-beta.2` - - `flutter_inappwebview_android`: `^1.2.0-beta.1` -> `^1.2.0-beta.2` - - `flutter_inappwebview_ios`: `^1.2.0-beta.1` -> `^1.2.0-beta.2` - - `flutter_inappwebview_macos`: `^1.2.0-beta.1` -> `^1.2.0-beta.2` - - `flutter_inappwebview_web`: `^1.2.0-beta.1` -> `^1.2.0-beta.2` - - `flutter_inappwebview_windows`: `^0.7.0-beta.1` -> `^0.7.0-beta.2` -- Fixed specific URLAuthenticationChallenge type for `onReceivedHttpAuthRequest`, `onReceivedServerTrustAuthRequest`, `onReceivedClientCertRequest` events of HeadlessInAppWebView -- Fixed missing return type for `InAppWebViewController.getJavaScriptBridgeName` static method - -#### Platform Interface -- Updated `flutter_inappwebview_internal_annotations` dependency from `^1.1.1` to `^1.2.0` -- Updated `fromMap` static method and `toMap` method implementations -- Updated all WebView events with return type `Future` to type `FutureOr` in order to not force the usage of `async` keyword -- Added `byName`, `name`, `asNameMap` custom enum classes methods -- Added `statusBarEnabled`, `browserAcceleratorKeysEnabled`, `generalAutofillEnabled`, `passwordAutosaveEnabled`, `isPinchZoomEnabled`, `hiddenPdfToolbarItems`, `reputationCheckingRequired`, `nonClientRegionSupportEnabled`, `alpha`, `isUserInteractionEnabled` properties to `InAppWebViewSettings` -- Added `isInterfaceSupported`, `getProcessInfos`, `getFailureReportFolderPath` methods to `PlatformWebViewEnvironment` class -- Added `isInterfaceSupported`, `setInputMethodEnabled`, `hideInputMethod`, `showInputMethod` methods to `PlatformInAppWebViewController` class -- Added `exclusiveUserDataFolderAccess`, `isCustomCrashReportingEnabled`, `enableTrackingPrevention`, `areBrowserExtensionsEnabled`, `channelSearchKind`, `releaseChannels`, `scrollbarStyle` properties to `WebViewEnvironmentSettings` -- Added `onDownloadStarting` WebView event and deprecated `onDownloadStartRequest` event -- Added `onNewBrowserVersionAvailable`, `onBrowserProcessExited`, `onProcessInfosChanged` events to `PlatformWebViewEnvironment` class -- Fixed missing PrintJobOrientation android values - -#### Android Platform -- Implemented `hideInputMethod`, `showInputMethod` InAppWebViewController methods -- Implemented `isUserInteractionEnabled`, `alpha` properties of `InAppWebViewSettings` -- Merged "Show / Hide / Disable / Enable soft Keyboard Input (Android & iOS)" [#2408](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2408) (thanks to [Mecharyry](https://github.com/Mecharyry)) -- Fixed "[Android] PrintJobOrientation _TypeError (type 'Null' is not a subtype of type 'int')" [#2413](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2413) -- Fixed "Accessibility Android" [#1694](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1694) -- Fixed "Automatic font scale according to accessibility option 'font size' of device does not work on Android" [#540](https://github.com/pichillilorenzo/flutter_inappwebview/issues/540) -- Fixed "callHandler method is not injected into InAppBrowser" [#1973](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1973) - -#### iOS Platform -- Implemented `setInputMethodEnabled`, `hideInputMethod` InAppWebViewController methods -- Implemented `isUserInteractionEnabled`, `alpha` properties of `InAppWebViewSettings` -- Merged "Show / Hide / Disable / Enable soft Keyboard Input (Android & iOS)" [#2408](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2408) (thanks to [Mecharyry](https://github.com/Mecharyry)) -- Fixed "In iOS version 17.2, when moving the input focus in a WebView, an unknown area appears at the top of the screen." [#1947](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1947) - -#### macOS Platform -- Implemented `alpha` property of `InAppWebViewSettings` - -#### Windows Platform -- Updated Microsoft.Web.WebView2 SDK version from `1.0.2792.45` to `1.0.2849.39` -- Implemented `disableDefaultErrorPage`, `statusBarEnabled`, `browserAcceleratorKeysEnabled`, `generalAutofillEnabled`, `passwordAutosaveEnabled`, `isPinchZoomEnabled`, `allowsBackForwardNavigationGestures`, `hiddenPdfToolbarItems`, `reputationCheckingRequired`, `nonClientRegionSupportEnabled` properties of `InAppWebViewSettings` -- Implemented `isInterfaceSupported`, `getProcessInfos`, `getFailureReportFolderPath` WebViewEnvironment methods -- Implemented `isInterfaceSupported`, `getZoomScale` InAppWebViewController method -- Implemented `onDownloadStarting`, `onAcceleratorKeyPressed` WebView event -- Implemented `exclusiveUserDataFolderAccess`, `isCustomCrashReportingEnabled`, `enableTrackingPrevention`, `areBrowserExtensionsEnabled`, `channelSearchKind`, `releaseChannels`, `scrollbarStyle` properties of `WebViewEnvironmentSettings` -- Implemented `onNewBrowserVersionAvailable`, `onBrowserProcessExited`, `onProcessInfosChanged` WebViewEnvironment events -- Send mouse leave region event to native view -- Fixed wrong channel name when creating a `WebViewEnvironment` instance -- Fixed "[Windows] Has an overlay on the desktop when the application is minimized" [#2402](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2402) -- Fixed "[Windows] missing implementation of onPermissionRequest event will cause crash when requested by the webpage" [#2404](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2404) -- Fixed "Windows: getCookies return empty list" [#2314](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2314) - -## 6.2.0-beta.1 - -- Updated dependencies to the latest versions for all platform implementations: - - `flutter_inappwebview_platform_interface`: `^1.3.0` -> `^1.4.0-beta.1` - - `flutter_inappwebview_android`: `^1.1.3` -> `^1.2.0-beta.1` - - `flutter_inappwebview_ios`: `^1.1.2` -> `^1.2.0-beta.1` - - `flutter_inappwebview_macos`: `^1.1.2` -> `^1.2.0-beta.1` - - `flutter_inappwebview_web`: `^1.1.2` -> `^1.2.0-beta.1` - - `flutter_inappwebview_windows`: `^0.6.0` -> `^0.7.0-beta.1` -- Fixed specific URLAuthenticationChallenge type for `onReceivedHttpAuthRequest`, `onReceivedServerTrustAuthRequest`, `onReceivedClientCertRequest` events - -Implemented security features to better manage access to the native javascript bridge. - -#### Platform Interface -- Updated static `fromMap` implementation for some classes -- Updated `kJavaScriptHandlerForbiddenNames` list -- Added `PlatformInAppLocalhostServer.onData` parameter to set a custom on data server callback -- Added `javaScriptBridgeEnabled`, `javaScriptBridgeOriginAllowList`, `javaScriptBridgeForMainFrameOnly`, `pluginScriptsOriginAllowList`, `pluginScriptsForMainFrameOnly`, `javaScriptHandlersOriginAllowList`, `javaScriptHandlersForMainFrameOnly`, `scrollMultiplier` InAppWebViewSettings parameters -- Added `setJavaScriptBridgeName`, `getJavaScriptBridgeName` static WebView controller methods -- Added `requestFocus` WebView method -- Added `onProcessFailed` WebView event -- Added `regexToAllowSyncUrlLoading` Android-specific property to `InAppWebViewSettings` -- Added `JavaScriptHandlerFunctionData` type -- Deprecated `JavaScriptHandlerCallback` type in favor of `JavaScriptHandlerFunction` type -- Deprecated `InAppWebViewSettings.forceDark` and `InAppWebViewSettings.forceDarkStrategy` Android-only properties in favor of `InAppWebViewSettings.algorithmicDarkeningAllowed` -- Fixed X509Certificate PEM base64 decoding - -#### Android Platform -- Added `InAppWebViewController.enableSlowWholeDocumentDraw` static method -- Added `CookieManager.flush` method -- Added support for `UserScript.forMainFrameOnly` parameter -- Implemented `requestFocus` WebView method -- Updated UserScript at document end implementation -- Updated `InAppWebViewController.takeScreenshot` implementation to support screenshot out of visible viewport when `InAppWebViewController.enableSlowWholeDocumentDraw` is called -- Fixed "After dispose a InAppWebViewKeepAlive using InAppWebViewController.disposeKeepAlive. NullPointerException is thrown when main activity enter destroyed state." [#2025](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2025) -- Fixed crash when trying to open InAppBrowser with R.menu.menu_main on release mode -- Fixed "android.webkit.WebSettingsWrapper cannot be cast to com.android.webview.chromium.ContentSettingsAdapter" [#2397](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2397) -- Merged "Prevent blank InAppBrowser Activity from being restored" [#1984](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1984) (thanks to [ShuheiSuzuki-07](https://github.com/ShuheiSuzuki-07)) -- Merged "Update Android Cookie Expiration date format to 24-hour format (HH)" [#2389](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2389) (thanks to [takuyaaaaaaahaaaaaa](https://github.com/takuyaaaaaaahaaaaaa)) -- Merged "[Android] allow sync navigation requests using a regular expression" [#2008](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2008) (thanks to [lyb5834](https://github.com/lyb5834)) - -#### macOS and iOS Platforms -- Implemented `requestFocus` WebView method -- Updated ConsoleLogJS internal PluginScript to main-frame only as using it on non-main frames could cause issues such as [#1738](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738) -- Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error -- Added support for `UserScript.allowedOriginRules` parameter -- Merged "change priority of DispatchQueue" [#2322](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2322) (thanks to [nnnlog](https://github.com/nnnlog)) -- ios: Fixed `show`, `hide` methods and `hidden` setting for `InAppBrowser` -- macOS: Implemented also `clearFocus` WebView method -- macOS: Implemented workaround for "[macOS] Copy Shortcut does not work if TextField outside of WebView has focus" [#2380](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2380) - -#### Windows Platform -- Updated `scrollMultiplier` default value from 6 to 1 -- Added support for `UserScript.allowedOriginRules` and `UserScript.forMainFrameOnly` parameters -- Implemented `onReceivedHttpAuthRequest`, `onReceivedClientCertRequest`, `onReceivedServerTrustAuthRequest`, `onRenderProcessGone`, `onRenderProcessUnresponsive`, `onWebContentProcessDidTerminate`, `onProcessFailed` WebView events -- Implemented `clearSslPreferences` WebView method -- Fixed `get_optional_fl_map_value` implementation in `utils/flutter.h` -- Fixed "Error in transparentBackground handling in Windows" [#2391](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2391) - -#### Web Platform -- Merged "[web] support iframe role and aria-hidden attributes" [2293](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2293) (thanks to [p-mazhnik](https://github.com/p-mazhnik)) -- Fixed 'Type 'int' is not a subtype of type 'JSValue' in type cast' when compiling/running using WASM - -## 6.1.5 - -- Updated dependencies to the latest versions for all platform implementations: - - `flutter_inappwebview_windows`: `^0.5.0` -> `^0.6.0` - -#### Windows Platform -- Updated code to support multiple flutter windows -- Fixed `InAppWebViewController.callAsyncJavaScript` not working with JSON objects -- Fixed `onLoadResourceWithCustomScheme` WebView event called every time - -## 6.1.4 - -- Updated dependencies to the latest versions for all platform implementations: - - `flutter_inappwebview_platform_interface`: `^1.2.0` -> `^1.3.0` - - `flutter_inappwebview_android`: `^1.1.1` -> `^1.1.3` - - `flutter_inappwebview_ios`: `^1.1.1` -> `^1.1.2` - - `flutter_inappwebview_macos`: `^1.1.1` -> `^1.1.2` - - `flutter_inappwebview_web`: `^1.1.1` -> `^1.1.2` - - `flutter_inappwebview_windows`: `^0.4.0` -> `^0.5.0` - -#### Android Platform -- Removed webview/plugin_scripts_js/ConsoleLogJS.java file, use native WebChromeClient.onConsoleMessage instead - -#### Windows Platform -- Implemented `shouldInterceptRequest`, `onLoadResourceWithCustomScheme` WebView events - -## 6.1.3 - -- Updated dependencies to the latest versions for all platform implementations: - - `flutter_inappwebview_platform_interface`: `^1.1.0` -> `^1.2.0` - - `flutter_inappwebview_android`: `^1.1.0+4` -> `^1.1.1` - - `flutter_inappwebview_ios`: `^1.1.0+3` -> `^1.1.1` - - `flutter_inappwebview_macos`: `^1.1.0+3` -> `^1.1.1` - - `flutter_inappwebview_web`: `^1.1.0+2` -> `^1.1.1` - - `flutter_inappwebview_windows`: `^0.3.0` -> `^0.4.0` - -#### Windows Platform - - Updated `shouldOverrideUrlLoading` implementation using the Chrome DevTools Protocol API Fetch.requestPaused event - -## 6.1.2 - -- Updated minimum platform implementation versions - -#### Windows Platform - -- Implemented `pause`, `resume`, `getCertificate` methods for `InAppWebViewController` -- Implemented `onPermissionRequest` WebView event -- Fixed `InAppWebViewController.evaluateJavascript` not working with JSON objects -- Fixed `InAppWebViewManager::METHOD_CHANNEL_NAME` c++ value -- Fixed `InAppWebViewController.takeScreenshot` to behave consistently with the other platforms - -## 6.1.1 - -- Updated README -- Updated pubspec.yaml -- Updated minimum platform implementation versions - -## 6.1.0+1 - -- Updated README - -## 6.1.0 - -- Added initial Windows support -- Added `InAppWebView` widget MacOS support -- Added privacy manifest for MacOS -- Migrated web support to `package:web`. -- Updated minimum supported SDK version to Flutter 3.24/Dart 3.5. -- Updated androidx.webkit:webkit:1.8.0 to androidx.webkit:webkit:1.12.0 -- Updated androidx.browser:browser:1.6.0 to androidx.browser:browser:1.8.0 -- Fixed "[MACOS] launching InAppBrowser with 'hidden: true' calls onExit immediately" [#1939](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1939) -- Fixed XCode 16 build -- Removed unsupported WebViewFeature.SUPPRESS_ERROR_PAGE -- Merged "Add privacy manifest for iOS" [#2029](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2029) (thanks to [ueman](https://github.com/ueman)) -- Merged "Remove references to deprecated v1 Android embedding" [#2176](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2176) (thanks to [gmackall](https://github.com/gmackall)) - -## 6.0.0 - -- Updated minimum platform interface and implementation versions -- Merged "Added == operator and hashCode to WebUri" [#1941](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1941) (thanks to [daisukeueta](https://github.com/daisukeueta)) - -## 6.0.0-rc.3 - -- Updated minimum platform interface and implementation versions -- Fix typos and other code improvements (thanks to [michalsrutek](https://github.com/michalsrutek)) -- Fixed "runtime issue of SecTrustCopyExceptions 'This method should not be called on the main thread as it may lead to UI unresponsiveness.' when using onReceivedServerTrustAuthRequest" [#1924](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1924) -- Merged "💥 Fix iPad crash due to missing sourceView" [#1933](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1933) (thanks to [michalsrutek](https://github.com/michalsrutek)) -- Merged "💥 Fix crash - remove force unwrapping from dispose method" [#1932](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1932) (thanks to [michalsrutek](https://github.com/michalsrutek)) - -## 6.0.0-rc.2 - -- Updated minimum platform interface and implementation versions -- Added `CustomPathHandler` class to be able to implement Android custom path handlers for `WebViewAssetLoader` - -## 6.0.0-rc.1 - -- Updated minimum platform interface and implementation versions -- Added `InAppBrowser.onMainWindowWillClose` event -- Added `WindowType.WINDOW` for `InAppBrowserSettings.windowType` -- Fixed "Cloudflare Turnstile failure" [#1738](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738) -- Fixed `InAppWebViewController.callAsyncJavaScript` Android-issue when the last line of the `functionBody` parameter includes a code comment - -### BREAKING CHANGES - -- Default value of `InAppBrowserSettings.windowType` is `WindowType.WINDOW` - -## 6.0.0-beta.32 - -- Updated minimum platform interface and implementation versions -- Added `InAppWebViewSettings.interceptOnlyAsyncAjaxRequests` [#1905](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1905) -- Added `InAppWebViewController.clearFormData` Android-specific method -- Added `InAppWebViewController.clearAllCache` static method -- Added `CookieManager.removeSessionCookies` Android-specific method -- Deprecated `InAppWebViewController.clearCache` and `InAppWebViewSettings.clearCache`. Use `InAppWebViewController.clearAllCache` static method instead -- Deprecated `InAppWebViewSettings.clearSessionCache`. Use `CookieManager.removeSessionCookies` method instead -- Updated `useShouldInterceptAjaxRequest` automatic infer logic -- Updated `CookieManager` methods return value -- Fixed "iOS crash at public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)" [#1912](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1912) -- Fixed "iOS Fatal Crash" [#1894](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1894) -- Fixed "getFavicons: _TypeError: type '_Map' is not a subtype of type 'Iterable'" [#1897](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1897) -- Fixed error in InterceptAjaxRequestJS 'Failed to set responseType property' -- Fixed shouldInterceptAjaxRequest javascript code when overriding XMLHttpRequest.open method parameters -- Fixed "onClosed not considering back navigation or up button / close button in ChromeSafariBrowser when using noHistory: true" [#1882](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1882) -- Merged "Fixed error in InterceptAjaxRequestJS 'Failed to set responseType property'" [#1904](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1904) (thanks to [EArminjon](https://github.com/EArminjon)) - -### BREAKING CHANGES - -- Due to Flutter platform channels async nature, using `useShouldInterceptAjaxRequest: true` would break sync ajax requests, so that the `XMLHttpRequest.send()` will not wait for the response. To fix this issue, the default value of `InAppWebViewSettings.interceptOnlyAsyncAjaxRequests` is `true`. To intercept also sync ajax requests, this value should be `false`. - -## 6.0.0-beta.31 - -- Updated minimum platform interface and implementation versions -- Fixed events not called on `InAppBrowser` and `ChromeSafariBrowser` opening same instance multiple times - -## 6.0.0-beta.30 - -- Updated minimum platform interface and implementation versions -- Fixed "Crash when starting ChromeSafariBrowser on Android java.lang.NoSuchMethodError: No virtual method isEngagementSignalsApiAvailable" [#1881](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1881) - -## 6.0.0-beta.29 - -### BREAKING CHANGES - -- Plugin conversion to a [Federated Plugin](https://docs.flutter.dev/packages-and-plugins/developing-packages#federated-plugins) to better support multiple environments and implementations. -- Dart SDK min version `>= 2.17.0` -- Android package name has been changed to `com.pichillilorenzo.flutter_inappwebview_android`. References to old package name `com.pichillilorenzo.flutter_inappwebview` should be updated, for example inside `AndroidManifest.xml` file: ``. The return value indicates whether the cookie was set successfully -- Merged "feat(ios): optional tradeoff to fix ios input delay" [#1665](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1665) (thanks to [andreasgangso](https://github.com/andreasgangso)) -- Merged "Fix ios multiple flutter presenting error" [#1736](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1736) (thanks to [AlexT84](https://github.com/AlexT84)) -- Merged "fix cert parsing for ios 12" [#1822](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1822) (thanks to [darkang3lz92](https://github.com/darkang3lz92)) -- Merged "Fix iOS and macOS Forced unwrap null value HTTPCookie for CookieManager.setCookie" [#1677](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1677) (thanks to [maxmitz](https://github.com/maxmitz)) -- Merged "android imm.isAcceptingText() crash fix" [#1827](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1827) (thanks to [AlexDochioiu](https://github.com/AlexDochioiu)) -- Merged "fix: chrome tab open failed due to chrome process not running" [#1772](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1772) (thanks to [YumengNevix](https://github.com/YumengNevix)) -- Merged "Android - Fix context menu position for pages with horizontal scroll" [#1504](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1504) (thanks to [lrorpilla](https://github.com/lrorpilla)) -- Fixed "iOS about:blank popup not loading page" [#1500](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1500) -- Fixed "iOS macOS - This method should not be called on the main thread as it may lead to UI unresponsiveness" [#1678](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678) -- Fixed iOS and macOS InAppWebView memory leaks - -## 6.0.0-beta.25 - -- Updated `androidx.webkit:webkit` dependency to `1.8.0` -- Updated `androidx.browser:browser` dependency to `1.6.0` -- Merged "feat: InAppLocalhostServer decode assets url when loading them" [#1657](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1657) (thanks to [Nirajn2311](https://github.com/Nirajn2311)) -- Merged "fix: xcode 15 related bug" [#1801](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1801) (thanks to [nesquikm](https://github.com/nesquikm)) - -## 6.0.0-beta.24+1 - -- Fixed "Can't compile on Android" [#1691](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1691) - -## 6.0.0-beta.24 - -- Added InAppWebView keep alive feature -- Added InAppBrowser menu items feature -- Added `hasJavaScriptHandler`, `hasUserScript`, `hasWebMessageListener` InAppWebViewController methods -- Added `hideCloseButton`, `hideDefaultMenuItems`, `menuButtonColor` InAppBrowser settings -- `HeadlessInAppWebView.webViewController` could be `null` -- Removed `throwIfAlreadyOpened`, `throwIfNotOpened` InAppBrowser methods -- Removed `throwIfAlreadyOpened`, `throwIfNotOpened` ChromeSafariBrowser methods -- Merged "fix #1389 #1315 contextMenu ios 13" [#1575](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1575) (thanks to [heralight](https://github.com/heralight)) -- Merged "fix: remove ignored flutter_export_environment.sh" [#1593](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1593) (thanks to [Sunbreak](https://github.com/Sunbreak)) -- Merged "Fix AndroidX migration URL in README.md" [#1529](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1529) (thanks to [cslee](https://github.com/cslee)) -- Merged "InAppBrowser Bugfix/viewgroup index crash" [#1618](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1618) (thanks to [KhatibFX](https://github.com/KhatibFX)) -- Fixed old iOS versions crash "dyld: Library not loaded: /usr/lib/swift/libswiftCoreGraphics.dylib Reason: image not found" (thanks to [guide-flutter](https://github.com/guide-flutter)) -- Fixed `InAppBrowser.show()` possible crash on macOS -- Fixed missing `windowTitlebarSeparatorStyle`, `windowAlphaValue`, `windowStyleMask`, `windowFrame` macOS settings updates when using `setSettings()` -- Fixed "iOS and macOS flutter multiple engine" [#1632](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1632) - -## 6.0.0-beta.23 - -- Updated `androidx.webkit:webkit` dependency to `1.6.1` -- Updated `androidx.browser:browser` dependency to `1.5.0` -- Updated `androidx.appcompat:appcompat` dependency to `1.6.1` -- Added support for Android `WebViewFeature.GET_COOKIE_INFO` -- Added `requestedWithHeaderOriginAllowList` WebView setting for Android -- Added `isInspectable`, `shouldPrintBackgrounds` WebView settings for iOS and macOS -- Removed `WebViewFeature.REQUESTED_WITH_HEADER_CONTROL`, `ServiceWorkerController.setRequestedWithHeaderMode()`, `ServiceWorkerController.getRequestedWithHeaderMode()`, `InAppWebViewSettings.requestedWithHeaderMode` -- Fixed "Build fail with AGP 8.0" [#1643](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1643) -- Fixed "java.lang.RuntimeException: Unknown feature REQUESTED_WITH_HEADER_CONTROL" [#1611](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1611) -- Fixed "iOS 16.4 WebDebugging WKWebView.isInspectable" [#1629](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1629) -- Fixed some `@available` checks for macOS - -## 6.0.0-beta.22 - -- Updated `window.flutter_inappwebview.callHandler` implementation: if there is an error/exception on Flutter/Dart side, the `callHandler` will reject the JavaScript promise with the error/exception message, so you can catch it also on JavaScript side -- Fixed Android Web Storage Manager `deleteAllData` and `deleteOrigin` methods implementation -- Fixed "Xiaomi store - Conflict of Privacy Permissions, android.permission.MY_READ_INSTALLED_PACKAGES" [#1462](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1462) -- Fixed "Flutter 3.0.5 compilation issue" [#1475](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1475) - -## 6.0.0-beta.21 - -- Fixed "Android plugin version 6 - UserScripts not executing on new tabs." [#1455](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1455) - -## 6.0.0-beta.20 - -- Using Android `WebViewClientCompat` for Chromium-based WebView if the WebView package major version is >= 73 (https://bugs.chromium.org/p/chromium/issues/detail?id=925887) -- Updated code docs -- Fixed "Unexpected addWebMessageListener behaviour" [#1422](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1422) - -## 6.0.0-beta.19 - -- Updated code docs -- Fixed "Cannot Grant Permission at Android 21" [#1447](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1447) -- Fixed some missing macOS asserts - -## 6.0.0-beta.18 - -- Fixed `InAppWebViewSettings` automatic infer if `initialSettings` is `null` - -## 6.0.0-beta.17 - -- Replaced `Uri.encodeFull` with `Uri.encodeComponent` to load html data correctly on Web platform - -## 6.0.0-beta.16 - -- Removed Android Hybrid Composition constraint to use the pull-to-refresh feature -- Removed Android `com.squareup.okhttp3:okhttp` dependency - -## 6.0.0-beta.15 - -- Automatically infer `useShouldOverrideUrlLoading`, `useOnLoadResource`, `useOnDownloadStart`, `useShouldInterceptAjaxRequest`, `useShouldInterceptFetchRequest`, `useShouldInterceptRequest`, `useOnRenderProcessGone`, `useOnNavigationResponse` settings if their value is `null` and the corresponding event is implemented by the WebView (`InAppWebView` and `HeadlessInAppWebView`, not `InAppBrowser`) before it's native initialization - -### BREAKING CHANGES - -- All `PrintJobSettings` properties are optionals -- All `PullToRefreshSettings` properties are optionals -- All `WebAuthenticationSessionSettings` properties are optionals - -## 6.0.0-beta.14 - -- Fixed User Script remove methods -- Fixed macOS available checks for XCode 14.1 - -## 6.0.0-beta.13 - -- Added `ContentBlockerActionType.BLOCK_COOKIES` and `ContentBlockerActionType.IGNORE_PREVIOUS_RULES` for iOS and macOS platforms -- Updated `ContentBlockerTrigger.urlFilterIsCaseSensitive` for Android -- Fixed Android `ContentBlockerActionType.CSS_DISPLAY_NONE` usage - -## 6.0.0-beta.12 - -- Removed `willSuppressErrorPage` WebView Android setting in favor of `disableDefaultErrorPage`. -- Added `isMultiProcessEnabled` static method on `InAppWebViewController` for Android -- Added `onContentSizeChanged` WebView event for iOS -- Added `onPermissionRequestCanceled`, `onRequestFocus` WebView events for Android -- Added `defaultVideoPoster` WebView setting for Android -- Added `TracingController` for Android WebViews - -### BREAKING CHANGES - -- Removed `willSuppressErrorPage` WebView Android setting. Use `disableDefaultErrorPage` instead. - -## 6.0.0-beta.11 - -- Fixed "[webRTC / macOS] onPermissionRequest not called on HeadlessInAppWebView" [#1405](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1405) - -## 6.0.0-beta.10 - -- Created `WebUri` class to replace `Uri` dart core type. Related to: - - "Uri.tryParse will make the host to be lowercase" [#1402](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1402) - - "An error occurs when using a specific intent" [#1328](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1328) - - "Android shouldOverrideUrlLoading not working" [#1350](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1350) - -### BREAKING CHANGES - -- Replaced the usage of `Uri` type with the new `WebUri` type - -## 6.0.0-beta.9 - -- Added `headers`, `otherLikelyURLs`, `referrer` arguments on `ChromeSafariBrowser.open` method for Android -- Added `onNavigationEvent`, `onServiceConnected`, `onRelationshipValidationResult` events on `ChromeSafariBrowser` for Android -- Added `mayLaunchUrl`, `launchUrl`, `updateActionButton`, `validateRelationship`, `setSecondaryToolbar`, `updateSecondaryToolbar` methods on `ChromeSafariBrowser` for Android -- Added `startAnimations`, `exitAnimations`, `navigationBarColor`, `navigationBarDividerColor`, `secondaryToolbarColor`, `alwaysUseBrowserUI` ChromeSafariBrowser settings for Android -- Added `getMaxToolbarItems` static method on `ChromeSafariBrowser` for Android -- Added `ChromeSafariBrowserMenuItem.image` property for iOS -- Added `didLoadSuccessfully` optional argument on `ChromeSafariBrowser.onCompletedInitialLoad` event for iOS -- Added `onInitialLoadDidRedirect`, `onWillOpenInBrowser` events on `ChromeSafariBrowser` for iOS -- Added `activityButton`, `eventAttribution` ChromeSafariBrowser settings for iOS -- Added `clearWebsiteData`, `prewarmConnections`, `invalidatePrewarmingToken` static methods on `ChromeSafariBrowser` for iOS -- Added `getVariationsHeader` WebView static method - -### BREAKING CHANGES - -- `ChromeSafariBrowser.onCompletedInitialLoad` event has an optional argument -- `ChromeSafariBrowserMenuItem.action` and `ChromeSafariBrowserActionButton.action` can be null -- All `ChromeSafariBrowserSettings` properties are optionals - -## 6.0.0-beta.8 - -- Merged "Exposed "shared" property of HttpServer bind method to support more use-cases." [#1395](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1395) (thanks to [LugonjaAleksandar](https://github.com/LugonjaAleksandar)) -- Fixed "ios 14.5 crash reports upgradeKnownHostsToHTTPS" [#1393](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1393) - -## 6.0.0-beta.7 - -- Updated Android hybrid composition implementation - -### BREAKING CHANGES - -- Minimum Flutter version `3.0.0` - -## 6.0.0-beta.6 - -- Added `InAppWebViewSettings.allowBackgroundAudioPlaying` for Android -- Added `WebViewAssetLoader` and `InAppWebViewSettings.webViewAssetLoader` for Android - -### BREAKING CHANGES - -- `WebResourceResponse.contentType` and `WebResourceResponse.contentEncoding` properties can be null - -## 6.0.0-beta.5 - -- Merge fixes of version `5.5.0+5` - -## 6.0.0-beta.4 - -- Added `InAppWebView.headlessWebView` property to convert an `HeadlessWebView` to `InAppWebView` widget - -## 6.0.0-beta.3 - -- Added MacOS support -- Added `windowType`, `windowAlphaValue`, `windowStyleMask`, `windowTitlebarSeparatorStyle`, `windowFrame` for MacOS `InAppBrowserSettings` -- Added `PrintJobInfo.printer` -- Added `getContentWidth` WebView method - -### BREAKING CHANGES - -- Removed `PrintJobInfo.printerId` -- All `InAppWebViewSettings`, `InAppBrowserSettings` properties are optionals -- `InAppBrowser.webViewController` can be null - -## 6.0.0-beta.2 - -- Fixed web example -- Fixed export library - -## 6.0.0-beta.1 - -- Deprecated old classes/properties/methods to make them eventually compatible with other Platforms and WebView engines. -- Added Web support -- Added `ProxyController` for Android -- Added `PrintJobController` to manage print jobs -- Added `WebAuthenticationSession` for iOS -- Added `FindInteractionController` for Android and iOS -- Added `pauseAllMediaPlayback`, `setAllMediaPlaybackSuspended`, `closeAllMediaPresentations`, `requestMediaPlaybackState`, `isInFullscreen`, `getCameraCaptureState`, `setCameraCaptureState`, `getMicrophoneCaptureState`, `setMicrophoneCaptureState`, `loadSimulatedRequest` WebView controller methods -- Added `underPageBackgroundColor`, `isTextInteractionEnabled`, `isSiteSpecificQuirksModeEnabled`, `upgradeKnownHostsToHTTPS`, `forceDarkStrategy`, `willSuppressErrorPage`, `algorithmicDarkeningAllowed`, `requestedWithHeaderMode`, `enterpriseAuthenticationAppLinkPolicyEnabled`, `isElementFullscreenEnabled`, `isFindInteractionEnabled`, `minimumViewportInset`, `maximumViewportInset` WebView settings -- Added `onCameraCaptureStateChanged`, `onMicrophoneCaptureStateChanged` WebView events -- Added support for `onPermissionRequest` event on iOS 15.0+ -- Added `debugLoggingSettings` static property for WebView and ChromeSafariBrowser -- Added `WebViewFeature.DOCUMENT_START_SCRIPT` Android feature support -- Added `getRequestedWithHeaderMode`, `setRequestedWithHeaderMode` ServiceWorkerController methods -- Added `ContentBlockerTrigger.ifFrameUrl` and `ContentBlockerTrigger.loadContext` properties -- Added `PullToRefreshController.isEnabled` method -- Updated `getMetaThemeColor` on iOS 15.0+ -- Deprecated `onLoadError` for `onReceivedError`. `onReceivedError` will be called also for subframes -- Deprecated `onLoadHttpError` for `onReceivedHttpError`. `onReceivedHttpError` will be called also for subframes - -### BREAKING CHANGES - -- Updated Android `minSdkVersion` to `19` -- Updated minimum iOS version to `9.0` -- On Android, the `InAppWebView` widget uses hybrid composition by default (`useHybridComposition: true`) -- All properties of `GeolocationPermissionShowPromptResponse` cannot be `null` -- Removed `URLProtectionSpace.iosIsProxy` property -- `historyUrl` and `baseUrl` of `InAppWebViewInitialData` can be `null` - -## 5.8.0 - -- Merged "fix: xcode 15 related bug" [#1790](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1790) (thanks to [nesquikm](https://github.com/nesquikm)) - -## 5.7.2+3 - -- Fixed "Xiaomi store - Conflict of Privacy Permissions, android.permission.MY_READ_INSTALLED_PACKAGES" [#1462](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1462) - -## 5.7.2+2 - -- Fixed "Unexpected addWebMessageListener behaviour" [#1422](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1422) - -## 5.7.2+1 - -- Fixed "Cannot Grant Permission at Android 21" [#1447](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1447) - -## 5.7.2 - -- Removed Android Hybrid Composition constraint to use the pull-to-refresh feature - -## 5.7.1+2 - -- Fixed Android `NullPointerException` on `InAppBrowserActivity.dispose` - -## 5.7.1+1 - -- Fixed User Script remove methods -- Fixed missing `break` statement on Android when parsing `ChromeCustomTabsOptions.displayMode` in Java code - -## 5.7.1 - -- Exposed "shared" property of HttpServer bind method to support more use-cases. (thanks to [LugonjaAleksandar](https://github.com/LugonjaAleksandar)) - -## 5.7.0 - -- Added `PlatformViewsService.initExpensiveAndroidView` for Android - -### BREAKING CHANGES - -- Flutter minimum version `3.0.0` - -## 5.6.0+2 - -- Revert back the usage of `PlatformViewsService.initExpensiveAndroidView` - -## 5.6.0+1 - -- Fixed Android hybrid composition on Flutter 2 - -## 5.6.0 - -- Fixed "URLCredential.fromMap returns null for username" [#1205](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1205) -- Fixed "Compare to webview_flutter, inappwebview is significant frame dropped while page scrolling" [#1386](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1386) -- Merged "Fix hybrid composition laggy" [#1387](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1387) (thanks to [Doflatango](https://github.com/Doflatango)) - -## 5.5.0+5 - -- Fixed `HeadlessInAppWebView` default size on Android -- Fixed "🐞[Android] execution of the workmanager destroys in_app_webview library's platform channel" [#1348](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1348) -- Fixed "HeadlessInAppWebView called from WorkManager background task triggers NullPointerException on missing context" [#912](https://github.com/pichillilorenzo/flutter_inappwebview/issues/912) - -## 5.5.0+4 - -- Fixed "Many crashes on iOS: Completion handler was not called" [#1221](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1221) -- Fixed "webView:didReceiveAuthenticationChallenge:completionHandler" [#1128](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1128) -- Merged "Fix missing import for Flutter 2.8.1" [#1381](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1381) (thanks to [chandrabezzo](https://github.com/chandrabezzo)) - -## 5.5.0+3 - -- Fixed iOS `toolbarTopTintColor` InAppBrowser option -- Fixed iOS `InAppBrowserOptions.hideProgressBar` when getting options -- Fixed missing implementation `InAppBrowser.isHidden` method on Android and iOS -- Fixed "Attempt to invoke virtual method 'java.lang.String android.webkit.WebView.getUrl()' on a null object reference" [#1324](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1324) -- Fixed "(Crash) NullPointerException at in_app_browser.InAppBrowserActivity.close' on a null object reference" [#1278](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1278) -- Fixed "ios system version parser error" [#1355](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1355) -- Removed unnamed constructors for all Singleton classes to avoid incorrect usage - -## 5.5.0+2 - -- Fixed README - -## 5.5.0+1 - -- Fixed README - -## 5.5.0 - -- Added Android direct camera capture feature -- Fixed missing `PullToRefreshController.isRefreshing` iOS implementation -- Fixed Android `PullToRefreshController.setEnabled` at runtime -- Fixed iOS `findNext` -- Fixed Android `RendererPriorityPolicy.waivedWhenNotVisible` type 'Null' is not a subtype of type 'bool' -- Fixed iOS 14.0 crash when calling `callAsyncJavaScript` method -- Merged "Android fix leaking MethodChannel through anonymous class" [#1201](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1201) (thanks to [emakar](https://github.com/emakar)) -- Merged "Fix RangeError: Maximum call stack size exceeded" [#1208](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1208) (thanks to [liasica](https://github.com/liasica)) -- Merged "fix: try to open with Chrome if default browser app does not support custom tabs" [#1233](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1233) (thanks to [addie9000](https://github.com/addie9000)) -- Merged "fix: Prevent Android java.lang.NullPointerException in InAppWebViewCl…" [#1237](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1237) (thanks to [kamilpowalowski](https://github.com/kamilpowalowski)) -- Merged "Android - Load client certificate from local storage" [#1241](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1241) (thanks to [akioyamamoto1977](https://github.com/akioyamamoto1977)) -- Merged "fix Theme_AppCompat_Dialog_Alert not found" [#1262](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1262) (thanks to [mohenaxiba](https://github.com/mohenaxiba)) -- Merged "Allow a cookie without a domain to be set on Android" [#1295](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1295) (thanks to [bagedevimo](https://github.com/bagedevimo)) -- Merged "Catch and ignore utf8 format exception in getFavicons()" [#1302](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1302) (thanks to [Doflatango](https://github.com/Doflatango)) -- Merged "Disable exporting activity definitions for Android" [#1313](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1313) (thanks to [daanporon](https://github.com/daanporon)) -- Merged "Add directoryIndex and documentRoot to InAppLocalhostServer option" [#1319](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1319) (thanks to [fa0311](https://github.com/fa0311)) -- Merged "fix(ios): invoke onBrowserCreated when viewDidLoad is called with win…" [#1344](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1344) (thanks to [perffecto](https://github.com/perffecto)) - -### BREAKING CHANGES - -- `CookieManager.getCookie`, `CookieManager.deleteCookie` and `CookieManager.deleteCookies` have the `domain` argument optional and without a default value - -## 5.4.4+3 - -- Removed Android unsafe trust manager - -## 5.4.4+2 - -- Fixed LICENSE - -## 5.4.4+1 - -- Fixed README - -## 5.4.4 - -- Added support for Android 33 -- Fixed possible null pointer exception in Android `ChromeCustomTabsActivity.java` - -## 5.4.3+8 - -- Merged "Xcode 14 build error: Stored properties cannot be marked potentially unavailable with '@available'" [#1238](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1238) (thanks to [CodeEagle](https://github.com/CodeEagle)) -- Fixed example for iOS - -## 5.4.3+7 - -- Fixed possible Android java.lang.NullPointerException in "InAppBrowserActivity.onCreateOptionsMenu" about "webView.getTitle()" - -## 5.4.3+6 - -- Fixed "iOS flutter_inappwebview/URLRequest.swift:13: Fatal error: Unexpectedly found nil while unwrapping an Optional value" [#1173](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1173) - -## 5.4.3+5 - -- Fixed possible java.lang.NullPointerException in `Runnable` of `InputAwareWebView.setInputConnectionTarget` method -- Fixed "Android Crash in latest 5.4.3+4 - java.lang.NullPointerException: Attempt to invoke virtual method java.lang.String android.webkit.WebView.getUrl()" [#1168](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1168) - -## 5.4.3+4 - -- Updated docs for `ChromeSafariBrowser.open` and throw error on iOS if the `url` parameter use a different scheme then `http` or `https` - -## 5.4.3+3 - -- Fixed "Android error: package org.jetbrains.annotations does not exist import org.jetbrains.annotations.NotNull;" [#1166](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1166) - -## 5.4.3+2 - -- Fixed "Latest version 5.4.3 crashes on Android" [#1159](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1159) - -## 5.4.3+1 - -- Try to fix "Latest version 5.4.3 crashes on Android" [#1159](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1159) - -## 5.4.3 - -- Added Bitwise OR operator support for `AndroidActionModeMenuItem` class - -## 5.4.2+1 - -- Try to fix "Latest version 5.4.2 crashes on Android - HeadlessInAppWebView.dispose" [#1155](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1155) - -## 5.4.2 - -- Added `setActionButton` method to `ChromeSafariBrowser` class - -## 5.4.1+2 - -- Fixed "Android ServiceWorkerControllerCompat.setServiceWorkerClient(null) makes Webivew Plugin Crashes" [#1151](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1151) - -## 5.4.1+1 - -- Fixed Android default context menu over custom context menu on API Level 31+ - -## 5.4.1 - -- Managed iOS native `detachFromEngine` flutter plugin event and updated `dispose` methods -- Updated Android native `HeadlessInAppWebViewManager.dispose` and `HeadlessInAppWebView.dispose` methods - -## 5.4.0+3 - -- Fixed Android error in some cases when calling `setServiceWorkerClient` java method on `ServiceWorkerManager` initialization - -## 5.4.0+2 - -- Fixed Android `ChromeCustomTabsActivity` not responding to the `ActionBroadcastReceiver` - -## 5.4.0+1 - -- Merged "[Android] Explicitly export for the receiver defined in AndroidManifest" [#1147](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1147) (thanks to [AlexV525](https://github.com/AlexV525)) - -## 5.4.0 - -- `getOriginalUrl` method is cross-platform now -- Updated Android `compileSdkVersion` to 31 -- Updated Flutter environment: sdk to `>=2.14.0 <3.0.0` and flutter version to `>=2.5.0` -- Added `singleInstance` option for Android `ChromeSafariBrowser` implementation -- Added `onDownloadStartRequest` event and deprecated old `onDownloadStart` event -- Added `shareState` Android option for `ChromeSafariBrowser` class -- Added support for Android TWA (Trusted Web Activity) -- Fixed missing `onZoomScaleChanged` call for `InAppBrowser` class -- Fixed `requestImageRef` method always `null` on iOS -- Fixed "applicationNameForUserAgent is not work in ios" [#525](https://github.com/pichillilorenzo/flutter_inappwebview/issues/525) -- Fixed "Crash when try select file from webview input on Android" [#867](https://github.com/pichillilorenzo/flutter_inappwebview/issues/867) -- Fixed "NavigationAction.request should use toMap method" [#878](https://github.com/pichillilorenzo/flutter_inappwebview/issues/878) -- Fixed "Missing body field in URLRequest toMap method" [#990](https://github.com/pichillilorenzo/flutter_inappwebview/issues/990) -- Fixed "iOS : createWindowAction.request.body in onCreateWindow() is NULL" [#994](https://github.com/pichillilorenzo/flutter_inappwebview/issues/994) -- Fixed "Crash at HeadlessInAppWebView dispose" [#881](https://github.com/pichillilorenzo/flutter_inappwebview/issues/881) -- Fixed "Crash happens when HeadlessInAppWebView's dispose function is called in iOS" [#972](https://github.com/pichillilorenzo/flutter_inappwebview/issues/972) -- Fixed "In android, when click a href with img returns img src on onCreateWindow" [#951](https://github.com/pichillilorenzo/flutter_inappwebview/issues/951) -- Fixed "crash at com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView$11.run (InAppWebView.java:1307)" [#1040](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1040) -- Fixed "Unexpected behavior when using a null initialUrlRequest" [#1063](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1063) -- Fixed "Local storage & cookie didn't persist when sharedCookie and cache both enabled" [#1092](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1092) -- Fixed "ios zoomBy crash: Foundation/NSNumber.swift:467: Fatal error: Unable to bridge NSNumber to Float" [#873](https://github.com/pichillilorenzo/flutter_inappwebview/issues/873) -- Fixed "In App Browser Crashing in Android - Action Bar is null" [#1137](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1137) -- Fixed "Cannot load Javascript on some Android devices - Uncaught TypeError: Cannot read property 'appendChild' of null" [#888](https://github.com/pichillilorenzo/flutter_inappwebview/issues/888) -- Merged "Update Options.swift" [#889](https://github.com/pichillilorenzo/flutter_inappwebview/pull/889) (thanks to [cloudygeek](https://github.com/cloudygeek)) -- Merged "fix: Applicatio nNameForUserAgent is not working in iOS" [#1095](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1095) (thanks to [sunalwaysknows](https://github.com/sunalwaysknows)) -- Merged "Make sure we open a new instance of a custom chrome chrome tab" [#812](https://github.com/pichillilorenzo/flutter_inappwebview/pull/812) (thanks to [savy-91](https://github.com/savy-91)) -- Merged "fix bug when in String[] array come null" [#868](https://github.com/pichillilorenzo/flutter_inappwebview/pull/868) (thanks to [Ser1ous](https://github.com/Ser1ous)) -- Merged "fix: use in NavigationAction request toMap method" [#879](https://github.com/pichillilorenzo/flutter_inappwebview/pull/879) (thanks to [chreck](https://github.com/chreck)) -- Merged "switch android mockserver dependency with okhttp" [#946](https://github.com/pichillilorenzo/flutter_inappwebview/pull/946) (thanks to [randysecrist](https://github.com/randysecrist)) -- Merged "Adds missing body to URLRequest mapping." [#991](https://github.com/pichillilorenzo/flutter_inappwebview/pull/991) (thanks to [Miiha](https://github.com/Miiha)) -- Merged "fix. Crash happens when HeadlessInAppWebView's dispose function is called in iOS" [#1017](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1017) (thanks to [hoanglm4](https://github.com/hoanglm4)) -- Merged "Fixes URL returned when taping image with href in onCreateWindow [Android]" [#1042](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1042) (thanks to [Manuito83](https://github.com/Manuito83)) -- Merged "Fix Android Sometimes crash after close webpage and return to platform code." [#1050](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1050) (thanks to [rsydor](https://github.com/rsydor)) -- Merged "Add application/wasm MimeType with InAppLocalhostServer" [#1054](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1054) (thanks to [foxstream528](https://github.com/foxstream528)) -- Merged "Fixed the unexpected behavior of InAppWebView and HeadlessInAppWebView when initialUrlRequest was set as null." [#1064](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1064) (thanks to [RodXander](https://github.com/RodXander)) -- Merged "updated com.android.tools.build:gradle" [#1066](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1066) (thanks to [chownation](https://github.com/chownation)) -- Merged "WIP - expose content-disposition and content-length from android" [#1088](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1088) (thanks to [ashank96](https://github.com/ashank96)) -- Merged "Fix ios persistance when using sharedCookie" [#1093](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1093) (thanks to [EA-YOUHOU](https://github.com/EA-YOUHOU)) -- Merged "Fixes zoomBy with floats (iOS)" [#1109](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1109) (thanks to [Manuito83](https://github.com/Manuito83)) -- Merged "Build on and support Android 12 SDK 31" [#1111](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1111) (thanks to [carloserazo47](https://github.com/carloserazo47)) -- Merged "Fix takeScreenshot Crash on iOS" [#1123](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1123) (thanks to [a00012025](https://github.com/a00012025)) -- Merged "Feature. Possibility to disable iOS above keyboard inputAccessoryView" [#1124](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1124) (thanks to [cutzmf](https://github.com/cutzmf)) - -## 5.3.2 - -- Added `onLoad` and `onError` callbacks in `ScriptHtmlTagAttributes` class used by `InAppWebViewController.injectJavascriptFileFromUrl` -- `InAppWebViewController.injectJavascriptFileFromAsset` returns a `Future` type now - -## 5.3.1+1 - -- Removed duplicate lib exports -- Fixed some rare cases when iOS WKWebView `scrollViewDidEndDragging` event blocks the scroll gesture - -## 5.3.1 - -- Added support of `allowingReadAccessTo` iOS-specific WebView option for the WebView `initialData` parameter -- Added `iosAllowingReadAccessTo` iOS-specific parameter to the `loadData` WebView method -- Fixed "iOS webview showing blank page in specific URL" [#776](https://github.com/pichillilorenzo/flutter_inappwebview/issues/776) -- Fixed "unable to access ApplicationDocumentsDirectory in real Ios devices" [#748](https://github.com/pichillilorenzo/flutter_inappwebview/issues/748) - -## 5.3.0+1 - -- Fixed "Android - Pull to refresh triggered when scrolling container inside a website" [#765](https://github.com/pichillilorenzo/flutter_inappwebview/issues/765) -- Fixed "InAppWebViewController.getHitTestResult" wrong type mapping - -## 5.3.0 - -- Added `initialSize` property to the `HeadlessInAppWebView` class -- Added `setSize` and `getSize` methods to the `HeadlessInAppWebView` class -- `androidOnScaleChanged` WebView event is now deprecated. Use the new `onZoomScaleChanged` WebView event, that is available for both Android and iOS -- `getScale` WebView method is now deprecated. Use the new `getZoomScale` WebView method -- Removed `final` keyword for all `HeadlessInAppWebView` events -- Fixed wrong usage of Android WebView scale property -- Fixed "java.lang.NullPointerException: com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebViewRenderProcessClient$1.success(InAppWebViewRenderProcessClient.java:37)" [#757](https://github.com/pichillilorenzo/flutter_inappwebview/issues/757) -- Fixed "In a multi-activity app, the plugin doesn't reattach to the first activity" [#732](https://github.com/pichillilorenzo/flutter_inappwebview/issues/732) -- Fixed "ChromeSafariBrowser isn't calling its events, and not keeping track of isOpen properly" [#759](https://github.com/pichillilorenzo/flutter_inappwebview/issues/759) -- Fixed Android ChromeSafariBrowser menu item callback not called because of PendingIntents extra were cached - -## 5.2.1+1 - -- Fixed iOS "Unexpectedly found nil while unwrapping an Optional value: file flutter_inappwebview/WKUserContentController.swift, line 36" error when `applePayAPIEnabled` iOS-specific WebView option is enabled - -## 5.2.1 - -- Added `isRunning` method to the `HeadlessInAppWebView` class -- Added `isRunning` method to the `InAppLocalhostServer` class -- Added `allowGoBackWithBackButton` and `shouldCloseOnBackButtonPressed` Android-specific InAppBrowser options -- Fixed iOS `WebMessageListener` javascript implementation not calling event listeners when `onmessage` is set -- Fixed `onCreateContextMenu` event on Android where `hitTestResult` has always `null` values -- Fixed "java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.SearchView.setQuery(java.lang.CharSequence, boolean)' on a null object reference" [#742](https://github.com/pichillilorenzo/flutter_inappwebview/issues/742) -- Fixed Android js error in some very rare case where `window.flutter_inappwebview` is `undefined` when loading plugin scripts - -## 5.2.0 - -- Added `WebMessageChannel` and `WebMessageListener` features -- Added `canScrollVertically` and `canScrollHorizontally` webview methods -- Added Android pull-to-refresh `setSize` method and `size` option -- Added `onOverScrolled` WebView event -- `AndroidInAppWebViewController.getCurrentWebViewPackage` is available now starting from Android API 21+ -- Updated Android Gradle distributionUrl version to `5.6.4` -- Updated Android `androidx.webkit:webkit` to `1.4.0`, `androidx.browser:browser` to `1.3.0`, `androidx.appcompat:appcompat` to `1.2.0` -- Attempt to fix "InAppBrowserActivity.onCreate NullPointerException - Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference" [#665](https://github.com/pichillilorenzo/flutter_inappwebview/issues/665) -- Fixed "[iOS] Application crashes when processing onCreateWindow" [#579](https://github.com/pichillilorenzo/flutter_inappwebview/issues/579) -- Fixed wrong mapping of `NavigationAction` class on Android for `androidHasGesture` and `androidIsRedirect` properties -- Fixed "Pull to refresh creating problem in some webpages on Android" [#719](https://github.com/pichillilorenzo/flutter_inappwebview/issues/719) -- Fixed iOS sometimes `scrollView.contentSize` doesn't fit all the `frame.size` available -- Fixed ajax and fetch interceptor when the data/body sent is not a string -- Fixed "InAppLocalhostServer - Error: type 'List' is not a subtype of type 'List' in type cast" [#724](https://github.com/pichillilorenzo/flutter_inappwebview/issues/724) -- Merged "fix proguard" [#737](https://github.com/pichillilorenzo/flutter_inappwebview/pull/737) (thanks to [myroid](https://github.com/myroid)) - -### BREAKING CHANGES - -- `FetchRequest.body` is a dynamic type now - -## 5.1.0+4 - -- Fixed "IOS scrolling crash the application" [#707](https://github.com/pichillilorenzo/flutter_inappwebview/issues/707) - -## 5.1.0+3 - -- Fixed "Unsupported operation: Platform._operatingSystem" when compiling for Web again [#507](https://github.com/pichillilorenzo/flutter_inappwebview/issues/507) - -## 5.1.0+2 - -- Fixed missing MATCH_PARENT layout params to the WebView on Android when it is wrapped by PullToRefreshLayout - -## 5.1.0+1 - -- Added a test for the pull-to-refresh feature when used on Android. It requires the `useHybridComposition: true` Android-specific option, otherwise it will throw an exception. - -## 5.1.0 - -- Added support for pull-to-refresh feature [#395](https://github.com/pichillilorenzo/flutter_inappwebview/issues/395) -- Fixed issue not rendering WebView content when scrolling on iOS [#703](https://github.com/pichillilorenzo/flutter_inappwebview/issues/703) -- Fixed `InAppBrowser.openData` method -- `InAppBrowser.initialUserScripts`, `InAppBrowser.id`, `HeadlessInAppWebView.id` properties are `final` now - -## 5.0.5+3 - -- Fixed Android `evaluateJavascript` method when using `contentWorld: ContentWorld.PAGE` - -## 5.0.5+2 - -- Updated docs for iOS-specific options `alwaysBounceVertical` and `alwaysBounceHorizontal` - -## 5.0.5+1 - -- Fixed "No bounce in inappwebview iOS" [#696](https://github.com/pichillilorenzo/flutter_inappwebview/issues/696) - -## 5.0.5 - -- Updated Android `WebChromeClient.getDefaultVideoPoster` -- Removed all the dependencies: `uuid`, `device_info`, `intl`, and `mime` - -## 5.0.4-nullsafety.1 - -- Added `headers` and `statusCode` properties to IOSURLResponse class - -## 5.0.3-nullsafety.1 - -- Fixed Android screenshot out of memory error -- Fixed `getFavicons` WebView method - -## 5.0.2-nullsafety.1 - -- Fixed missing `verticalScrollbarThumbColor`, `verticalScrollbarTrackColor`, `horizontalScrollbarThumbColor`, `horizontalScrollbarTrackColor` Android-specific WebView options when calling native java `setOptions()` method on Android - -## 5.0.1-nullsafety.1 - -- Added `verticalScrollbarThumbColor`, `verticalScrollbarTrackColor`, `horizontalScrollbarThumbColor`, `horizontalScrollbarTrackColor` Android-specific WebView options -- Fixed some null types and wrong casting - -## 5.0.0-nullsafety.0 - -- Added support for Dart null-safety feature -- Added Android Hybrid Composition support "Use PlatformViewLink widget for Android WebView" [#462](https://github.com/pichillilorenzo/flutter_inappwebview/pull/462) (thanks to [plateaukao](https://github.com/plateaukao) and [tneotia](https://github.com/tneotia)) -- Added `allowUniversalAccessFromFileURLs` and `allowFileAccessFromFileURLs` WebView options also for iOS (also thanks to [liranhao](https://github.com/liranhao)) -- Added limited cookies support on iOS below 11.0 using JavaScript -- Added `IOSCookieManager` class and `CookieManager.instance().ios.getAllCookies` iOS-specific method -- Added `UserScript`, `UserScriptInjectionTime`, `ContentWorld`, `AndroidWebViewFeature`, `AndroidServiceWorkerController`, `AndroidServiceWorkerClient`, `ScreenshotConfiguration`, `IOSWKPDFConfiguration`, `URLRequest` classes -- Added `initialUserScripts` WebView option -- Added `addUserScript`, `addUserScripts`, `removeUserScript`, `removeUserScripts`, `removeUserScriptsByGroupName`, `removeAllUserScripts`, `callAsyncJavaScript`, `isSecureContext` WebView methods -- Added `contentWorld` argument to `evaluateJavascript` WebView method -- Added `isDirectionalLockEnabled`, `mediaType`, `pageZoom`, `limitsNavigationsToAppBoundDomains`, `useOnNavigationResponse`, `applePayAPIEnabled`, `allowingReadAccessTo`, `disableLongPressContextMenuOnLinks` iOS-specific WebView options -- Added `handlesURLScheme`, `createPdf`, `createWebArchiveData` iOS-specific WebView methods -- Added `iosOnNavigationResponse` and `iosShouldAllowDeprecatedTLS` iOS-specific WebView events -- Added `iosAnimated` optional argument to `zoomBy` WebView method -- Added `screenshotConfiguration` optional argument to `takeScreenshot` WebView method -- Added `scriptHtmlTagAttributes` optional argument to `injectJavascriptFileFromUrl` WebView method -- Added `cssLinkHtmlTagAttributes` optional argument to `injectCSSFileFromUrl` WebView method -- Added `iosAllowingReadAccessTo` iOS-specific optional argument to `loadUrl` WebView method -- Added new iOS-specific attributes to `ShouldOverrideUrlLoadingRequest` and `CreateWindowRequest` classes -- Added `toolbarTopTranslucent`, `toolbarTopTintColor`, `toolbarBottomTintColor`, `toolbarTopBarTintColor` ios-specific InAppBrowser options -- Updated integration tests -- Merged "Upgraded appcompat to 1.2.0-rc-02" [#465](https://github.com/pichillilorenzo/flutter_inappwebview/pull/465) (thanks to [andreidiaconu](https://github.com/andreidiaconu)) -- Merged "Added missing field 'headers' which returned by WebResourceResponse.toMap()" [#490](https://github.com/pichillilorenzo/flutter_inappwebview/pull/490) (thanks to [Doflatango](https://github.com/Doflatango)) -- Merged "Fix: added iOS fallback module import" [#466](https://github.com/pichillilorenzo/flutter_inappwebview/pull/466) (thanks to [Eddayy](https://github.com/Eddayy)) -- Merged "Fix NullPointerException after taking a photo by a camera app on Android" [#492](https://github.com/pichillilorenzo/flutter_inappwebview/pull/492) (thanks to [AAkira](https://github.com/AAkira)) -- Merged "iOS CookieManager.getCookies - Check that URL has suffix of cookie do…" [#658](https://github.com/pichillilorenzo/flutter_inappwebview/pull/658) (thanks to [arneke](https://github.com/arneke)) -- Merged "Add NTLM Auth" [#634](https://github.com/pichillilorenzo/flutter_inappwebview/pull/634) (thanks to [albatrosify](https://github.com/albatrosify)) -- Merged "iOS ChromeSafariBrowserManager - Fixing unnecessary casting of rootViewController to FlutterViewController" [#567](https://github.com/pichillilorenzo/flutter_inappwebview/pull/567) (thanks to [gunantosteven](https://github.com/gunantosteven)) -- Merged "Fix _channel.invokeMethod name for injectCSSFileFromUrl method" [#645](https://github.com/pichillilorenzo/flutter_inappwebview/pull/645) (thanks to [omralcrt](https://github.com/omralcrt)) -- Merged "Add android media intents on wildcard input accept" [#620](https://github.com/pichillilorenzo/flutter_inappwebview/pull/620) (thanks to [cbodin](https://github.com/cbodin)) -- Merged "Add ChromeSafariBrowser support for Android 11" [#538](https://github.com/pichillilorenzo/flutter_inappwebview/pull/538) (thanks to [DRSchlaubi](https://github.com/DRSchlaubi)) -- Merged "fix(iOS): missing implementation of method zoomBy" [#670](https://github.com/pichillilorenzo/flutter_inappwebview/pull/670) (thanks to [pcqpcq](https://github.com/pcqpcq)) -- Merged "[mod] Fix all issues relate to long click in Android version 7.0 (#657, #527)" [#671](https://github.com/pichillilorenzo/flutter_inappwebview/pull/671) (thanks to [MrNinja](https://github.com/MrNinja)) -- Merged "Fix ViewGroup.removeView NullPointerException (#450)" [#683](https://github.com/pichillilorenzo/flutter_inappwebview/pull/683) (thanks to [toda-bps](https://github.com/toda-bps)) -- Fixed missing properties initialization when using InAppWebViewController.fromInAppBrowser -- Fixed "Issue in Flutter web: 'Unsupported operation: Platform._operatingSystem'" [#507](https://github.com/pichillilorenzo/flutter_inappwebview/issues/507) -- Fixed "window.flutter_inappwebview.callHandler is not a function" [#218](https://github.com/pichillilorenzo/flutter_inappwebview/issues/218) -- Fixed "Android ContentBlocker - java.lang.NullPointerException ContentBlockerTrigger resource type" [#506](https://github.com/pichillilorenzo/flutter_inappwebview/issues/506) -- Fixed "Android CookieManager throws error caused by websites that are sending back illegal/invalid cookies." [#476](https://github.com/pichillilorenzo/flutter_inappwebview/issues/476) -- Fixed missing `clearHistory` webview method implementation on Android -- Fixed iOS crash when using CookieManager getCookies for an URL and the host URL is `null` -- Fixed "IOS does not support allowUniversalAccessFromFileURLs" [#654](https://github.com/pichillilorenzo/flutter_inappwebview/issues/654) -- Fixed "Failed to load WebView provider: No WebView installed" [#642](https://github.com/pichillilorenzo/flutter_inappwebview/issues/642) -- Fixed "java.net.MalformedURLException: unknown protocol: wss - Error using library sipml5 in flutter_inappwebview" [#614](https://github.com/pichillilorenzo/flutter_inappwebview/issues/614) -- Fixed "Android 10 clipboard not working properly" [#678](https://github.com/pichillilorenzo/flutter_inappwebview/issues/678) (thanks to [armadastate](https://github.com/armadastate)) - -### BREAKING CHANGES - -- Minimum Flutter version required is `1.22.2` and Dart SDK `>=2.12.0-0 <3.0.0` -- iOS Xcode version `>= 12` -- `allowUniversalAccessFromFileURLs` and `allowFileAccessFromFileURLs` WebView options moved from Android-specific options to cross-platform options -- Added `callAsyncJavaScript` name to the list of javaScriptHandlerForbiddenNames -- Moved `saveWebArchive` WebView method from Android-specific to cross-platform -- Moved `progressBar` InAppBroswer from Android-specific option to cross-platform option and renamed to `hideProgressBar` -- Renamed `HttpAuthChallenge` to `URLAuthenticationChallenge` -- Updated `basicConstraints`, `subjectKeyIdentifier`, `authorityKeyIdentifier`, `certificatePolicies`, `cRLDistributionPoints`, `authorityInfoAccess` attributes type of `X509Certificate` -- Updated "WebView.storyboard" for InAppBrowser iOS representation -- Renamed `ShouldOverrideUrlLoadingAction` class to `NavigationActionPolicy` -- Renamed `ProtectionSpace` class to `URLProtectionSpace` -- Renamed `ProtectionSpaceHttpAuthCredentials` to `URLProtectionSpaceHttpAuthCredentials` -- Renamed `CreateWindowRequest` class to `CreateWindowAction` -- Renamed `initialUrl` to `initialUrlRequest` WebView attribute and made it of type `URLRequest` -- Renamed `toolbarTop` InAppBrowser cross-platform option to `hideToolbarTop` -- Renamed `toolbarBottom` InAppBrowser ios-specific option to `hideToolbarBottom` -- Removed `debuggingEnabled` WebView option; on Android you should use now the `AndroidInAppWebViewController.setWebContentsDebuggingEnabled(bool debuggingEnabled)` static method; on iOS, debugging is always enabled -- Removed `androidOnRequestFocus` event because it is never called -- Removed `initialHeaders` WebView attribute. Use `URLRequest.headers` attribute -- Removed `headers` argument from `loadFile` WebView method -- Removed `headers` argument from `openFile` InAppBrowser method -- Removed `headers` argument from `loadUrl` WebView method, renamed the `url` argument to `urlRequest` and made it of type `URLRequest` -- Removed `headers` argument from `openFile` InAppBrowser method -- Removed `headers` argument from `openUrl` InAppBrowser method, renamed the `url` argument to `urlRequest` and made it of type `URLRequest` -- Removed `fallback` argument from `ChromeSafariBrowser` constructor. Check for availability of `ChromeSafariBrowser` if you want show one or the other. -- Removed `scheme` argument from `onLoadResourceCustomScheme` WebView event. Use the `Uri url` parameter now. -- Removed `ShouldOverrideUrlLoadingRequest` class and replaced with `NavigationAction` -- Changed `zoomBy` WebView method signature -- Changed type of `urlFile` argument of `injectCSSFileFromUrl` WebView method to `Uri` -- Changed type of `urlFile` argument of `injectJavascriptFileFromUrl` WebView method to `Uri` -- Changed return type of `getOriginalUrl` Android-specific WebView method to `Uri` -- Changed return type of `getSafeBrowsingPrivacyPolicyUrl` Android-specific WebView method to `Uri` -- Changed type of `url` argument of `onLoadStart`, `onLoadStop`, `onLoadError`, `onLoadHttpError`, `onLoadResourceCustomScheme`, `onUpdateVisitedHistory`, `onPrint`, `onPageCommitVisible`, `androidOnSafeBrowsingHit`, `androidOnRenderProcessUnresponsive`, `androidOnRenderProcessResponsive`, `androidOnFormResubmission`, `androidOnReceivedTouchIconUrl` WebView events to `Uri` -- Changed type of `baseUrl` and `androidHistoryUrl` arguments of `loadData` WebView method and `openData` InAppBrowser method -- Changed `openUrl` InAppBrowser method to `openUrlRequest` -- Changed type of `url` argument of `openWithSystemBrowser` InAppBrowser method to `Uri` -- Changed all InAppBrowser color options type from `String` to `Color` -- Changed all ChromeSafariBrowser color options type from `String` to `Color` -- Updated attributes of `ShouldOverrideUrlLoadingRequest`, `ServerTrustChallenge` and `ClientCertChallenge` classes -- Changed type of `url` attribute to `Uri` for `JsAlertRequest`, `JsAlertConfirm`, `JsPromptRequest` classes - -## 4.0.0+4 - -- Reverted calling `handler.post` on Android when a WebView is created -- Fixed iOS extra bottom padding when opening the keyboard -- Fixed "Build for web not working – The integer literal 9223372036854775807 can't be represented exactly in JavaScript" [#429](https://github.com/pichillilorenzo/flutter_inappwebview/issues/429) -- Fixed iOS userContentController didReceive WKScriptMessage event when using a WebView created with a `windowId` - -## 4.0.0 - -- Updated `onCreateWindow`, `onJsAlert`, `onJsConfirm`, `onJsPrompt` webview events -- Added `onCloseWindow`, `onTitleChanged`, `onWindowFocus`, `onWindowBlur` webview events -- Added `androidOnRequestFocus`, `androidOnReceivedIcon`, `androidOnReceivedTouchIconUrl`, `androidOnJsBeforeUnload`, `androidOnReceivedLoginRequest` Android-specific webview events -- Added `disableDefaultErrorPage` Android-specific webview option -- Added `isAvailable` ChromeSafariBrowser static method -- Fixed "SFSafariViewController doesn't open like a native iOS modal" [#403](https://github.com/pichillilorenzo/flutter_inappwebview/issues/403) - -### BREAKING CHANGES - -- Updated `onCreateWindow`, `onJsAlert`, `onJsConfirm`, `onJsPrompt` webview event -- Renamed `OnCreateWindowRequest` class to `CreateWindowRequest` - -## 3.4.0+2 - -- Reverted default `InAppWebView.gestureRecognizers` value to null on Android - -## 3.4.0+1 - -- Updated README.md -- Updated missing docs -- Fixed pub.dev Health suggestions and Analysis suggestions - -## 3.4.0 - -- Added `requestFocusNodeHref`, `requestImageRef`, `getMetaTags`, `getMetaThemeColor`, `getScrollX`, `getScrollY`, `getCertificate` webview methods -- Added `WebStorage`, `LocalStorage` and `SessionStorage` class to manage `window.localStorage` and `window.sessionStorage` JavaScript [Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API) -- Added `supportZoom` webview option also on iOS -- Added `HttpOnly`, `SameSite` cookie options -- Updated `Cookie` class -- Added `animated` option to `scrollTo` and `scrollBy` webview methods -- Added error and message to the `ServerTrustChallenge` class for iOS (class used by the `onReceivedServerTrustAuthRequest` event) -- Added `contentInsetAdjustmentBehavior` webview iOS-specific option -- Added `copy` methods for webview options class -- Added `SslCertificate` class and `X509Certificate` class and parser -- Added `values` property for all the custom Enums -- Updated Android workaround to hide the Keyboard when the user click outside on something not focusable such as input or a textarea. -- Fixed `zoomBy`, `setOptions` webview methods on Android -- Fixed `databaseEnabled` android webview option default value to `true` -- Fixed `verticalScrollBarEnabled` and `horizontalScrollBarEnabled` on Android -- Fixed error caused by `pauseTimers` on iOS when the WebView has been disposed -- Fixed `ignoresViewportScaleLimits`, `dataDetectorTypes`, `suppressesIncrementalRendering`, `selectionGranularity` iOS-specific option when used in `initialOptions` -- Fixed `getFavicons` method -- Fixed `HttpAuthCredentialDatabase.removeHttpAuthCredential` on Android -- Fixed some cases where `takeScreenshot` was not working on Android -- Fixed `After upgrade to Android embedding V2, still get Shared.activity is null / NullPointerException on android.content.Context.getResources()` [#390](https://github.com/pichillilorenzo/flutter_inappwebview/issues/390) - -### BREAKING CHANGES - -- `evaluateJavascript` webview method now returns `null` on iOS if the evaluated JavaScript source returns `null` -- `getHtml` webview method now could return `null` if it was unable to get it. -- Moved `supportZoom` webview option to cross-platform -- `builtInZoomControls` android webview options changed default value to `true` -- Updated `ServerTrustChallenge` class used by the `onReceivedServerTrustAuthRequest` event -- The method `getOptions` could return null now -- Updated `HttpAuthCredentialDatabase.getAllAuthCredentials` method return type - -## 3.3.0+3 - -- Updated Android build.gradle version and some androidx properties -- Fixed `Multiple sessions` [#371](https://github.com/pichillilorenzo/flutter_inappwebview/issues/371) -- Fixed `incognito mode is broken swift` [#320](https://github.com/pichillilorenzo/flutter_inappwebview/issues/320) - -## 3.3.0 - -- Updated API docs -- Updated Android context menu workaround -- Calling `onCreateContextMenu` event on iOS also when the context menu is disabled in order to have the same effect as Android -- Added `options` attribute to `ContextMenu` class and created `ContextMenuOptions` class -- Added Android keyboard workaround to hide the keyboard when clicking other HTML elements, losing the focus on the previous input -- Added `onEnterFullscreen`, `onExitFullscreen` webview events [#275](https://github.com/pichillilorenzo/flutter_inappwebview/issues/275) -- Added Android support to use camera on HTML inputs that requires it, such as `` [#353](https://github.com/pichillilorenzo/flutter_inappwebview/issues/353) -- Added `overScrollMode`, `networkAvailable`, `scrollBarStyle`, `verticalScrollbarPosition`, `scrollBarDefaultDelayBeforeFade`, `scrollbarFadingEnabled`, `scrollBarFadeDuration`, `rendererPriorityPolicy`, `useShouldInterceptRequest`, `useOnRenderProcessGone` webview options on Android -- Added `pageDown`, `pageUp`, `saveWebArchive`, `zoomIn`, `zoomOut`, `clearHistory` webview methods on Android -- Added `getCurrentWebViewPackage` static webview method on Android -- Added `setContextMenu`, `clearFocus` methods to webview controller -- Added `onPageCommitVisible` webview event -- Added `androidShouldInterceptRequest`, `androidOnRenderProcessUnresponsive`, `androidOnRenderProcessResponsive`, `androidOnRenderProcessGone`, `androidOnFormResubmission`, `androidOnScaleChanged` Android events -- Added `toString()` method to various classes in order to have a better output instead of simply `Instance of ...` -- Fixed `Print preview is not working? java.lang.IllegalStateException: Can print only from an activity` [#128](https://github.com/pichillilorenzo/flutter_inappwebview/issues/128) -- Fixed `onJsAlert`, `onJsConfirm`, `onJsPrompt` for `InAppBrowser` on Android -- Fixed `onActivityResult` for `InAppBrowser` on Android -- Fixed `InAppBrowser.openWithSystemBrowser crash on iOS` [#358](https://github.com/pichillilorenzo/flutter_inappwebview/issues/358) -- Fixed `Attempt to invoke virtual method 'java.util.Set java.util.HashMap.entrySet()' on a null object reference` [#367](https://github.com/pichillilorenzo/flutter_inappwebview/issues/367) -- Fixed missing `allowsAirPlayForMediaPlayback` iOS webview options implementation - -### BREAKING CHANGES - -- Android `clearClientCertPreferences`, `getSafeBrowsingPrivacyPolicyUrl`, `setSafeBrowsingWhitelist` webview methods are static now -- Removed iOS event `onDidCommit`; it has been renamed to `onPageCommitVisible` and made cross-platform -- `contextMenu` webview attribute is `final` now - -## 3.2.0 - -- Added `ContextMenu` and `ContextMenuItem` classes [#235](https://github.com/pichillilorenzo/flutter_inappwebview/issues/235) -- Added `onCreateContextMenu`, `onHideContextMenu`, `onContextMenuActionItemClicked` context menu events -- Added `contextMenu` to WebView -- Added `disableContextMenu` WebView option -- Added `getSelectedText`, `getHitTestResult` methods to WebView Controller -- Fixed `Confirmation dialog (onbeforeunload) displayed after popped from webview page` [#337](https://github.com/pichillilorenzo/flutter_inappwebview/issues/337) -- Fixed `CookieManager.setCookie` `expiresDate` option -- Fixed `Scrolling not smooth on iOS` [#341](https://github.com/pichillilorenzo/flutter_inappwebview/issues/341) - -### BREAKING CHANGES - -- Renamed `LongPressHitTestResult` to `InAppWebViewHitTestResult`. -- Renamed `LongPressHitTestResultType` to `InAppWebViewHitTestResultType`. - -## 3.1.0 - -- Added `HeadlessInAppWebView` class to be able to use WebView in headless mode -- Added `close`, `addMenuItem`, `addMenuItems` methods to `ChromeSafariBrowser` -- Added `ChromeSafariBrowserMenuItem` class in order to create custom menu item for `ChromeSafariBrowser` -- Fixed `InAppWebView.channel` null when used by `InAppBrowserActivity` on android -- Fixed iOS presentationStyle affecting only dismiss animation [#305](https://github.com/pichillilorenzo/flutter_inappwebview/issues/305) - -### BREAKING CHANGES - -- Renamed `InAppWebViewWidgetOptions` to `InAppWebViewGroupOptions`. - -## 3.0.0 - -- Added `Promise` javascript [polyfill](https://github.com/tildeio/rsvp.js) for webviews that doesn't support it for `window.flutter_inappwebview.callHandler` -- Added `getDefaultUserAgent` static method to `InAppWebViewController` -- Added `onUpdateVisitedHistory`, `onPrint`, `onLongPressHitTestResult` event -- Added `androidOnGeolocationPermissionsHidePrompt` event for Android webview -- Added `iosOnWebContentProcessDidTerminate`, `iosOnDidCommit`, `iosOnDidReceiveServerRedirectForProvisionalNavigation` events for iOS webview -- Added `supportMultipleWindows` webview option for Android -- Added `regexToCancelSubFramesLoading` webview option for Android to cancel subframe requests on `shouldOverrideUrlLoading` event based on a Regular Expression -- Added `getContentHeight`, `zoomBy`, `printCurrentPage`, `getScale` methods -- Added `getOriginalUrl` webview method for Android -- Added `reloadFromOrigin`, `hasOnlySecureContent` webview methods for iOS -- Added `automaticallyAdjustsScrollIndicatorInsets`, `accessibilityIgnoresInvertColors`, `decelerationRate`, `alwaysBounceVertical`, `alwaysBounceHorizontal`, `scrollsToTop`, `isPagingEnabled`, `maximumZoomScale`, `minimumZoomScale` webview options for iOS -- Added `WebStorageManager` class which manages the web storage used by WebView instances -- Added `packageName` [#229](https://github.com/pichillilorenzo/flutter_inappwebview/issues/229) and `keepAliveEnabled` ChromeCustomTab options for Android -- Updated for Flutter 1.12 new Java Embedding API (Android) -- Updated `clearCache` for Android -- Updated default value for `domStorageEnabled` and `databaseEnabled` options to `true` for Android -- Merged "Fixes null error when calling getOptions for InAppBrowser class" [#214](https://github.com/pichillilorenzo/flutter_inappwebview/pull/214) (thanks to [panndoraBoo](https://github.com/panndoraBoo)) -- Merged "Fixes crash onConsoleMessage iOS forced unwrapping" [#228](https://github.com/pichillilorenzo/flutter_inappwebview/pull/228) (thanks to [tokonu](https://github.com/tokonu)) -- Merged "Fix HTTPCookie.secure" [#311](https://github.com/pichillilorenzo/flutter_inappwebview/pull/311) (thanks to [xtyxtyx](https://github.com/xtyxtyx)) -- Merged "Fix config options for Android release builds" [#295](https://github.com/pichillilorenzo/flutter_inappwebview/pull/295) (thanks to [wwwdata](https://github.com/wwwdata)) -- Merged "fix scrollbar on iOS always show if not disable scroll" [#256](https://github.com/pichillilorenzo/flutter_inappwebview/pull/256) (thanks to [phamnhuvu-dev](https://github.com/phamnhuvu-dev)) -- Merged "Fix crash on nil/invalid URL (iOS)" [#262](https://github.com/pichillilorenzo/flutter_inappwebview/pull/262) (thanks to [AlexVincent525](https://github.com/AlexVincent525)) -- Merged "Fix crash when `prompt` was called on Android Q." [#262](https://github.com/pichillilorenzo/flutter_inappwebview/pull/263) (thanks to [AlexVincent525](https://github.com/AlexVincent525)) -- Fix for Android and iOS `InAppBrowser` for some controller methods not exposed. -- Fixed "App Crashes after clicking on dropdown (Using inappwebview)" [#182](https://github.com/pichillilorenzo/flutter_inappwebview/issues/182) -- Fixed "webview can not be released when in ios" [#225](https://github.com/pichillilorenzo/flutter_inappwebview/issues/225). Now the iOS WebView is released from memory when it is disposed from Flutter. -- Fixed "Setting of presentationStyle not working on iOS" [#213](https://github.com/pichillilorenzo/flutter_inappwebview/issues/213) -- Fixed "Android zoom issues" [#270](https://github.com/pichillilorenzo/flutter_inappwebview/issues/270) - -### BREAKING CHANGES - -- Updated `shouldOverrideUrlLoading` event: - - the `url` parameter has been moved inside an instance of `ShouldOverrideUrlLoadingRequest` class - - it has a return type `ShouldOverrideUrlLoadingAction` to allow or cancel navigation instead of cancel every time the request -- Renamed `onTargetBlank` to `onCreateWindow` -- Deleted `useOnTargetBlank` webview option -- Making methods available only for the specific platform more explicit: moved all the webview's controller methods for Android inside `controller.android` and all the webview's controller methods for iOS inside `controller.ios` -- Making events available only for the specific platform more explicit: - - Renamed `onSafeBrowsingHit` to `androidOnSafeBrowsingHit` - - Renamed `onGeolocationPermissionsShowPrompt` to `androidOnGeolocationPermissionsShowPrompt` - - Renamed `onPermissionRequest` to `androidOnPermissionRequest` -- Updated attribute names for `InAppWebViewWidgetOptions`, `InAppBrowserClassOptions` and `ChromeSafariBrowserClassOptions` classes -- Renamed and updated `onNavigationStateChange` to `onUpdateVisitedHistory` -- Renamed all iOS and Android webview options class -- Renamed Chrome Custom Tab `addShareButton` option to `addDefaultShareMenuItem` -- Renamed ChromeSafariBrowser `onLoaded` to `onCompletedInitialLoad` - -## 2.1.0+1 - -- Fix docs - -## 2.1.0 - -- Added `pause` and `resume` methods for Android. -- Added `pauseTimers` and `resumeTimers` methods. -- Added new `historyUrl` optional parameter for `loadData` and `openData` methods and `InAppWebViewInitialData` class. It is used only on Android. -- Fix "problems with onReceivedHttpAuthRequest when initialData is used" [#201](https://github.com/pichillilorenzo/flutter_inappwebview/issues/201) -- Fix "System ui (status bar and navigation bar) doesn't hide automatically" [#202](https://github.com/pichillilorenzo/flutter_inappwebview/issues/202) - -## 2.0.1+1 - -- Fixed error "java.lang.ClassCastException: $Proxy1 cannot be cast to android.view.WindowManagerImpl" on Android when using native alert dialogs - -## 2.0.1 - -- Added `onPermissionRequest` event. This event is fired when the webview is requesting permission to access the specified resources and the permission currently isn't granted or denied (available only on Android). - -## 2.0.0 - -- Merged "Avoid null pointer exception after webview is disposed" [#116](https://github.com/pichillilorenzo/flutter_inappwebview/pull/116) (thanks to [robsonfingo](https://github.com/robsonfingo)) -- Merged "Remove async call in close" [#119](https://github.com/pichillilorenzo/flutter_inappwebview/pull/119) (thanks to [benfingo](https://github.com/benfingo)) -- Merged "Android takeScreenshot does not work properly." [#122](https://github.com/pichillilorenzo/flutter_inappwebview/pull/122) (thanks to [PauloMelo](https://github.com/PauloMelo)) -- Merged "Resolving gradle error." [#144](https://github.com/pichillilorenzo/flutter_inappwebview/pull/144) (thanks to [Klingens13](https://github.com/Klingens13)) -- Merged "Create issue and pull request templates" [#150](https://github.com/pichillilorenzo/flutter_inappwebview/pull/150) (thanks to [deandreamatias](https://github.com/deandreamatias)) -- Merged "Fix abstract method error && swift version error" [#155](https://github.com/pichillilorenzo/flutter_inappwebview/pull/155) (thanks to [AlexVincent525](https://github.com/AlexVincent525)) -- Merged "migrating to swift 5.0" [#162](https://github.com/pichillilorenzo/flutter_inappwebview/pull/162) (thanks to [fattiger00](https://github.com/fattiger00)) -- Merged "Update readme example" [#178](https://github.com/pichillilorenzo/flutter_inappwebview/pull/178) (thanks to [SebastienBtr](https://github.com/SebastienBtr)) -- Merged "handle choose file callback in android" [#183](https://github.com/pichillilorenzo/flutter_inappwebview/pull/183) (thanks to [crazecoder](https://github.com/crazecoder)) -- Merged "add initialScale in android" [#186](https://github.com/pichillilorenzo/flutter_inappwebview/pull/186) (thanks to [crazecoder](https://github.com/crazecoder)) -- Added `horizontalScrollBarEnabled` and `verticalScrollBarEnabled` options to enable/disable the corresponding scrollbar of the WebView [#165](https://github.com/pichillilorenzo/flutter_inappwebview/issues/165) -- Added `onDownloadStart` event and `useOnDownloadStart` option: event fires when the WebView recognizes and starts a downloadable file. -- Added `onLoadResourceCustomScheme` event and `resourceCustomSchemes` option to set custom schemes that WebView must handle to load resources -- Added `onTargetBlank` event and `useOnTargetBlank` option to manage links with `target="_blank"` -- Added `ContentBlocker`, `ContentBlockerTrigger` and `ContentBlockerAction` classes and the `contentBlockers` option that allows to define a set of rules to use to block content in the WebView -- Added new WebView options: `minimumFontSize`, `debuggingEnabled`, `preferredContentMode`, `applicationNameForUserAgent`, `incognito`, `cacheEnabled`, `disableVerticalScroll`, `disableHorizontalScroll` -- Added new Android WebView options: `allowContentAccess`, `allowFileAccess`, `allowFileAccessFromFileURLs`, `allowUniversalAccessFromFileURLs`, `appCachePath`, `blockNetworkImage`, `blockNetworkLoads`, `cacheMode`, `cursiveFontFamily`, `defaultFixedFontSize`, `defaultFontSize`, `defaultTextEncodingName`, `disabledActionModeMenuItems`, `fantasyFontFamily`, `fixedFontFamily`, `forceDark`, `geolocationEnabled`, `layoutAlgorithm`, `loadWithOverviewMode`, `loadsImagesAutomatically`, `minimumLogicalFontSize`, `needInitialFocus`, `offscreenPreRaster`, `sansSerifFontFamily`, `serifFontFamily`, `standardFontFamily`, `saveFormData`, `thirdPartyCookiesEnabled`, `hardwareAcceleration` -- Added new iOS WebView options: `isFraudulentWebsiteWarningEnabled`, `selectionGranularity`, `dataDetectorTypes`, `sharedCookiesEnabled` -- Added `onGeolocationPermissionsShowPrompt` event and `GeolocationPermissionShowPromptResponse` class (available only for Android) -- Added `startSafeBrowsing`, `setSafeBrowsingWhitelist` and `getSafeBrowsingPrivacyPolicyUrl` methods (available only for Android) -- Added `clearSslPreferences` and `clearClientCertPreferences` methods (available only for Android) -- Added `onSafeBrowsingHit` event (available only for Android) -- Added `onJsAlert`, `onJsConfirm` and `onJsPrompt` events to manage javascript popup dialogs -- Added `onReceivedHttpAuthRequest` event -- Added `clearCache`, `scrollTo`, `scrollBy`, `getHtml`, `injectJavascriptFileFromAsset` and `injectCSSFileFromAsset` methods method -- Added `HttpAuthCredentialDatabase` class -- Added `onReceivedServerTrustAuthRequest` and `onReceivedClientCertRequest` events to manage SSL requests -- Added `onFindResultReceived` event, `findAllAsync`, `findNext` and `clearMatches` methods -- Added `shouldInterceptAjaxRequest`, `onAjaxReadyStateChange`, `onAjaxProgress` and `shouldInterceptFetchRequest` events with `useShouldInterceptAjaxRequest` and `useShouldInterceptFetchRequest` webview options -- Added `onNavigationStateChange` and `onLoadHttpError` events -- Fun: added `getTRexRunnerHtml` and `getTRexRunnerCss` methods to get html (with javascript) and css to recreate the Chromium's t-rex runner game - -### BREAKING CHANGES -- Deleted `WebResourceRequest` class -- Updated `WebResourceResponse` class -- Updated `ConsoleMessage` class -- Updated `ConsoleMessageLevel` class -- Updated `onLoadResource` event -- Updated `CookieManager` class -- WebView options are now available with the new corresponding classes: `InAppWebViewOptions`, `AndroidInAppWebViewOptions`, `iOSInAppWebViewOptions`, `InAppBrowserOptions`, `AndroidInAppBrowserOptions`, `iOSInAppBrowserOptions`, `AndroidChromeCustomTabsOptions` and `iOSSafariOptions` -- Renamed `getFavicon` to `getFavicons`, now it returns a list of all favicons (`List`) found -- Renamed `injectScriptFile` to `injectJavascriptFileFromUrl` -- Renamed `injectScriptCode` to `evaluateJavascript` -- Renamed `injectStyleCode` to `injectCSSCode` -- Renamed `injectStyleFile` to `injectCSSFileFromUrl` - -## 1.2.2 - -- Merged "added a shared WKProcessPool for webview instances" [#198](https://github.com/pichillilorenzo/flutter_inappwebview/pull/198) (thanks to [robertcnst](https://github.com/robertcnst)) -- Fixed iOS setCookie. - -## 1.2.1 - -- Merged "Add new option to control the contentMode in Android platform" [#101](https://github.com/pichillilorenzo/flutter_inappwebview/pull/101) (thanks to [DreamBuddy](https://github.com/DreamBuddy)) -- Merged "Fix crash on xcode 10.2" [#107](https://github.com/pichillilorenzo/flutter_inappwebview/pull/107) (thanks to [robsonfingo](https://github.com/robsonfingo)) -- Merged "Remove headers_build_phase from example's Podfile" [#108](https://github.com/pichillilorenzo/flutter_inappwebview/pull/108) (thanks to [robsonfingo](https://github.com/robsonfingo)) -- Fixed "Make html5 video fullscreen" for Android [#43](https://github.com/pichillilorenzo/flutter_inappwebview/issues/43) -- Fixed "AllowsInlineMediaPlayback not working" for iOS [#73](https://github.com/pichillilorenzo/flutter_inappwebview/issues/73) - -## 1.2.0 - -- Merged "Adds a transparentBackground option for iOS and Android" [#86](https://github.com/pichillilorenzo/flutter_inappwebview/pull/86) (thanks to [matthewlloyd](https://github.com/matthewlloyd)) -- Merged "The 'open' method requires an options dictionary" [#87](https://github.com/pichillilorenzo/flutter_inappwebview/pull/87) (thanks to [matthewlloyd](https://github.com/matthewlloyd)) -- Merged "iOS: Call setNeedsLayout() in scrollViewDidScroll()" [#88](https://github.com/pichillilorenzo/flutter_inappwebview/pull/88) (thanks to [matthewlloyd](https://github.com/matthewlloyd)) -- Fixed "java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread." [#98](https://github.com/pichillilorenzo/flutter_inappwebview/issues/98) (thanks to [DreamBuddy](https://github.com/DreamBuddy)) -- Fixed "app force close/crash when enabling zoom and repeatedly changing orientation and zoomin zoomout" [#93](https://github.com/pichillilorenzo/flutter_inappwebview/issues/93) -- Added `displayZoomControls` webview option for Android -- Fixed "Compatibility with other plugins" [#80](https://github.com/pichillilorenzo/flutter_inappwebview/issues/80) - -## 1.1.3 - -- Merged "Add null checks around calls to InAppWebView callbacks" [#85](https://github.com/pichillilorenzo/flutter_inappwebview/pull/85) (thanks to [matthewlloyd](https://github.com/matthewlloyd)) - -## 1.1.2 - -- Fix InAppBrowser crashes the app when i change the page "Lost connection" [#74](https://github.com/pichillilorenzo/flutter_inappwebview/issues/74) -- Fix javascript `...args` parameter of `window.flutter_inappwebview.callHandler()` -- Merged Enable setTextZoom function of Android WebViewSetting [#81](https://github.com/pichillilorenzo/flutter_inappwebview/pull/81) (thanks to [YouCii](https://github.com/YouCii)) -- Merged bug fix for android build: Android dependency 'androidx.core:core' has different version for the compile (1.0.0) and runtime (1.0.1) classpath [#83](https://github.com/pichillilorenzo/flutter_inappwebview/pull/83) (thanks to [cinos1](https://github.com/cinos1)) - -## 1.1.1 - -- Fixed README.md and `addJavaScriptHandler` method documentation - -## 1.1.0 - -- Breaking change for `addJavaScriptHandler` and `removeJavaScriptHandler` methods. -- `addJavaScriptHandler` method can return data to JavaScript using `Promise` [#46](https://github.com/pichillilorenzo/flutter_inappwebview/issues/46) -- added `flutterInAppBrowserPlatformReady` JavaScript event to wait until the platform is ready [#64](https://github.com/pichillilorenzo/flutter_inappwebview/issues/64) - -## 1.0.1 - -- Fixed Unable to load initialFile on iOS #56 -- Some code cleanup - -## 1.0.0 - -Breaking changes: -- Fixed [Flutter AndroidX compatibility](https://flutter.dev/docs/development/packages-and-plugins/androidx-compatibility), the latest version that doesn't use `AndroidX` is `0.6.0` (thanks to [juicycleff](https://github.com/juicycleff)). - -## 0.6.0 - -- added support for **iOS** inline native WebView integrated in the flutter widget tree -- updated example folder (thanks to [marquesinijatinha](https://github.com/marquesinijatinha)) -- Fixed bug where passing null to expiresDate failed (thanks to [Sense545](https://github.com/Sense545)) -- Fixed iOS error: encode resourceURL (thanks to [igtm](https://github.com/igtm)) -- Fixed iOS error: Double value cannot be converted to Int because the result would be greater than Int.max in 32-bit devices (thanks to [huzhiren](https://github.com/huzhiren)) -- Fixed iOS error: problem in ChromeSafariBrowser (thanks to [marquesinijatinha](https://github.com/marquesinijatinha)) -- Fixed Android build error caused by gradle and build gradle versions (thanks to [tje3d](https://github.com/tje3d)) -- Updated `uuid` dependency to `^2.0.0` - -## 0.5.51 - -- updated `pubspec.yaml` -- updated `README.md` - -## 0.5.5 - -- added `getUrl` method for the `InAppWebViewController` class -- added `getTitle` method for the `InAppWebViewController` class -- added `getProgress` method for the `InAppWebViewController` class -- added `getFavicon` method for the `InAppWebViewController` class -- added `onScrollChanged` event for the `InAppWebViewController` and `InAppBrowser` class -- added `onBrowserCreated` event for the `InAppBrowser` class -- added `openData` method for the `InAppBrowser` class -- added `initialData` property for the `InAppWebView` widget - -## 0.5.4 - -- added `WebHistory` and `WebHistoryItem` class -- added `getCopyBackForwardList`, `goBackOrForward`, `canGoBackOrForward` and `goTo` methods for the `InAppWebViewController` class - -## 0.5.3 - -- added `CookieManager` class - -## 0.5.2 - -- fixed some missing `result.success()` on Android and iOS -- added `postUrl()` method for the `InAppWebViewController` class -- added `loadData()` method for the `InAppWebViewController` class - -## 0.5.1 - -- updated README.md - -## 0.5.0 - -- added initial support for Inline WebViews using the `InAppWebView` widget -- added `InAppBrowser.openFile()` method -- added `InAppBrowser.onProgressChanged()` event -- moved `InAppBrowser` WebView related functions on the `InAppWebViewController` class -- added `InAppLocalhostServer` class -- added `InAppWebView.canGoBack()` and `InAppWebView.canGoForward()` methods -- removed `openWithSystemBrowser` and `isLocalFile` option. Now use the corresponding method -- code refactoring - -## 0.4.1 - -- added `InAppBrowser.takeScreenshot()` -- added `InAppBrowser.setOptions()` -- added `InAppBrowser.getOptions()` - -## 0.4.0 - -- removed `target` parameter to `InAppBrowser.open()` method. To open the url on the system browser, use the `openWithSystemBrowser: true` option -- fixes for the `_ChannelManager` private class -- fixed `EXC_BAD_INSTRUCTION` onLoadStart in Swift -- added `openWithSystemBrowser` and `isLocalFile` options -- added `InAppBrowser.openWithSystemBrowser` method -- added `InAppBrowser.openOnLocalhost` method -- added `InAppBrowser.loadFile` method -- added `InAppBrowser.isOpened` method - -## 0.3.2 - -- fixed WebView.storyboard path for iOS - -## 0.3.1 - -- fixed README.md example - -## 0.3.0 - -- fixed WebView.storyboard to deployment target 8.0 -- added `InAppBrowser.onLoadResource()` method. The event fires when the InAppBrowser webview loads a resource -- added `InAppBrowser.addJavaScriptHandler()` and `InAppBrowser.removeJavaScriptHandler()` methods to add/remove javascript message handlers -- removed `keyboardDisplayRequiresUserAction` from iOS available options -- now the `url` parameter of `InAppBrowser.open()` is optional. The default value is `about:blank` - -## 0.2.1 - -- added `InAppBrowser.onConsoleMessage()` method to manage console messages -- fixed `InAppBrowser.injectScriptCode()` method when there is not a return value - -## 0.2.0 - -- added support of Chrome CustomTabs for Android -- added support of SFSafariViewController for iOS -- added the ability to create multiple instances of browsers - -## 0.1.1 - -- updated/added new methods -- updated UI of android/iOS in-app browser -- code cleanup -- added new options when opening the in-app browser - -## 0.0.1 - -Initial release. diff --git a/flutter_inappwebview/LICENSE b/flutter_inappwebview/LICENSE deleted file mode 100755 index 6ccd8da42c..0000000000 --- a/flutter_inappwebview/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2023 Lorenzo Pichilli - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/flutter_inappwebview/README.md b/flutter_inappwebview/README.md deleted file mode 100755 index f6cafe5f44..0000000000 --- a/flutter_inappwebview/README.md +++ /dev/null @@ -1,226 +0,0 @@ -
- -# Flutter InAppWebView Plugin [![Share on Twitter](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Flutter%20InAppBrowser%20plugin!&url=https://github.com/pichillilorenzo/flutter_inappwebview&hashtags=flutter,flutterio,dart,dartlang,webview) [![Share on Facebook](https://img.shields.io/badge/share-facebook-blue.svg?longCache=true&style=flat&colorB=%234267b2)](https://www.facebook.com/sharer/sharer.php?u=https%3A//github.com/pichillilorenzo/flutter_inappwebview) - -![InAppWebView-logo](https://user-images.githubusercontent.com/5956938/195422744-bdcfed16-73f0-4bc9-94ab-ecf10771a1c4.png) - - -[![All Contributors](https://img.shields.io/badge/all_contributors-100-orange.svg?style=flat-square)](#contributors-) - - -[![flutter_inappwebview version](https://img.shields.io/pub/v/flutter_inappwebview?include_prereleases)](https://pub.dartlang.org/packages/flutter_inappwebview) -[![Pub Points](https://img.shields.io/pub/points/flutter_inappwebview)](https://pub.dev/packages/flutter_inappwebview/score) -[![Pub Popularity](https://img.shields.io/pub/popularity/flutter_inappwebview)](https://pub.dev/packages/flutter_inappwebview/score) -[![Pub Likes](https://img.shields.io/pub/likes/flutter_inappwebview)](https://pub.dev/packages/flutter_inappwebview/score) -[![Awesome Flutter](https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square)](https://stackoverflow.com/questions/tagged/flutter-inappwebview) -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](/LICENSE) - -[![Donate to this project](https://img.shields.io/badge/support-donate-yellow.svg)](https://inappwebview.dev/donate/) -[![GitHub forks](https://img.shields.io/github/forks/pichillilorenzo/flutter_inappwebview?style=social)](https://github.com/pichillilorenzo/flutter_inappwebview) -[![GitHub stars](https://img.shields.io/github/stars/pichillilorenzo/flutter_inappwebview?style=social)](https://github.com/pichillilorenzo/flutter_inappwebview) - -###### Supported Platforms - -[![flutter_inappwebview_platform_interface version](https://img.shields.io/pub/v/flutter_inappwebview_platform_interface?include_prereleases&label=Platform%20Interface)](https://pub.dartlang.org/packages/flutter_inappwebview_platform_interface) -[![flutter_inappwebview_android version](https://img.shields.io/pub/v/flutter_inappwebview_android?include_prereleases&label=Android)](https://pub.dartlang.org/packages/flutter_inappwebview_android) -[![flutter_inappwebview_ios version](https://img.shields.io/pub/v/flutter_inappwebview_ios?include_prereleases&label=iOS)](https://pub.dartlang.org/packages/flutter_inappwebview_ios) -[![flutter_inappwebview_macos version](https://img.shields.io/pub/v/flutter_inappwebview_macos?include_prereleases&label=macOS)](https://pub.dartlang.org/packages/flutter_inappwebview_macos) -[![flutter_inappwebview_windows version](https://img.shields.io/pub/v/flutter_inappwebview_windows?include_prereleases&label=Windows)](https://pub.dartlang.org/packages/flutter_inappwebview_windows) -[![flutter_inappwebview_linux version](https://img.shields.io/pub/v/flutter_inappwebview_linux?include_prereleases&label=linux)](https://pub.dartlang.org/packages/flutter_inappwebview_linux) -[![flutter_inappwebview_web version](https://img.shields.io/pub/v/flutter_inappwebview_web?include_prereleases&label=Web)](https://pub.dartlang.org/packages/flutter_inappwebview_web) - -A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window. - -
- -## Articles/Resources - -- [Official documentation: inappwebview.dev/docs](https://inappwebview.dev/docs/intro) -- Read the online [API Reference](https://pub.dartlang.org/documentation/flutter_inappwebview/latest/) to get the **full API documentation**. -- [Official blog: inappwebview.dev/blog](https://inappwebview.dev/blog/) -- Find open source projects on the [Official Showcase page: inappwebview.dev/showcase](https://inappwebview.dev/showcase/) -- Check the [flutter_inappwebview_examples](https://github.com/pichillilorenzo/flutter_inappwebview_examples) repository for project examples -- Check the [flutter_inappwebview/example/integration_test/webview_flutter_test.dart](https://github.com/pichillilorenzo/flutter_inappwebview/blob/master/flutter_inappwebview/example/integration_test/webview_flutter_test.dart) file for other code examples -- [Flutter Browser App](https://github.com/pichillilorenzo/flutter_browser_app): A Full-Featured Mobile Browser App (such as the Google Chrome mobile browser) created using Flutter and the features offered by the flutter_inappwebview plugin - -## Showcase - Who use it - -Check the [Showcase](https://inappwebview.dev/showcase/) page to see an open list of Apps built with **Flutter** and **Flutter InAppWebView**. - -#### Are you using the **Flutter InAppWebView** plugin and would you like to add your App there? - -Send a submission request to the [Submit App](https://inappwebview.dev/submit-app/) page! - -## Requirements - -- Dart sdk: "^3.8.0" -- Flutter: ">=3.32.0" -- Android: `minSdkVersion >= 19`, [AGP](https://developer.android.com/build/releases/gradle-plugin) version `>= 7.3.0` (use [Android Studio - Android Gradle plugin Upgrade Assistant](https://developer.android.com/build/agp-upgrade-assistant) for help) -- iOS 12.0+, Xcode version `>= 15.0` -- MacOS 10.14+: Xcode version `>= 15.0` -- Windows: [NuGet CLI](https://learn.microsoft.com/en-us/nuget/install-nuget-client-tools?tabs=windows#nugetexe-cli) available on your PATH environment variable -- Linux: WPE 2.0 WebKit built - -## Installation - -Add `flutter_inappwebview` as a [dependency in your pubspec.yaml file](https://flutter.io/using-packages/). - -### Platform Installation Setup: -- [Android](https://inappwebview.dev/docs/intro/#setup-android) -- [iOS](https://inappwebview.dev/docs/intro/#setup-ios) -- [macOS](https://inappwebview.dev/docs/intro/#setup-macos) -- [Windows](https://inappwebview.dev/docs/intro/#setup-windows) -- [Web](https://inappwebview.dev/docs/intro/#setup-web) - -## Support - -Did you find this plugin useful? Please consider to [make a donation](https://inappwebview.dev/donate/) to help improve it! - -## Contributors ✨ - -Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Alex Li
Alex Li

💻
1/2
1/2

💻
Christofer Bodin
Christofer Bodin

💻
Matthew Lloyd
Matthew Lloyd

💻
C E
C E

💻
Robson Araujo
Robson Araujo

💻
Ryan
Ryan

💻
CodeEagle
CodeEagle

💻
Tanay Neotia
Tanay Neotia

💻
Jamie Joost
Jamie Joost

💻
Matias de Andrea
Matias de Andrea

💻
YouCii
YouCii

💻
Salnikov Sergey
Salnikov Sergey

💻
Po-Jui Chen
Po-Jui Chen

💻
Manuito
Manuito

💻
setcy
setcy

💻
EArminjon
EArminjon

💻
Ashank Bharati
Ashank Bharati

💻
Michael Chow
Michael Chow

💻
Osvaldo Saez
Osvaldo Saez

💻
rsydor
rsydor

💻
Le Minh Hoang
Le Minh Hoang

💻
Michael Kao
Michael Kao

💻
cloudygeek
cloudygeek

💻
Christoph Eck
Christoph Eck

💻
Ser1ous
Ser1ous

💻
Caleb Jones
Caleb Jones

💻
Saverio Murgia
Saverio Murgia

💻
Trần Đức Tâm
Trần Đức Tâm

💻
Joker
Joker

💻
Yash Chandra Verma
Yash Chandra Verma

💻
Arne Kepp
Arne Kepp

💻
Ömral Cörüt
Ömral Cörüt

💻
LrdHelmchen
LrdHelmchen

💻
Steven Gunanto
Steven Gunanto

💻
Michael Rittmeister
Michael Rittmeister

💻
Akira Aratani
Akira Aratani

💻
Doflatango
Doflatango

💻
Edmund Tay
Edmund Tay

💻
Andrei Diaconu
Andrei Diaconu

💻
Daniel Kao
Daniel Kao

💻
xuty
xuty

💻
Ben Bieker
Ben Bieker

💻
Phạm Như Vũ
Phạm Như Vũ

💻
SebastienBtr
SebastienBtr

💻
NeZha
NeZha

💻
Jan Klinge
Jan Klinge

💻
PauloDurrerMelo
PauloDurrerMelo

💻
benmeemo
benmeemo

💻
cinos
cinos

💻
Rex Raphael
Rex Raphael

💻
Jan Henrik Høiland
Jan Henrik Høiland

💻
Iguchi Tomokatsu
Iguchi Tomokatsu

💻
Jonas Uekötter
Jonas Uekötter

📖 💻
emakar
emakar

💻
liasica
liasica

💻
Eiichiro Adachi
Eiichiro Adachi

💻
Kamil Powałowski
Kamil Powałowski

💻
Akio Yamamoto
Akio Yamamoto

💻
mohenaxiba
mohenaxiba

💻
Ben Anderson
Ben Anderson

💻
Daan Poron
Daan Poron

🛡️
ふぁ
ふぁ

💻
perffecto
perffecto

💻
Chandra Abdul Fattah
Chandra Abdul Fattah

💻
Aleksandar Lugonja
Aleksandar Lugonja

💻
Alexandre Richonnier
Alexandre Richonnier

💻
Sunbreak
Sunbreak

💻
Eric Lee
Eric Lee

📖
KhatibFX
KhatibFX

💻
Guide.inc
Guide.inc

💻
Niraj Nandish
Niraj Nandish

💻
nesquikm
nesquikm

💻
Andreas Gangsø
Andreas Gangsø

💻
Alexandru Terente
Alexandru Terente

💻
Dango Mango
Dango Mango

💻
Max Zimmermann
Max Zimmermann

💻
Alexandru Dochioiu
Alexandru Dochioiu

💻
YumengNevix
YumengNevix

💻
lrorpilla
lrorpilla

💻
Michal Šrůtek
Michal Šrůtek

💻
daisukeueta
daisukeueta

💻
Gray Mackall
Gray Mackall

💻
Pavel Mazhnik
Pavel Mazhnik

💻
nlog (solrin)
nlog (solrin)

💻
Murmurl912
Murmurl912

💻
Benjamin Schulz
Benjamin Schulz

🤔
seal-app
seal-app

💻
Takuya Tominaga
Takuya Tominaga

💻
Sergey
Sergey

💻
yuanbo li
yuanbo li

💻
Ryan Feline
Ryan Feline

💻
Jeff Ward
Jeff Ward

⚠️
Yelzhan Yerkebulan
Yelzhan Yerkebulan

💻
GooRingX
GooRingX

💻
Robodoh
Robodoh

💻
imoyakin
imoyakin

💻
laishere
laishere

💻
Marco Muccinelli
Marco Muccinelli

💻
momadvisor
momadvisor

💻
- - - - - - -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! diff --git a/flutter_inappwebview/analysis_options.yaml b/flutter_inappwebview/analysis_options.yaml deleted file mode 100644 index e2d13ab58a..0000000000 --- a/flutter_inappwebview/analysis_options.yaml +++ /dev/null @@ -1,16 +0,0 @@ -include: package:flutter_lints/flutter.yaml - -linter: - rules: - constant_identifier_names: ignore - deprecated_member_use_from_same_package: ignore - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options -analyzer: - errors: - constant_identifier_names: ignore - deprecated_member_use: ignore - deprecated_member_use_from_same_package: ignore - unnecessary_cast: ignore - unnecessary_import: ignore diff --git a/flutter_inappwebview/build.yaml b/flutter_inappwebview/build.yaml deleted file mode 100644 index e2b3acf338..0000000000 --- a/flutter_inappwebview/build.yaml +++ /dev/null @@ -1,5 +0,0 @@ -targets: - $default: - sources: - exclude: - - example/**.dart diff --git a/flutter_inappwebview/example/.gitignore b/flutter_inappwebview/example/.gitignore deleted file mode 100755 index 4b042de1be..0000000000 --- a/flutter_inappwebview/example/.gitignore +++ /dev/null @@ -1,74 +0,0 @@ -# Miscellaneous -*.class -*.lock -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# Visual Studio Code related -.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -build/ - -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java - -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages - -integration_test/env.dart diff --git a/flutter_inappwebview/example/.metadata b/flutter_inappwebview/example/.metadata deleted file mode 100755 index be82a01709..0000000000 --- a/flutter_inappwebview/example/.metadata +++ /dev/null @@ -1,30 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "8b872868494e429d94fa06dca855c306438b22c0" - channel: "stable" - -project_type: app - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: 8b872868494e429d94fa06dca855c306438b22c0 - base_revision: 8b872868494e429d94fa06dca855c306438b22c0 - - platform: windows - create_revision: 8b872868494e429d94fa06dca855c306438b22c0 - base_revision: 8b872868494e429d94fa06dca855c306438b22c0 - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/flutter_inappwebview/example/README.md b/flutter_inappwebview/example/README.md deleted file mode 100755 index 06eead02ee..0000000000 --- a/flutter_inappwebview/example/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# flutter_inappwebview_example - -Demonstrates how to use the flutter_inappwebview plugin. - -## Getting Started - -For help getting started with Flutter, view our online -[documentation](https://flutter.io/). diff --git a/flutter_inappwebview/example/analysis_options.yaml b/flutter_inappwebview/example/analysis_options.yaml deleted file mode 100644 index b3cbd63470..0000000000 --- a/flutter_inappwebview/example/analysis_options.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - rules: - constant_identifier_names: ignore - deprecated_member_use_from_same_package: ignore - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options -analyzer: - errors: - deprecated_member_use: ignore - deprecated_member_use_from_same_package: ignore - unnecessary_cast: ignore - unnecessary_import: ignore diff --git a/flutter_inappwebview/example/android/.gitignore b/flutter_inappwebview/example/android/.gitignore deleted file mode 100644 index 6f568019d3..0000000000 --- a/flutter_inappwebview/example/android/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties -**/*.keystore -**/*.jks diff --git a/flutter_inappwebview/example/android/app/build.gradle b/flutter_inappwebview/example/android/app/build.gradle deleted file mode 100755 index 17f2a4bfd5..0000000000 --- a/flutter_inappwebview/example/android/app/build.gradle +++ /dev/null @@ -1,74 +0,0 @@ -plugins { - id "com.android.application" - id "kotlin-android" - id "dev.flutter.flutter-gradle-plugin" -} - -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -android { - namespace 'com.pichillilorenzo.flutter_inappwebviewexample' - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - - compileSdkVersion flutter.compileSdkVersion - ndkVersion flutter.ndkVersion - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.pichillilorenzo.flutter_inappwebviewexample" - minSdkVersion flutter.minSdkVersion - targetSdkVersion 36 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - multiDexEnabled true - } - - buildTypes { - release { - // only for com.pichillilorenzo.flutter_inappwebview_android.R.menu.menu_main - minifyEnabled false - shrinkResources false - - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } - - lint { - disable 'InvalidPackage' - } -} - -flutter { - source '../..' -} - -dependencies { - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test:runner:1.6.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' - implementation 'com.google.android.material:material:1.12.0' - implementation 'com.android.support:multidex:1.0.3' -} diff --git a/flutter_inappwebview/example/android/app/src/debug/AndroidManifest.xml b/flutter_inappwebview/example/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index f880684a6a..0000000000 --- a/flutter_inappwebview/example/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/flutter_inappwebview/example/android/app/src/main/AndroidManifest.xml b/flutter_inappwebview/example/android/app/src/main/AndroidManifest.xml deleted file mode 100755 index 3581175eee..0000000000 --- a/flutter_inappwebview/example/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_inappwebview/example/android/app/src/main/java/com/pichillilorenzo/flutterwebviewexample/MainActivity.java b/flutter_inappwebview/example/android/app/src/main/java/com/pichillilorenzo/flutterwebviewexample/MainActivity.java deleted file mode 100755 index 253cc91191..0000000000 --- a/flutter_inappwebview/example/android/app/src/main/java/com/pichillilorenzo/flutterwebviewexample/MainActivity.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.pichillilorenzo.flutterwebviewexample; - -import io.flutter.embedding.android.FlutterActivity; - -public class MainActivity extends FlutterActivity { - -} \ No newline at end of file diff --git a/flutter_inappwebview/example/android/app/src/main/res/drawable-v21/launch_background.xml b/flutter_inappwebview/example/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f3f6..0000000000 --- a/flutter_inappwebview/example/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/flutter_inappwebview/example/android/app/src/main/res/drawable/launch_background.xml b/flutter_inappwebview/example/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100755 index 304732f884..0000000000 --- a/flutter_inappwebview/example/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/flutter_inappwebview/example/android/app/src/main/res/layout/remote_view.xml b/flutter_inappwebview/example/android/app/src/main/res/layout/remote_view.xml deleted file mode 100644 index ae9402472c..0000000000 --- a/flutter_inappwebview/example/android/app/src/main/res/layout/remote_view.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - -
- - - - - - """, - ), - onWebViewCreated: (controller) { - controllerCompleter.complete(controller); - }, - onConsoleMessage: (controller, consoleMessage) { - webMessageCompleter.complete(consoleMessage.message); - }, - onLoadStop: (controller, url) async { - var webMessageChannel = await controller - .createWebMessageChannel(); - var port1 = webMessageChannel!.port1; - var port2 = webMessageChannel.port2; - - await port1.setWebMessageCallback((message) async { - await port1.postMessage( - WebMessage(data: message!.data + " and back"), - ); - }); - await controller.postWebMessage( - message: WebMessage(data: "capturePort", ports: [port2]), - targetOrigin: WebUri("*"), - ); - await controller.evaluateJavascript( - source: "document.getElementById('button').click();", - ); - }, - ), - ), - ); - await controllerCompleter.future; - - final String message = await webMessageCompleter.future; - expect(message, 'JavaScript To Native and back'); - }); - - skippableTestWidgets('WebMessageChannel post ArrayBuffer', ( - WidgetTester tester, - ) async { - final Completer controllerCompleter = - Completer(); - final Completer webMessageCompleter = Completer(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: InAppWebView( - key: GlobalKey(), - initialData: InAppWebViewInitialData( - data: """ - - - - - WebMessageChannel Test - - - -
- - - - - - """, - ), - onWebViewCreated: (controller) { - controllerCompleter.complete(controller); - }, - onConsoleMessage: (controller, consoleMessage) { - webMessageCompleter.complete(consoleMessage.message); - }, - onLoadStop: (controller, url) async { - var webMessageChannel = await controller - .createWebMessageChannel(); - var port1 = webMessageChannel!.port1; - var port2 = webMessageChannel.port2; - - await port1.setWebMessageCallback((message) async { - await port1.postMessage( - WebMessage( - data: utf8.encode(utf8.decode(message!.data) + " and back"), - type: WebMessageType.ARRAY_BUFFER, - ), - ); - }); - await controller.postWebMessage( - message: WebMessage( - data: utf8.encode("capturePort"), - type: WebMessageType.ARRAY_BUFFER, - ports: [port2], - ), - targetOrigin: WebUri("*"), - ); - await controller.evaluateJavascript( - source: "document.getElementById('button').click();", - ); - }, - ), - ), - ); - await controllerCompleter.future; - - final String message = await webMessageCompleter.future; - expect(message, 'JavaScript To Native and back'); - }); - - skippableTestWidgets('WebMessageListener post String', ( - WidgetTester tester, - ) async { - final Completer controllerCompleter = - Completer(); - final Completer pageLoaded = Completer(); - final Completer webMessageCompleter = Completer(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: InAppWebView( - key: GlobalKey(), - onWebViewCreated: (controller) async { - await controller.addWebMessageListener( - WebMessageListener( - jsObjectName: "myTestObj", - allowedOriginRules: Set.from(["https://*.example.com"]), - onPostMessage: - (message, sourceOrigin, isMainFrame, replyProxy) { - if (isMainFrame && - (sourceOrigin.toString() + '/') == - TEST_URL_EXAMPLE.toString()) { - replyProxy.postMessage( - WebMessage(data: message!.data + " and back"), - ); - } else { - replyProxy.postMessage(WebMessage(data: "Nope")); - } - }, - ), - ); - controllerCompleter.complete(controller); - }, - onConsoleMessage: (controller, consoleMessage) { - webMessageCompleter.complete(consoleMessage.message); - }, - onLoadStop: (controller, url) async { - if (url.toString() == TEST_URL_EXAMPLE.toString()) { - pageLoaded.complete(); - } - }, - ), - ), - ); - final controller = await controllerCompleter.future; - await controller.loadUrl(urlRequest: URLRequest(url: TEST_URL_EXAMPLE)); - await pageLoaded.future; - - await controller.evaluateJavascript( - source: """ - myTestObj.addEventListener('message', function(event) { - console.log(event.data); - }); - myTestObj.postMessage('JavaScript To Native'); - """, - ); - - final String message = await webMessageCompleter.future; - expect(message, 'JavaScript To Native and back'); - }); - - skippableTestWidgets('WebMessageListener post ArrayBuffer', ( - WidgetTester tester, - ) async { - final Completer controllerCompleter = - Completer(); - final Completer pageLoaded = Completer(); - final Completer webMessageCompleter = Completer(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: InAppWebView( - key: GlobalKey(), - onWebViewCreated: (controller) async { - await controller.addWebMessageListener( - WebMessageListener( - jsObjectName: "myTestObj", - allowedOriginRules: Set.from(["https://*.example.com"]), - onPostMessage: - (message, sourceOrigin, isMainFrame, replyProxy) { - if (isMainFrame && - (sourceOrigin.toString() + '/') == - TEST_URL_EXAMPLE.toString()) { - replyProxy.postMessage( - WebMessage( - data: utf8.encode( - utf8.decode(message!.data) + " and back", - ), - type: WebMessageType.ARRAY_BUFFER, - ), - ); - } else { - replyProxy.postMessage( - WebMessage( - data: utf8.encode("Nope"), - type: WebMessageType.ARRAY_BUFFER, - ), - ); - } - }, - ), - ); - controllerCompleter.complete(controller); - }, - onConsoleMessage: (controller, consoleMessage) { - webMessageCompleter.complete(consoleMessage.message); - }, - onLoadStop: (controller, url) async { - if (url.toString() == TEST_URL_EXAMPLE.toString()) { - pageLoaded.complete(); - } - }, - ), - ), - ); - final controller = await controllerCompleter.future; - await controller.loadUrl(urlRequest: URLRequest(url: TEST_URL_EXAMPLE)); - await pageLoaded.future; - - await controller.evaluateJavascript( - source: """ - function bufferToString(buffer) { - return String.fromCharCode.apply(null, Array.from(new Uint8Array(buffer))); - } - - function stringToBuffer(value) { - var buffer = new ArrayBuffer(value.length); - var view = new Uint8Array(buffer); - for (var i = 0, length = value.length; i < length; i++) { - view[i] = value.charCodeAt(i); - } - return buffer; - } - - myTestObj.addEventListener('message', function(event) { - console.log(bufferToString(event.data)); - }); - myTestObj.postMessage(stringToBuffer('JavaScript To Native')); - """, - ); - - final String message = await webMessageCompleter.future; - expect(message, 'JavaScript To Native and back'); - }); - }, skip: shouldSkip); -} diff --git a/flutter_inappwebview/example/integration_test/in_app_webview/webview_asset_loader.dart b/flutter_inappwebview/example/integration_test/in_app_webview/webview_asset_loader.dart deleted file mode 100644 index 2e3e992d32..0000000000 --- a/flutter_inappwebview/example/integration_test/in_app_webview/webview_asset_loader.dart +++ /dev/null @@ -1,51 +0,0 @@ -part of 'main.dart'; - -void webViewAssetLoader() { - final shouldSkip = !InAppWebViewSettings.isPropertySupported( - InAppWebViewSettingsProperty.webViewAssetLoader, - ); - - skippableTestWidgets('WebViewAssetLoader', (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - final Completer pageLoaded = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: InAppWebView( - key: GlobalKey(), - initialUrlRequest: URLRequest(url: TEST_WEBVIEW_ASSET_LOADER_URL), - initialSettings: InAppWebViewSettings( - allowFileAccessFromFileURLs: false, - allowUniversalAccessFromFileURLs: false, - allowFileAccess: false, - allowContentAccess: false, - webViewAssetLoader: WebViewAssetLoader( - domain: TEST_WEBVIEW_ASSET_LOADER_DOMAIN, - pathHandlers: [AssetsPathHandler(path: '/assets/')], - ), - ), - onWebViewCreated: (controller) { - controllerCompleter.complete(controller); - }, - onLoadStop: (controller, url) { - pageLoaded.complete(url.toString()); - }, - ), - ), - ); - - final InAppWebViewController controller = await controllerCompleter.future; - final url = await pageLoaded.future; - - expect(url, TEST_WEBVIEW_ASSET_LOADER_URL.toString()); - - expect( - await controller.evaluateJavascript( - source: "document.querySelector('h1').innerHTML", - ), - 'WebViewAssetLoader', - ); - }, skip: shouldSkip); -} diff --git a/flutter_inappwebview/example/integration_test/in_app_webview/webview_windows.dart b/flutter_inappwebview/example/integration_test/in_app_webview/webview_windows.dart deleted file mode 100644 index fe9e441512..0000000000 --- a/flutter_inappwebview/example/integration_test/in_app_webview/webview_windows.dart +++ /dev/null @@ -1,360 +0,0 @@ -part of 'main.dart'; - -void webViewWindows() { - final shouldSkip = !InAppWebView.isPropertySupported( - PlatformWebViewCreationParamsProperty.onCreateWindow, - ); - - skippableGroup('WebView Windows', () { - final shouldSkipTest1 = - kIsWeb || - !InAppWebView.isPropertySupported( - PlatformWebViewCreationParamsProperty.onCreateWindow, - ); - - skippableTestWidgets('onCreateWindow return false', ( - WidgetTester tester, - ) async { - final Completer controllerCompleter = - Completer(); - final Completer pageLoaded = Completer(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: InAppWebView( - key: GlobalKey(), - initialFile: - "test_assets/in_app_webview_on_create_window_test.html", - initialSettings: InAppWebViewSettings( - clearCache: true, - javaScriptCanOpenWindowsAutomatically: true, - ), - onWebViewCreated: (controller) { - controllerCompleter.complete(controller); - }, - onLoadStop: (controller, url) { - if (url!.toString() == TEST_URL_EXAMPLE.toString()) { - pageLoaded.complete(); - } - }, - onCreateWindow: (controller, createNavigationAction) async { - controller.loadUrl(urlRequest: createNavigationAction.request); - return false; - }, - ), - ), - ); - await tester.pump(); - await expectLater(pageLoaded.future, completes); - }, skip: shouldSkipTest1); - - final shouldSkipTest2 = - kIsWeb || - !InAppWebView.isPropertySupported( - PlatformWebViewCreationParamsProperty.windowId, - ); - - skippableTestWidgets('onCreateWindow return true', ( - WidgetTester tester, - ) async { - final Completer controllerCompleter = - Completer(); - final Completer onCreateWindowCompleter = Completer(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: InAppWebView( - key: GlobalKey(), - initialFile: - "test_assets/in_app_webview_on_create_window_test.html", - initialSettings: InAppWebViewSettings( - clearCache: true, - javaScriptCanOpenWindowsAutomatically: true, - supportMultipleWindows: true, - ), - onWebViewCreated: (controller) { - controllerCompleter.complete(controller); - }, - onCreateWindow: (controller, createNavigationAction) async { - onCreateWindowCompleter.complete(createNavigationAction.windowId); - return true; - }, - ), - ), - ); - - await tester.pump(); - - var windowId = await onCreateWindowCompleter.future; - - final Completer windowControllerCompleter = - Completer(); - final Completer windowPageLoaded = Completer(); - final Completer onCloseWindowCompleter = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: InAppWebView( - key: GlobalKey(), - windowId: windowId, - initialSettings: InAppWebViewSettings(clearCache: true), - onWebViewCreated: (controller) { - windowControllerCompleter.complete(controller); - }, - onLoadStop: (controller, url) async { - if (url!.scheme != "about" && !windowPageLoaded.isCompleted) { - windowPageLoaded.complete(url.toString()); - await controller.evaluateJavascript(source: "window.close();"); - } - }, - onCloseWindow: (controller) { - onCloseWindowCompleter.complete(); - }, - ), - ), - ); - - await tester.pump(); - - final String windowUrlLoaded = await windowPageLoaded.future; - - expect(windowUrlLoaded, TEST_URL_EXAMPLE.toString()); - await expectLater(onCloseWindowCompleter.future, completes); - }, skip: shouldSkipTest2); - - final shouldSkipTest3 = - kIsWeb || - !InAppWebView.isPropertySupported( - PlatformWebViewCreationParamsProperty.onCreateWindow, - ); - - skippableTestWidgets( - 'window.open() with target _blank opens in same window', - (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - final StreamController pageLoads = - StreamController.broadcast(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: InAppWebView( - key: GlobalKey(), - onWebViewCreated: (controller) { - controllerCompleter.complete(controller); - }, - initialUrlRequest: URLRequest(url: TEST_URL_ABOUT_BLANK), - initialSettings: InAppWebViewSettings( - javaScriptEnabled: true, - javaScriptCanOpenWindowsAutomatically: true, - ), - onLoadStop: (controller, url) { - pageLoads.add(url!.toString()); - }, - ), - ), - ); - await pageLoads.stream.first; - final InAppWebViewController controller = - await controllerCompleter.future; - - await controller.evaluateJavascript( - source: 'window.open("$TEST_URL_ABOUT_BLANK", "_blank");', - ); - await pageLoads.stream.first; - final String? currentUrl = (await controller.getUrl())?.toString(); - expect(currentUrl, TEST_URL_ABOUT_BLANK.toString()); - - pageLoads.close(); - }, - skip: shouldSkipTest3, - ); - - // on Android, for some reason, it works on an example app but not in this test - final shouldSkipTest4 = - kIsWeb || defaultTargetPlatform == TargetPlatform.android; - skippableTestWidgets('can open new window and go back', ( - WidgetTester tester, - ) async { - final Completer controllerCompleter = - Completer(); - final StreamController pageLoads = - StreamController.broadcast(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: InAppWebView( - key: GlobalKey(), - initialUrlRequest: URLRequest(url: TEST_CROSS_PLATFORM_URL_1), - onWebViewCreated: (controller) { - controllerCompleter.complete(controller); - }, - initialSettings: InAppWebViewSettings( - javaScriptEnabled: true, - javaScriptCanOpenWindowsAutomatically: true, - ), - onLoadStop: (controller, url) { - pageLoads.add(url!.toString()); - }, - ), - ), - ); - - await tester.pump(); - - final InAppWebViewController controller = - await controllerCompleter.future; - - Future waitForUrl(String expectedUrl) async { - await for (final url in pageLoads.stream) { - if (url == expectedUrl) { - return url; - } - } - throw Exception('Stream closed without receiving $expectedUrl'); - } - - // Wait for initial page load - await waitForUrl(TEST_CROSS_PLATFORM_URL_1.toString()); - await controller.evaluateJavascript( - source: 'window.open("$TEST_URL_1", "_blank");', - ); - final currentUrl = await waitForUrl(TEST_URL_1.toString()); - expect(currentUrl, contains(TEST_URL_1.host)); - - await controller.goBack(); - final urlAfterGoBack = await waitForUrl( - TEST_CROSS_PLATFORM_URL_1.toString(), - ); - expect(urlAfterGoBack, contains(TEST_CROSS_PLATFORM_URL_1.host)); - - pageLoads.close(); - }, skip: shouldSkipTest4); - - // Android blocks javascript: URLs opened from iframes for security reasons - final shouldSkipTest5 = defaultTargetPlatform != TargetPlatform.android; - skippableTestWidgets('javascript does not run in parent window', ( - WidgetTester tester, - ) async { - final String iframe = ''' - - - '''; - final String iframeTestBase64 = base64Encode( - const Utf8Encoder().convert(iframe), - ); - - final String openWindowTest = - ''' - - - - XSS test - - - - - - '''; - final String openWindowTestBase64 = base64Encode( - const Utf8Encoder().convert(openWindowTest), - ); - final Completer controllerCompleter = - Completer(); - final Completer pageLoadCompleter = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: InAppWebView( - key: GlobalKey(), - initialUrlRequest: URLRequest( - url: WebUri( - 'data:text/html;charset=utf-8;base64,$openWindowTestBase64', - ), - ), - onWebViewCreated: (controller) { - controllerCompleter.complete(controller); - }, - initialSettings: InAppWebViewSettings( - javaScriptEnabled: true, - javaScriptCanOpenWindowsAutomatically: true, - ), - onLoadStop: (controller, url) { - pageLoadCompleter.complete(); - }, - ), - ), - ); - - final InAppWebViewController controller = - await controllerCompleter.future; - await pageLoadCompleter.future; - - final iframeLoaded = await controller.evaluateJavascript( - source: 'iframeLoaded', - ); - expect(iframeLoaded, true); - - final pElement = await controller.evaluateJavascript( - source: - 'document.querySelector("p") && document.querySelector("p").textContent', - ); - expect(pElement, null); - }, skip: shouldSkipTest5); - - // final shouldSkipTest6 = !kIsWeb; - final shouldSkipTest6 = true; - // on Web, opening a new window during tests makes crash - skippableTestWidgets('onCreateWindow called on Web', ( - WidgetTester tester, - ) async { - final Completer controllerCompleter = - Completer(); - final Completer onCreateWindowCalled = Completer(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: InAppWebView( - key: GlobalKey(), - initialUrlRequest: URLRequest(url: TEST_WEB_PLATFORM_URL_1), - initialSettings: InAppWebViewSettings( - clearCache: true, - javaScriptCanOpenWindowsAutomatically: true, - ), - onWebViewCreated: (controller) { - controllerCompleter.complete(controller); - }, - onCreateWindow: (controller, createNavigationAction) async { - onCreateWindowCalled.complete( - createNavigationAction.request.url.toString(), - ); - return false; - }, - ), - ), - ); - - final InAppWebViewController controller = - await controllerCompleter.future; - await controller.evaluateJavascript( - source: "window.open('$TEST_CROSS_PLATFORM_URL_1');", - ); - - var url = await onCreateWindowCalled.future; - expect(url, TEST_CROSS_PLATFORM_URL_1.toString()); - }, skip: shouldSkipTest6); - }, skip: shouldSkip); -} diff --git a/flutter_inappwebview/example/integration_test/process_global_config/apply.dart b/flutter_inappwebview/example/integration_test/process_global_config/apply.dart deleted file mode 100644 index d980a03fcb..0000000000 --- a/flutter_inappwebview/example/integration_test/process_global_config/apply.dart +++ /dev/null @@ -1,36 +0,0 @@ -part of 'main.dart'; - -void apply() { - final shouldSkip = !ProcessGlobalConfig.isMethodSupported( - PlatformProcessGlobalConfigMethod.apply, - ); - - skippableTestWidgets('apply', (WidgetTester tester) async { - await expectLater( - ProcessGlobalConfig.instance().apply( - settings: ProcessGlobalConfigSettings( - dataDirectorySuffix: - (await WebViewFeature.isStartupFeatureSupported( - WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX, - )) - ? 'suffix_inappwebviewexample' - : null, - directoryBasePaths: - (await WebViewFeature.isStartupFeatureSupported( - WebViewFeature.STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS, - )) - ? ProcessGlobalConfigDirectoryBasePaths( - cacheDirectoryBasePath: - (await getApplicationDocumentsDirectory()).absolute.path + - '/inappwebviewexample/cache', - dataDirectoryBasePath: - (await getApplicationDocumentsDirectory()).absolute.path + - '/inappwebviewexample/data', - ) - : null, - ), - ), - completes, - ); - }, skip: shouldSkip); -} diff --git a/flutter_inappwebview/example/integration_test/process_global_config/main.dart b/flutter_inappwebview/example/integration_test/process_global_config/main.dart deleted file mode 100644 index a3b1825197..0000000000 --- a/flutter_inappwebview/example/integration_test/process_global_config/main.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:path_provider/path_provider.dart'; -import '../util.dart'; - -part 'apply.dart'; - -void main() { - final shouldSkip = !ProcessGlobalConfig.isClassSupported(); - - skippableGroup('Process Global Config', () { - apply(); - }, skip: shouldSkip); -} diff --git a/flutter_inappwebview/example/integration_test/proxy_controller/clear_and_set_proxy_override.dart b/flutter_inappwebview/example/integration_test/proxy_controller/clear_and_set_proxy_override.dart deleted file mode 100644 index c23ecd5363..0000000000 --- a/flutter_inappwebview/example/integration_test/proxy_controller/clear_and_set_proxy_override.dart +++ /dev/null @@ -1,73 +0,0 @@ -part of 'main.dart'; - -void clearAndSetProxyOverride() { - final shouldSkip = !ProxyController.isMethodSupported( - PlatformProxyControllerMethod.setProxyOverride, - ); - - skippableTestWidgets('clear and set proxy override', ( - WidgetTester tester, - ) async { - final Completer controllerCompleter = - Completer(); - final Completer pageLoaded = Completer(); - - var proxyAvailable = - !PlatformWebViewFeature.static().isClassSupported() || - await WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE); - - if (proxyAvailable) { - ProxyController proxyController = ProxyController.instance(); - - await proxyController.clearProxyOverride(); - await proxyController.setProxyOverride( - settings: ProxySettings( - proxyRules: [ProxyRule(url: "${environment["NODE_SERVER_IP"]}:8083")], - ), - ); - } - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: InAppWebView( - key: GlobalKey(), - initialUrlRequest: URLRequest(url: TEST_URL_HTTP_EXAMPLE), - onWebViewCreated: (controller) { - controllerCompleter.complete(controller); - }, - onLoadStop: (controller, url) { - pageLoaded.complete(url!.toString()); - }, - ), - ), - ); - - final InAppWebViewController controller = await controllerCompleter.future; - - await tester.pump(); - - final String url = await pageLoaded.future; - expect(url, TEST_URL_HTTP_EXAMPLE.toString()); - - // The proxy server's req.url returns different values by platform: - // - Android: full URL (http://www.example.com/) - // - macOS/iOS: just the path (/) - final proxyUrl = await controller.evaluateJavascript( - source: "document.getElementById('url').innerHTML;", - ); - expect(proxyUrl, anyOf("/", TEST_URL_HTTP_EXAMPLE.toString())); - expect( - await controller.evaluateJavascript( - source: "document.getElementById('method').innerHTML;", - ), - "GET", - ); - expect( - await controller.evaluateJavascript( - source: "document.getElementById('headers').innerHTML;", - ), - isNotNull, - ); - }, skip: shouldSkip); -} diff --git a/flutter_inappwebview/example/integration_test/proxy_controller/main.dart b/flutter_inappwebview/example/integration_test/proxy_controller/main.dart deleted file mode 100644 index cae5a73cb4..0000000000 --- a/flutter_inappwebview/example/integration_test/proxy_controller/main.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import '../constants.dart'; -import '../env.dart'; -import '../util.dart'; - -part 'clear_and_set_proxy_override.dart'; - -void main() { - final shouldSkip = !ProxyController.isClassSupported(); - - skippableGroup('Proxy Controller', () { - clearAndSetProxyOverride(); - }, skip: shouldSkip); -} diff --git a/flutter_inappwebview/example/integration_test/service_worker_controller/main.dart b/flutter_inappwebview/example/integration_test/service_worker_controller/main.dart deleted file mode 100644 index 0aac846dde..0000000000 --- a/flutter_inappwebview/example/integration_test/service_worker_controller/main.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; -import '../constants.dart'; -import '../util.dart'; - -part 'set_service_worker_client.dart'; -part 'should_intercept_request.dart'; - -void main() { - final shouldSkip = !ServiceWorkerController.isClassSupported(); - - skippableGroup('Service Worker Controller', () { - shouldInterceptRequest(); - setServiceWorkerClient(); - }, skip: shouldSkip); -} diff --git a/flutter_inappwebview/example/integration_test/service_worker_controller/set_service_worker_client.dart b/flutter_inappwebview/example/integration_test/service_worker_controller/set_service_worker_client.dart deleted file mode 100644 index 0e6ca03f37..0000000000 --- a/flutter_inappwebview/example/integration_test/service_worker_controller/set_service_worker_client.dart +++ /dev/null @@ -1,43 +0,0 @@ -part of 'main.dart'; - -void setServiceWorkerClient() { - final shouldSkip = !ServiceWorkerController.isMethodSupported( - PlatformServiceWorkerControllerMethod.setServiceWorkerClient, - ); - - skippableTestWidgets('setServiceWorkerClient to null', ( - WidgetTester tester, - ) async { - final Completer pageLoaded = Completer(); - - var swAvailable = await WebViewFeature.isFeatureSupported( - WebViewFeature.SERVICE_WORKER_BASIC_USAGE, - ); - var swInterceptAvailable = await WebViewFeature.isFeatureSupported( - WebViewFeature.SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST, - ); - - if (swAvailable && swInterceptAvailable) { - ServiceWorkerController serviceWorkerController = - ServiceWorkerController.instance(); - - await serviceWorkerController.setServiceWorkerClient(null); - } - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: InAppWebView( - key: GlobalKey(), - initialUrlRequest: URLRequest(url: TEST_SERVICE_WORKER_URL), - onLoadStop: (controller, url) { - pageLoaded.complete(url!.toString()); - }, - ), - ), - ); - - final String url = await pageLoaded.future; - expect(url, TEST_SERVICE_WORKER_URL.toString()); - }, skip: shouldSkip); -} diff --git a/flutter_inappwebview/example/integration_test/service_worker_controller/should_intercept_request.dart b/flutter_inappwebview/example/integration_test/service_worker_controller/should_intercept_request.dart deleted file mode 100644 index 37f0050b75..0000000000 --- a/flutter_inappwebview/example/integration_test/service_worker_controller/should_intercept_request.dart +++ /dev/null @@ -1,48 +0,0 @@ -part of 'main.dart'; - -void shouldInterceptRequest() { - final shouldSkip = !ServiceWorkerController.isMethodSupported( - PlatformServiceWorkerControllerMethod.setServiceWorkerClient, - ); - - skippableTestWidgets('shouldInterceptRequest', (WidgetTester tester) async { - final Completer completer = Completer(); - - var swAvailable = await WebViewFeature.isFeatureSupported( - WebViewFeature.SERVICE_WORKER_BASIC_USAGE, - ); - var swInterceptAvailable = await WebViewFeature.isFeatureSupported( - WebViewFeature.SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST, - ); - - if (swAvailable && swInterceptAvailable) { - ServiceWorkerController serviceWorkerController = - ServiceWorkerController.instance(); - - await serviceWorkerController.setServiceWorkerClient( - ServiceWorkerClient( - shouldInterceptRequest: (request) async { - if (!completer.isCompleted) { - completer.complete(); - } - return null; - }, - ), - ); - } else { - completer.complete(); - } - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: InAppWebView( - key: GlobalKey(), - initialUrlRequest: URLRequest(url: TEST_SERVICE_WORKER_URL), - ), - ), - ); - - await expectLater(completer.future, completes); - }, skip: shouldSkip); -} diff --git a/flutter_inappwebview/example/integration_test/support_methods/main.dart b/flutter_inappwebview/example/integration_test/support_methods/main.dart deleted file mode 100644 index dc23c8b723..0000000000 --- a/flutter_inappwebview/example/integration_test/support_methods/main.dart +++ /dev/null @@ -1,469 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../util.dart'; - -void main() { - skippableGroup('Support methods', () { - skippableTest('WebMessageChannel support methods are callable', () { - expect( - () => - WebMessageChannel.isClassSupported(platform: defaultTargetPlatform), - returnsNormally, - ); - expect( - () => WebMessageChannel.isMethodSupported( - PlatformWebMessageChannelMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => WebMessageChannel.isPropertySupported( - PlatformWebMessageChannelCreationParamsProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('WebMessageListener support methods are callable', () { - expect( - () => WebMessageListener.isClassSupported( - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => WebMessageListener.isMethodSupported( - PlatformWebMessageListenerMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => WebMessageListener.isPropertySupported( - PlatformWebMessageListenerCreationParamsProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('WebViewEnvironment support methods are callable', () { - expect( - () => WebViewEnvironment.isClassSupported( - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => WebViewEnvironment.isMethodSupported( - PlatformWebViewEnvironmentMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => WebViewEnvironment.isPropertySupported( - PlatformWebViewEnvironmentCreationParamsProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('HeadlessInAppWebView support methods are callable', () { - expect( - () => HeadlessInAppWebView.isClassSupported( - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => HeadlessInAppWebView.isMethodSupported( - PlatformHeadlessInAppWebViewMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => HeadlessInAppWebView.isPropertySupported( - PlatformHeadlessInAppWebViewCreationParamsProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('WebStorage support methods are callable', () { - expect( - () => WebStorage.isClassSupported(platform: defaultTargetPlatform), - returnsNormally, - ); - expect( - () => WebStorage.isMethodSupported( - PlatformWebStorageMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => WebStorage.isPropertySupported( - PlatformWebStorageCreationParamsProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => WebStorage.isPropertySupported( - PlatformWebStorageProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('LocalStorage support methods are callable', () { - expect( - () => LocalStorage.isClassSupported(platform: defaultTargetPlatform), - returnsNormally, - ); - expect( - () => LocalStorage.isMethodSupported( - PlatformLocalStorageMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => LocalStorage.isPropertySupported( - PlatformStorageCreationParamsProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('SessionStorage support methods are callable', () { - expect( - () => SessionStorage.isClassSupported(platform: defaultTargetPlatform), - returnsNormally, - ); - expect( - () => SessionStorage.isMethodSupported( - PlatformSessionStorageMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => SessionStorage.isPropertySupported( - PlatformStorageCreationParamsProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('WebStorageManager support methods are callable', () { - expect( - () => - WebStorageManager.isClassSupported(platform: defaultTargetPlatform), - returnsNormally, - ); - expect( - () => WebStorageManager.isMethodSupported( - PlatformWebStorageManagerMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('PullToRefreshController support methods are callable', () { - expect( - () => PullToRefreshController.isClassSupported( - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => PullToRefreshController.isMethodSupported( - PlatformPullToRefreshControllerMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => PullToRefreshController.isPropertySupported( - PlatformPullToRefreshControllerCreationParamsProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('InAppWebView support methods are callable', () { - expect( - () => InAppWebView.isClassSupported(platform: defaultTargetPlatform), - returnsNormally, - ); - expect( - () => InAppWebView.isPropertySupported( - PlatformInAppWebViewWidgetCreationParamsProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('InAppWebViewSettings support methods are callable', () { - expect( - () => InAppWebViewSettings.isPropertySupported( - InAppWebViewSettingsProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('InAppWebViewController support methods are callable', () { - expect( - () => InAppWebViewController.isClassSupported( - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => InAppWebViewController.isMethodSupported( - PlatformInAppWebViewControllerMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => InAppWebViewController.isPropertySupported( - PlatformInAppWebViewControllerProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('InAppBrowser support methods are callable', () { - expect( - () => InAppBrowser.isClassSupported(platform: defaultTargetPlatform), - returnsNormally, - ); - expect( - () => InAppBrowser.isMethodSupported( - PlatformInAppBrowserMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => InAppBrowser.isPropertySupported( - PlatformInAppBrowserProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('ChromeSafariBrowser support methods are callable', () { - expect( - () => ChromeSafariBrowser.isClassSupported( - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => ChromeSafariBrowser.isMethodSupported( - PlatformChromeSafariBrowserMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('WebAuthenticationSession support methods are callable', () { - expect( - () => WebAuthenticationSession.isClassSupported( - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => WebAuthenticationSession.isMethodSupported( - PlatformWebAuthenticationSessionMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => WebAuthenticationSession.isPropertySupported( - PlatformWebAuthenticationSessionProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('CookieManager support methods are callable', () { - expect( - () => CookieManager.isClassSupported(platform: defaultTargetPlatform), - returnsNormally, - ); - expect( - () => CookieManager.isMethodSupported( - PlatformCookieManagerMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => CookieManager.isPropertySupported( - PlatformCookieManagerCreationParamsProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('ProcessGlobalConfig support methods are callable', () { - expect( - () => ProcessGlobalConfig.isClassSupported( - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => ProcessGlobalConfig.isMethodSupported( - PlatformProcessGlobalConfigMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('ServiceWorkerController support methods are callable', () { - expect( - () => ServiceWorkerController.isClassSupported( - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => ServiceWorkerController.isMethodSupported( - PlatformServiceWorkerControllerMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('ProxyController support methods are callable', () { - expect( - () => ProxyController.isClassSupported(platform: defaultTargetPlatform), - returnsNormally, - ); - expect( - () => ProxyController.isMethodSupported( - PlatformProxyControllerMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('PrintJobController support methods are callable', () { - expect( - () => PrintJobController.isClassSupported( - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => PrintJobController.isMethodSupported( - PlatformPrintJobControllerMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => PrintJobController.isPropertySupported( - PlatformPrintJobControllerCreationParamsProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => PrintJobController.isPropertySupported( - PlatformPrintJobControllerProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('TracingController support methods are callable', () { - expect( - () => - TracingController.isClassSupported(platform: defaultTargetPlatform), - returnsNormally, - ); - expect( - () => TracingController.isMethodSupported( - PlatformTracingControllerMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest('FindInteractionController support methods are callable', () { - expect( - () => FindInteractionController.isClassSupported( - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => FindInteractionController.isMethodSupported( - PlatformFindInteractionControllerMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => FindInteractionController.isPropertySupported( - PlatformFindInteractionControllerCreationParamsProperty.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }); - - skippableTest( - 'HttpAuthCredentialDatabase support methods are callable', - () { - expect( - () => HttpAuthCredentialDatabase.isClassSupported( - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - expect( - () => HttpAuthCredentialDatabase.isMethodSupported( - PlatformHttpAuthCredentialDatabaseMethod.values.first, - platform: defaultTargetPlatform, - ), - returnsNormally, - ); - }, - ); - }); -} diff --git a/flutter_inappwebview/example/integration_test/tracing_controller/main.dart b/flutter_inappwebview/example/integration_test/tracing_controller/main.dart deleted file mode 100644 index 2ba0703cd7..0000000000 --- a/flutter_inappwebview/example/integration_test/tracing_controller/main.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:path_provider/path_provider.dart'; -import '../constants.dart'; -import '../util.dart'; - -part 'start_and_stop.dart'; - -void main() { - final shouldSkip = !TracingController.isClassSupported(); - - skippableGroup('Tracing Controller', () { - startAndStop(); - }, skip: shouldSkip); -} diff --git a/flutter_inappwebview/example/integration_test/tracing_controller/start_and_stop.dart b/flutter_inappwebview/example/integration_test/tracing_controller/start_and_stop.dart deleted file mode 100644 index 3c34e5e89f..0000000000 --- a/flutter_inappwebview/example/integration_test/tracing_controller/start_and_stop.dart +++ /dev/null @@ -1,60 +0,0 @@ -part of 'main.dart'; - -void startAndStop() { - final shouldSkip = - !TracingController.isMethodSupported( - PlatformTracingControllerMethod.start, - ) || - !TracingController.isMethodSupported( - PlatformTracingControllerMethod.stop, - ); - - skippableTestWidgets('start and stop', (WidgetTester tester) async { - final Completer pageLoaded = Completer(); - - final tracingAvailable = await WebViewFeature.isFeatureSupported( - WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE, - ); - - if (!tracingAvailable) { - return; - } - - final tracingController = TracingController.instance(); - expect(await tracingController.isTracing(), false); - await tracingController.start( - settings: TracingSettings( - tracingMode: TracingMode.RECORD_CONTINUOUSLY, - categories: [TracingCategory.CATEGORIES_ANDROID_WEBVIEW, "blink*"], - ), - ); - expect(await tracingController.isTracing(), true); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: InAppWebView( - key: GlobalKey(), - initialUrlRequest: URLRequest(url: TEST_CROSS_PLATFORM_URL_1), - onLoadStop: (controller, url) { - if (!pageLoaded.isCompleted) { - pageLoaded.complete(); - } - }, - ), - ), - ); - - await pageLoaded.future; - - Directory appDocDir = await getApplicationDocumentsDirectory(); - String traceFilePath = - '${appDocDir.path}${Platform.pathSeparator}trace.json'; - expect(await tracingController.stop(filePath: traceFilePath), true); - - expect(File(traceFilePath).existsSync(), true); - - await Future.delayed(Duration(seconds: 2)); - expect(await tracingController.isTracing(), false); - }, skip: shouldSkip); -} diff --git a/flutter_inappwebview/example/integration_test/util.dart b/flutter_inappwebview/example/integration_test/util.dart deleted file mode 100644 index e20980f988..0000000000 --- a/flutter_inappwebview/example/integration_test/util.dart +++ /dev/null @@ -1,199 +0,0 @@ -import 'dart:async'; -import 'dart:collection'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -/// Returns a matcher that matches the isNullOrEmpty property. -const Matcher isNullOrEmpty = _NullOrEmpty(); - -class _NullOrEmpty extends Matcher { - const _NullOrEmpty(); - - @override - bool matches(Object? item, Map matchState) => - item == null || (item as dynamic).isEmpty; - - @override - Description describe(Description description) => - description.add('null or empty'); -} - -void skippableGroup( - Object description, - void Function() body, { - bool skip = false, -}) { - if (!skip) { - group(description.toString(), body, skip: skip); - } else { - print( - 'SKIPPING GROUP "$description" for platform ${defaultTargetPlatform.toString()}', - ); - } -} - -void skippableTest( - Object description, - dynamic Function() body, { - String? testOn, - Timeout? timeout = const Timeout(Duration(seconds: 60)), - bool skip = false, - dynamic tags, - Map? onPlatform, - int? retry, -}) { - if (!skip) { - test( - description.toString(), - body, - testOn: testOn, - timeout: timeout, - skip: skip, - onPlatform: onPlatform, - tags: tags, - retry: retry, - ); - } else { - print( - 'SKIPPING TEST "$description" for platform ${defaultTargetPlatform.toString()}', - ); - } -} - -void skippableTestWidgets( - String description, - WidgetTesterCallback callback, { - bool skip = false, - Timeout? timeout = const Timeout(Duration(seconds: 60)), - bool semanticsEnabled = true, - TestVariant variant = const DefaultTestVariant(), - dynamic tags, -}) { - if (!skip) { - testWidgets( - description, - callback, - skip: skip, - timeout: timeout, - semanticsEnabled: semanticsEnabled, - variant: variant, - tags: tags, - ); - } else { - print( - 'SKIPPING TEST WIDGET "$description" for platform ${defaultTargetPlatform.toString()}', - ); - } -} - -class Foo { - String? bar; - String? baz; - - Foo({this.bar, this.baz}); - - Map toJson() { - return {'bar': this.bar, 'baz': this.baz}; - } -} - -class MyInAppBrowser extends InAppBrowser { - final Completer browserCreated = Completer(); - final Completer firstPageLoaded = Completer(); - final Completer browserClosed = Completer(); - - MyInAppBrowser({ - int? windowId, - UnmodifiableListView? initialUserScripts, - }) : super(windowId: windowId, initialUserScripts: initialUserScripts); - - @override - Future onBrowserCreated() async { - browserCreated.complete(); - } - - @override - void onLoadStop(WebUri? url) { - super.onLoadStop(url); - - if (!firstPageLoaded.isCompleted) { - firstPageLoaded.complete(); - } - } - - @override - void onExit() { - if (!browserClosed.isCompleted) { - browserClosed.complete(); - } - } -} - -class MyChromeSafariBrowser extends ChromeSafariBrowser { - final Completer serviceConnected = Completer(); - final Completer opened = Completer(); - final Completer firstPageLoaded = Completer(); - final Completer closed = Completer(); - final Completer navigationEvent = - Completer(); - final Completer navigationFinished = Completer(); - final Completer messageChannelReady = Completer(); - final Completer postMessageReceived = Completer(); - final Completer relationshipValidationResult = Completer(); - - @override - void onServiceConnected() { - serviceConnected.complete(); - } - - @override - void onOpened() { - opened.complete(); - } - - @override - void onCompletedInitialLoad(didLoadSuccessfully) { - firstPageLoaded.complete(didLoadSuccessfully); - } - - @override - void onNavigationEvent(CustomTabsNavigationEventType? type) { - if (!navigationEvent.isCompleted) { - navigationEvent.complete(type); - } - if (!navigationFinished.isCompleted && - type == CustomTabsNavigationEventType.FINISHED) { - navigationFinished.complete(); - } - } - - @override - void onMessageChannelReady() async { - if (!messageChannelReady.isCompleted) { - messageChannelReady.complete(); - } - } - - @override - void onPostMessage(String message) { - if (!postMessageReceived.isCompleted) { - postMessageReceived.complete(message); - } - } - - @override - void onRelationshipValidationResult( - CustomTabsRelationType? relation, - Uri? requestedOrigin, - bool result, - ) { - relationshipValidationResult.complete(result); - } - - @override - void onClosed() { - closed.complete(); - } -} diff --git a/flutter_inappwebview/example/integration_test/webview_flutter_test.dart b/flutter_inappwebview/example/integration_test/webview_flutter_test.dart deleted file mode 100644 index 86894514b4..0000000000 --- a/flutter_inappwebview/example/integration_test/webview_flutter_test.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:integration_test/integration_test.dart'; - -import 'process_global_config/main.dart' as process_global_config_tests; -import 'in_app_webview/main.dart' as in_app_webview_tests; -import 'find_interaction_controller/main.dart' - as find_interaction_controller_tests; -import 'service_worker_controller/main.dart' as service_worker_controller_tests; -import 'proxy_controller/main.dart' as proxy_controller_tests; -import 'headless_in_app_webview/main.dart' as headless_in_app_webview_tests; -import 'cookie_manager/main.dart' as cookie_manager_tests; -import 'in_app_browser/main.dart' as in_app_browser_tests; -import 'chrome_safari_browser/main.dart' as chrome_safari_browser_tests; -import 'in_app_localhost_server/main.dart' as in_app_localhost_server_tests; -import 'tracing_controller/main.dart' as tracing_controller_tests; -import 'support_methods/main.dart' as support_methods_tests; - -void main() { - IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - - PlatformInAppWebViewController.debugLoggingSettings.usePrint = true; - PlatformInAppWebViewController.debugLoggingSettings.maxLogMessageLength = - 7000; - PlatformInAppBrowser.debugLoggingSettings.usePrint = true; - PlatformInAppBrowser.debugLoggingSettings.maxLogMessageLength = 7000; - PlatformChromeSafariBrowser.debugLoggingSettings.usePrint = true; - PlatformChromeSafariBrowser.debugLoggingSettings.maxLogMessageLength = 7000; - PlatformWebAuthenticationSession.debugLoggingSettings.usePrint = true; - PlatformWebAuthenticationSession.debugLoggingSettings.maxLogMessageLength = - 7000; - PlatformPullToRefreshController.debugLoggingSettings.usePrint = true; - PlatformPullToRefreshController.debugLoggingSettings.maxLogMessageLength = - 7000; - PlatformFindInteractionController.debugLoggingSettings.usePrint = true; - PlatformFindInteractionController.debugLoggingSettings.maxLogMessageLength = - 7000; - - process_global_config_tests.main(); - in_app_webview_tests.main(); - find_interaction_controller_tests.main(); - service_worker_controller_tests.main(); - proxy_controller_tests.main(); - tracing_controller_tests.main(); - headless_in_app_webview_tests.main(); - cookie_manager_tests.main(); - in_app_browser_tests.main(); - chrome_safari_browser_tests.main(); - in_app_localhost_server_tests.main(); - support_methods_tests.main(); -} diff --git a/flutter_inappwebview/example/ios/.gitignore b/flutter_inappwebview/example/ios/.gitignore deleted file mode 100644 index 7a7f9873ad..0000000000 --- a/flutter_inappwebview/example/ios/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -**/dgph -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/flutter_inappwebview/example/ios/Flutter/.last_build_id b/flutter_inappwebview/example/ios/Flutter/.last_build_id deleted file mode 100644 index dcdc357ce0..0000000000 --- a/flutter_inappwebview/example/ios/Flutter/.last_build_id +++ /dev/null @@ -1 +0,0 @@ -f2dc815feb3d720ac2860b728da31698 \ No newline at end of file diff --git a/flutter_inappwebview/example/ios/Flutter/AppFrameworkInfo.plist b/flutter_inappwebview/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100755 index 1dc6cf7652..0000000000 --- a/flutter_inappwebview/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 13.0 - - diff --git a/flutter_inappwebview/example/ios/Flutter/Debug.xcconfig b/flutter_inappwebview/example/ios/Flutter/Debug.xcconfig deleted file mode 100755 index 8ad039b757..0000000000 --- a/flutter_inappwebview/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,4 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" -FLUTTER_BUILD_MODE=debug \ No newline at end of file diff --git a/flutter_inappwebview/example/ios/Flutter/Release.xcconfig b/flutter_inappwebview/example/ios/Flutter/Release.xcconfig deleted file mode 100755 index 88c29144c8..0000000000 --- a/flutter_inappwebview/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/flutter_inappwebview/example/ios/Podfile b/flutter_inappwebview/example/ios/Podfile deleted file mode 100644 index 10f3c9b470..0000000000 --- a/flutter_inappwebview/example/ios/Podfile +++ /dev/null @@ -1,41 +0,0 @@ -# Uncomment this line to define a global platform for your project -platform :ios, '13.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_ios_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_ios_build_settings(target) - end -end diff --git a/flutter_inappwebview/example/ios/Runner.xcodeproj/project.pbxproj b/flutter_inappwebview/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 0a7d1c43e2..0000000000 --- a/flutter_inappwebview/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,759 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 6143FF37290959650014A1FC /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6143FF36290959650014A1FC /* UniformTypeIdentifiers.framework */; }; - 6143FF3A290959650014A1FC /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6143FF39290959650014A1FC /* Media.xcassets */; }; - 6143FF3C290959650014A1FC /* ActionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6143FF3B290959650014A1FC /* ActionViewController.swift */; }; - 6143FF3F290959650014A1FC /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6143FF3D290959650014A1FC /* MainInterface.storyboard */; }; - 6143FF43290959650014A1FC /* test.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 6143FF35290959650014A1FC /* test.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 61FF730023634CA10069C557 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 61FF72FF23634CA10069C557 /* libsqlite3.tbd */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 75018AFBF33C6954B9C375F0 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 86871EBA13742A6D5F3F398B /* Pods_Runner.framework */; }; - 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - EDC1147F21735BC200D2247A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 6143FF41290959650014A1FC /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 97C146E61CF9000F007C117D /* Project object */; - proxyType = 1; - remoteGlobalIDString = 6143FF34290959650014A1FC; - remoteInfo = test; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 6174FE1725CEB74E00A5020C /* Embed Foundation Extensions */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 13; - files = ( - 6143FF43290959650014A1FC /* test.appex in Embed Foundation Extensions */, - ); - name = "Embed Foundation Extensions"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 6143FF35290959650014A1FC /* test.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = test.appex; sourceTree = BUILT_PRODUCTS_DIR; }; - 6143FF36290959650014A1FC /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; }; - 6143FF39290959650014A1FC /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Media.xcassets; sourceTree = ""; }; - 6143FF3B290959650014A1FC /* ActionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionViewController.swift; sourceTree = ""; }; - 6143FF3E290959650014A1FC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; - 6143FF40290959650014A1FC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 61FF72FF23634CA10069C557 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; }; - 61FF730123634DD10069C557 /* flutter_downloader.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = flutter_downloader.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 80ABE07D2023159E36035B32 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 86871EBA13742A6D5F3F398B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - AA4061AE397745454F676BAB /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 6143FF32290959650014A1FC /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 6143FF37290959650014A1FC /* UniformTypeIdentifiers.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, - 61FF730023634CA10069C557 /* libsqlite3.tbd in Frameworks */, - 75018AFBF33C6954B9C375F0 /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 50BAF1DF19E018DDF2B149B9 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 61FF730123634DD10069C557 /* flutter_downloader.framework */, - 61FF72FF23634CA10069C557 /* libsqlite3.tbd */, - 6143FF36290959650014A1FC /* UniformTypeIdentifiers.framework */, - 86871EBA13742A6D5F3F398B /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 6143FF38290959650014A1FC /* test */ = { - isa = PBXGroup; - children = ( - 6143FF39290959650014A1FC /* Media.xcassets */, - 6143FF3B290959650014A1FC /* ActionViewController.swift */, - 6143FF3D290959650014A1FC /* MainInterface.storyboard */, - 6143FF40290959650014A1FC /* Info.plist */, - ); - path = test; - sourceTree = ""; - }; - 7AC6E2111A9BB885C2D9F6EE /* Pods */ = { - isa = PBXGroup; - children = ( - 80ABE07D2023159E36035B32 /* Pods-Runner.debug.xcconfig */, - AA4061AE397745454F676BAB /* Pods-Runner.release.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 6143FF38290959650014A1FC /* test */, - 97C146EF1CF9000F007C117D /* Products */, - 50BAF1DF19E018DDF2B149B9 /* Frameworks */, - 7AC6E2111A9BB885C2D9F6EE /* Pods */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - 6143FF35290959650014A1FC /* test.appex */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 6143FF34290959650014A1FC /* test */ = { - isa = PBXNativeTarget; - buildConfigurationList = 6143FF46290959660014A1FC /* Build configuration list for PBXNativeTarget "test" */; - buildPhases = ( - 6143FF31290959650014A1FC /* Sources */, - 6143FF32290959650014A1FC /* Frameworks */, - 6143FF33290959650014A1FC /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = test; - productName = test; - productReference = 6143FF35290959650014A1FC /* test.appex */; - productType = "com.apple.product-type.app-extension"; - }; - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - DC1BB9CDFB0410A7329D249A /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 6174FE1725CEB74E00A5020C /* Embed Foundation Extensions */, - 97C146EC1CF9000F007C117D /* Resources */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - DFFD8453B8E169BF6BE74B49 /* [CP] Embed Pods Frameworks */, - 1F85D10872C1EEC5B3816B3D /* [CP] Copy Pods Resources */, - ); - buildRules = ( - ); - dependencies = ( - 6143FF42290959650014A1FC /* PBXTargetDependency */, - ); - name = Runner; - packageProductDependencies = ( - 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, - ); - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = YES; - LastSwiftUpdateCheck = 1400; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = "The Chromium Authors"; - TargetAttributes = { - 6143FF34290959650014A1FC = { - CreatedOnToolsVersion = 14.0; - DevelopmentTeam = PFP8UV45Y6; - ProvisioningStyle = Automatic; - }; - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1020; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.BackgroundModes = { - enabled = 1; - }; - }; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, - ); - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - 6143FF34290959650014A1FC /* test */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 6143FF33290959650014A1FC /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 6143FF3A290959650014A1FC /* Media.xcassets in Resources */, - 6143FF3F290959650014A1FC /* MainInterface.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - EDC1147F21735BC200D2247A /* Main.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 1F85D10872C1EEC5B3816B3D /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", - "${PODS_CONFIGURATION_BUILD_DIR}/permission_handler_apple/permission_handler_apple_privacy.bundle", - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/permission_handler_apple_privacy.bundle", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; - }; - DC1BB9CDFB0410A7329D249A /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - DFFD8453B8E169BF6BE74B49 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/flutter_downloader/flutter_downloader.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_downloader.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 6143FF31290959650014A1FC /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 6143FF3C290959650014A1FC /* ActionViewController.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 6143FF42290959650014A1FC /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 6143FF34290959650014A1FC /* test */; - targetProxy = 6143FF41290959650014A1FC /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 6143FF3D290959650014A1FC /* MainInterface.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 6143FF3E290959650014A1FC /* Base */, - ); - name = MainInterface.storyboard; - sourceTree = ""; - }; - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 6143FF44290959660014A1FC /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = PFP8UV45Y6; - GCC_C_LANGUAGE_STANDARD = gnu11; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = test/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = test; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 The Chromium Authors. All rights reserved."; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MARKETING_VERSION = 1.0; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.pichillilorenzo.flutterinappwebview-ios-example5.test"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 6143FF45290959660014A1FC /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = PFP8UV45Y6; - GCC_C_LANGUAGE_STANDARD = gnu11; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = test/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = test; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 The Chromium Authors. All rights reserved."; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MARKETING_VERSION = 1.0; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.pichillilorenzo.flutterinappwebview-ios-example5.test"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_BITCODE = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_BITCODE = NO; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = PFP8UV45Y6; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.pichillilorenzo.flutterinappwebview-ios-example5"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = PFP8UV45Y6; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.pichillilorenzo.flutterinappwebview-ios-example5"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 6143FF46290959660014A1FC /* Build configuration list for PBXNativeTarget "test" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 6143FF44290959660014A1FC /* Debug */, - 6143FF45290959660014A1FC /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { - isa = XCLocalSwiftPackageReference; - relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; - }; -/* End XCLocalSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { - isa = XCSwiftPackageProductDependency; - productName = FlutterGeneratedPluginSwiftPackage; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/flutter_inappwebview/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/flutter_inappwebview/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100755 index 919434a625..0000000000 --- a/flutter_inappwebview/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/flutter_inappwebview/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_inappwebview/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/flutter_inappwebview/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/flutter_inappwebview/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/flutter_inappwebview/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5ea..0000000000 --- a/flutter_inappwebview/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/flutter_inappwebview/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/flutter_inappwebview/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index 571dea19a3..0000000000 --- a/flutter_inappwebview/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,68 +0,0 @@ -{ - "pins" : [ - { - "identity" : "dkcamera", - "kind" : "remoteSourceControl", - "location" : "https://github.com/zhangao0086/DKCamera", - "state" : { - "branch" : "master", - "revision" : "5c691d11014b910aff69f960475d70e65d9dcc96" - } - }, - { - "identity" : "dkimagepickercontroller", - "kind" : "remoteSourceControl", - "location" : "https://github.com/zhangao0086/DKImagePickerController", - "state" : { - "branch" : "4.3.9", - "revision" : "0bdfeacefa308545adde07bef86e349186335915" - } - }, - { - "identity" : "dkphotogallery", - "kind" : "remoteSourceControl", - "location" : "https://github.com/zhangao0086/DKPhotoGallery", - "state" : { - "branch" : "master", - "revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d" - } - }, - { - "identity" : "sdwebimage", - "kind" : "remoteSourceControl", - "location" : "https://github.com/SDWebImage/SDWebImage", - "state" : { - "revision" : "36e79ba485e9bb4d3cd4e3318908866dac5e7b51", - "version" : "5.21.5" - } - }, - { - "identity" : "swift-collections", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-collections.git", - "state" : { - "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", - "version" : "1.3.0" - } - }, - { - "identity" : "swiftygif", - "kind" : "remoteSourceControl", - "location" : "https://github.com/kirualex/SwiftyGif.git", - "state" : { - "revision" : "4430cbc148baa3907651d40562d96325426f409a", - "version" : "5.4.5" - } - }, - { - "identity" : "tocropviewcontroller", - "kind" : "remoteSourceControl", - "location" : "https://github.com/TimOliver/TOCropViewController", - "state" : { - "revision" : "d4a6d8100f4b886fdbc8ae399bf144ff3e9afb7e", - "version" : "2.8.0" - } - } - ], - "version" : 2 -} diff --git a/flutter_inappwebview/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/flutter_inappwebview/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100755 index 851adedd1f..0000000000 --- a/flutter_inappwebview/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_inappwebview/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/flutter_inappwebview/example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100755 index 21a3cc14c7..0000000000 --- a/flutter_inappwebview/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/flutter_inappwebview/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_inappwebview/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100755 index 18d981003d..0000000000 --- a/flutter_inappwebview/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/flutter_inappwebview/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/flutter_inappwebview/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5ea..0000000000 --- a/flutter_inappwebview/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/flutter_inappwebview/example/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved b/flutter_inappwebview/example/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index 571dea19a3..0000000000 --- a/flutter_inappwebview/example/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,68 +0,0 @@ -{ - "pins" : [ - { - "identity" : "dkcamera", - "kind" : "remoteSourceControl", - "location" : "https://github.com/zhangao0086/DKCamera", - "state" : { - "branch" : "master", - "revision" : "5c691d11014b910aff69f960475d70e65d9dcc96" - } - }, - { - "identity" : "dkimagepickercontroller", - "kind" : "remoteSourceControl", - "location" : "https://github.com/zhangao0086/DKImagePickerController", - "state" : { - "branch" : "4.3.9", - "revision" : "0bdfeacefa308545adde07bef86e349186335915" - } - }, - { - "identity" : "dkphotogallery", - "kind" : "remoteSourceControl", - "location" : "https://github.com/zhangao0086/DKPhotoGallery", - "state" : { - "branch" : "master", - "revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d" - } - }, - { - "identity" : "sdwebimage", - "kind" : "remoteSourceControl", - "location" : "https://github.com/SDWebImage/SDWebImage", - "state" : { - "revision" : "36e79ba485e9bb4d3cd4e3318908866dac5e7b51", - "version" : "5.21.5" - } - }, - { - "identity" : "swift-collections", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-collections.git", - "state" : { - "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", - "version" : "1.3.0" - } - }, - { - "identity" : "swiftygif", - "kind" : "remoteSourceControl", - "location" : "https://github.com/kirualex/SwiftyGif.git", - "state" : { - "revision" : "4430cbc148baa3907651d40562d96325426f409a", - "version" : "5.4.5" - } - }, - { - "identity" : "tocropviewcontroller", - "kind" : "remoteSourceControl", - "location" : "https://github.com/TimOliver/TOCropViewController", - "state" : { - "revision" : "d4a6d8100f4b886fdbc8ae399bf144ff3e9afb7e", - "version" : "2.8.0" - } - } - ], - "version" : 2 -} diff --git a/flutter_inappwebview/example/ios/Runner/AppDelegate.swift b/flutter_inappwebview/example/ios/Runner/AppDelegate.swift deleted file mode 100755 index b224a399ef..0000000000 --- a/flutter_inappwebview/example/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,23 +0,0 @@ -import UIKit -import Flutter -//import flutter_downloader - -@UIApplicationMain - -@objc class AppDelegate: FlutterAppDelegate { - - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - //FlutterDownloaderPlugin.setPluginRegistrantCallback(registerPlugins) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} - -//private func registerPlugins(registry: FlutterPluginRegistry) { -// if (!registry.hasPlugin("FlutterDownloaderPlugin")) { -// FlutterDownloaderPlugin.register(with: registry.registrar(forPlugin: "FlutterDownloaderPlugin")!) -// } -//} diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100755 index d36b1fab2d..0000000000 --- a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100755 index 3d43d11e66..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100755 index 28c6bf0301..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100755 index 2ccbfd967d..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100755 index f091b6b0bc..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100755 index 4cde12118d..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100755 index d0ef06e7ed..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100755 index dcdc2306c2..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100755 index 2ccbfd967d..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100755 index c8f9ed8f5c..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100755 index a6d6b8609d..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100755 index a6d6b8609d..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100755 index 75b2d164a5..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100755 index c4df70d39d..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100755 index 6a84f41e14..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100755 index d0e1f58536..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/Contents.json b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/Contents.json deleted file mode 100755 index da4a164c91..0000000000 --- a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100755 index 0bedcf2fd4..0000000000 --- a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100755 index 9da19eacad..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100755 index 9da19eacad..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100755 index 9da19eacad..0000000000 Binary files a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/flutter_inappwebview/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100755 index 89c2725b70..0000000000 --- a/flutter_inappwebview/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/flutter_inappwebview/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/flutter_inappwebview/example/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100755 index e5f47340ef..0000000000 --- a/flutter_inappwebview/example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_inappwebview/example/ios/Runner/Base.lproj/Main.storyboard b/flutter_inappwebview/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100755 index c0688ac0eb..0000000000 --- a/flutter_inappwebview/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_inappwebview/example/ios/Runner/Info.plist b/flutter_inappwebview/example/ios/Runner/Info.plist deleted file mode 100755 index 2f4e465c45..0000000000 --- a/flutter_inappwebview/example/ios/Runner/Info.plist +++ /dev/null @@ -1,82 +0,0 @@ - - - - - CADisableMinimumFrameDurationOnPhone - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - flutter_inappwebview_example - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - NSAllowsArbitraryLoadsInWebContent - - NSAllowsLocalNetworking - - - NSBonjourServices - - _dartobservatory._tcp - - NSCameraUsageDescription - InAppWebView requires access to cam. - NSDocumentsFolderUsageDescription - InAppWebView requires access to documents folder - NSLocalNetworkUsageDescription - Allow Flutter tools on your computer to connect and debug your application. - NSLocationAlwaysAndWhenInUseUsageDescription - Need location - NSLocationAlwaysUsageDescription - Need location - NSLocationWhenInUseUsageDescription - Need location - NSMicrophoneUsageDescription - InAppWebView requires access to mic. - UIApplicationSupportsIndirectInputEvents - - UIBackgroundModes - - fetch - processing - remote-notification - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/flutter_inappwebview/example/ios/Runner/Runner-Bridging-Header.h b/flutter_inappwebview/example/ios/Runner/Runner-Bridging-Header.h deleted file mode 100755 index 308a2a560b..0000000000 --- a/flutter_inappwebview/example/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/flutter_inappwebview/example/ios/test/ActionViewController.swift b/flutter_inappwebview/example/ios/test/ActionViewController.swift deleted file mode 100644 index 09c2917401..0000000000 --- a/flutter_inappwebview/example/ios/test/ActionViewController.swift +++ /dev/null @@ -1,58 +0,0 @@ -// -// ActionViewController.swift -// test -// -// Created by Lorenzo Pichilli on 26/10/22. -// Copyright © 2022 The Chromium Authors. All rights reserved. -// - -import UIKit -import MobileCoreServices -import UniformTypeIdentifiers - -class ActionViewController: UIViewController { - - @IBOutlet weak var imageView: UIImageView! - - override func viewDidLoad() { - super.viewDidLoad() - - // Get the item[s] we're handling from the extension context. - - // For example, look for an image and place it into an image view. - // Replace this with something appropriate for the type[s] your extension supports. - var imageFound = false - for item in self.extensionContext!.inputItems as! [NSExtensionItem] { - for provider in item.attachments! { - if provider.hasItemConformingToTypeIdentifier(UTType.image.identifier) { - // This is an image. We'll load it, then place it in our image view. - weak var weakImageView = self.imageView - provider.loadItem(forTypeIdentifier: UTType.image.identifier, options: nil, completionHandler: { (imageURL, error) in - OperationQueue.main.addOperation { - if let strongImageView = weakImageView { - if let imageURL = imageURL as? URL { - strongImageView.image = UIImage(data: try! Data(contentsOf: imageURL)) - } - } - } - }) - - imageFound = true - break - } - } - - if (imageFound) { - // We only handle one image, so stop looking for more. - break - } - } - } - - @IBAction func done() { - // Return any edited content to the host app. - // This template doesn't do anything, so we just echo the passed in items. - self.extensionContext!.completeRequest(returningItems: self.extensionContext!.inputItems, completionHandler: nil) - } - -} diff --git a/flutter_inappwebview/example/ios/test/Base.lproj/MainInterface.storyboard b/flutter_inappwebview/example/ios/test/Base.lproj/MainInterface.storyboard deleted file mode 100644 index b165d3a9b0..0000000000 --- a/flutter_inappwebview/example/ios/test/Base.lproj/MainInterface.storyboard +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_inappwebview/example/ios/test/Info.plist b/flutter_inappwebview/example/ios/test/Info.plist deleted file mode 100644 index 2c98e4c5ac..0000000000 --- a/flutter_inappwebview/example/ios/test/Info.plist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - NSExtension - - NSExtensionAttributes - - NSExtensionActivationRule - TRUEPREDICATE - NSExtensionServiceAllowsFinderPreviewItem - - NSExtensionServiceAllowsTouchBarItem - - NSExtensionServiceFinderPreviewIconName - NSActionTemplate - NSExtensionServiceTouchBarBezelColorName - TouchBarBezel - NSExtensionServiceTouchBarIconName - NSActionTemplate - - NSExtensionMainStoryboard - MainInterface - NSExtensionPointIdentifier - com.apple.ui-services - - - diff --git a/flutter_inappwebview/example/ios/test/Media.xcassets/Contents.json b/flutter_inappwebview/example/ios/test/Media.xcassets/Contents.json deleted file mode 100644 index 73c00596a7..0000000000 --- a/flutter_inappwebview/example/ios/test/Media.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/flutter_inappwebview/example/ios/test/Media.xcassets/TouchBarBezel.colorset/Contents.json b/flutter_inappwebview/example/ios/test/Media.xcassets/TouchBarBezel.colorset/Contents.json deleted file mode 100644 index 94a9fc2181..0000000000 --- a/flutter_inappwebview/example/ios/test/Media.xcassets/TouchBarBezel.colorset/Contents.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - }, - "colors" : [ - { - "idiom" : "mac", - "color" : { - "reference" : "systemPurpleColor" - } - } - ] -} \ No newline at end of file diff --git a/flutter_inappwebview/example/lib/main.dart b/flutter_inappwebview/example/lib/main.dart deleted file mode 100755 index 6a00f69315..0000000000 --- a/flutter_inappwebview/example/lib/main.dart +++ /dev/null @@ -1,147 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; -import 'package:flutter_inappwebview_example/providers/test_runner.dart'; -import 'package:flutter_inappwebview_example/providers/network_monitor.dart'; -import 'package:flutter_inappwebview_example/models/test_configuration.dart'; -import 'package:flutter_inappwebview_example/screens/platform_info_screen.dart'; -import 'package:flutter_inappwebview_example/screens/webview_tester_screen.dart'; -import 'package:flutter_inappwebview_example/screens/settings_editor_screen.dart'; -import 'package:flutter_inappwebview_example/screens/webview_environment_settings_editor_screen.dart'; -import 'package:flutter_inappwebview_example/screens/storage/cookie_manager_screen.dart'; -import 'package:flutter_inappwebview_example/screens/storage/web_storage_screen.dart'; -import 'package:flutter_inappwebview_example/screens/storage/http_auth_screen.dart'; -import 'package:flutter_inappwebview_example/screens/browsers/inapp_browser_screen.dart'; -import 'package:flutter_inappwebview_example/screens/browsers/chrome_safari_browser_screen.dart'; -import 'package:flutter_inappwebview_example/screens/browsers/headless_webview_screen.dart'; -import 'package:flutter_inappwebview_example/screens/advanced/controllers_screen.dart'; -import 'package:flutter_inappwebview_example/screens/advanced/service_controllers_screen.dart'; -import 'package:flutter_inappwebview_example/screens/advanced/static_methods_screen.dart'; -import 'package:flutter_inappwebview_example/screens/support_matrix/support_matrix_screen.dart'; -import 'package:flutter_inappwebview_example/screens/support_matrix/platform_comparison_screen.dart'; -import 'package:flutter_inappwebview_example/screens/test_automation/test_runner_screen.dart'; -import 'package:flutter_inappwebview_example/screens/test_automation/test_configuration_screen.dart'; -import 'package:flutter_inappwebview_example/utils/test_registry.dart'; - -// import 'package:path_provider/path_provider.dart'; -// import 'package:permission_handler/permission_handler.dart'; - -final localhostServer = InAppLocalhostServer(documentRoot: 'assets'); - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - - // Initialize test registry - TestRegistry.init(); - - // await Permission.camera.request(); - // await Permission.microphone.request(); - // await Permission.storage.request(); - - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { - await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode); - } - - final settingsManager = SettingsManager(); - await settingsManager.init(); - - final testConfigManager = TestConfigurationManager(); - await testConfigManager.init(); - - runApp( - MyApp( - settingsManager: settingsManager, - testConfigManager: testConfigManager, - ), - ); -} - -class MyApp extends StatefulWidget { - const MyApp({ - super.key, - required this.settingsManager, - required this.testConfigManager, - }); - - final SettingsManager settingsManager; - final TestConfigurationManager testConfigManager; - - @override - _MyAppState createState() => _MyAppState(); -} - -class _MyAppState extends State { - @override - void initState() { - super.initState(); - } - - @override - void dispose() { - super.dispose(); - } - - @override - Widget build(BuildContext context) { - // Wrap the app with providers for Phase 1 - return MultiProvider( - providers: [ - ChangeNotifierProvider(create: (_) => EventLogProvider()), - ChangeNotifierProvider.value(value: widget.settingsManager), - ChangeNotifierProvider(create: (_) => TestRunner()), - ChangeNotifierProvider(create: (_) => NetworkMonitor()), - ChangeNotifierProvider.value(value: widget.testConfigManager), - ], - child: _buildMaterialApp(), - ); - } - - Widget _buildMaterialApp() { - return MaterialApp( - title: '${InAppWebView} Test Suite', - theme: ThemeData( - primarySwatch: Colors.blue, - appBarTheme: AppBarTheme( - elevation: 2, - centerTitle: false, - iconTheme: IconThemeData(color: Colors.white), - titleTextStyle: TextStyle( - color: Colors.white, - fontSize: 20, - fontWeight: FontWeight.w500, - ), - ), - useMaterial3: false, - ), - routes: { - '/': (context) => WebViewTesterScreen(), - '/platform-info': (context) => PlatformInfoScreen(), - '/webview-tester': (context) => WebViewTesterScreen(), - '/settings': (context) => SettingsEditorScreen(), - '/environment-settings': (context) => - WebViewEnvironmentSettingsEditorScreen(), - '/storage/cookies': (context) => CookieManagerScreen(), - '/storage/webstorage': (context) => WebStorageScreen(), - '/storage/http-auth': (context) => HttpAuthScreen(), - '/browsers/inapp-browser': (context) => InAppBrowserScreen(), - '/browsers/chrome-safari-browser': (context) => - ChromeSafariBrowserScreen(), - '/browsers/headless': (context) => HeadlessWebViewScreen(), - '/advanced/controllers': (context) => ControllersScreen(), - '/advanced/service-controllers': (context) => - ServiceControllersScreen(), - '/advanced/static-methods': (context) => StaticMethodsScreen(), - '/support-matrix': (context) => SupportMatrixScreen(), - '/platform-comparison': (context) => PlatformComparisonScreen(), - '/test-automation': (context) => TestRunnerScreen(), - '/test-configuration': (context) => TestConfigurationScreen(), - }, - ); - } -} diff --git a/flutter_inappwebview/example/lib/models/environment_setting_definition.dart b/flutter_inappwebview/example/lib/models/environment_setting_definition.dart deleted file mode 100644 index e634ee0e29..0000000000 --- a/flutter_inappwebview/example/lib/models/environment_setting_definition.dart +++ /dev/null @@ -1,91 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; - -/// Enum representing the type of an environment setting. -enum EnvironmentSettingType { - boolean, - string, - stringList, - enumeration, - customSchemeRegistrations, -} - -/// Definition of a single environment setting. -class EnvironmentSettingDefinition { - final String name; - final String description; - final EnvironmentSettingType type; - final dynamic defaultValue; - final List? enumValues; - final String? hint; - final WebViewEnvironmentSettingsProperty property; - - const EnvironmentSettingDefinition({ - required this.name, - required this.description, - required this.type, - this.defaultValue, - this.enumValues, - this.hint, - required this.property, - }); - - static String enumDisplayName(dynamic value) { - if (value == null) return '(none)'; - try { - final dynamic result = (value as dynamic).name(); - if (result is String) return result; - } catch (_) {} - try { - final dynamic result = (value as dynamic).name; - if (result is String) return result; - } catch (_) {} - return value.toString(); - } - - static dynamic enumValueToNative(dynamic value) { - if (value == null) return null; - try { - return (value as dynamic).toNativeValue(); - } catch (_) { - return value; - } - } - - String get key => property.name; - - bool isSupportedOnPlatform(SupportedPlatform platform) { - if (platform == SupportedPlatform.web) return false; - final targetPlatform = platform.targetPlatform; - if (targetPlatform == null) return false; - return WebViewEnvironmentSettings.isPropertySupported( - property, - platform: targetPlatform, - ); - } - - bool get isSupportedOnCurrentPlatform { - if (kIsWeb) return true; - return WebViewEnvironmentSettings.isPropertySupported(property); - } - - /// Platforms that support this setting (web cannot be checked via TargetPlatform). - Set get supportedPlatforms { - return SupportCheckHelper.supportedPlatformsForProperty( - property: property, - checker: (property, {platform}) => - WebViewEnvironmentSettings.isPropertySupported( - property, - platform: platform, - ), - ).where((platform) => platform != SupportedPlatform.web).toSet(); - } - - bool get hasPlatformLimitations { - final nativePlatforms = SupportedPlatform.values.where( - (platform) => platform != SupportedPlatform.web, - ); - return nativePlatforms.any((platform) => !isSupportedOnPlatform(platform)); - } -} diff --git a/flutter_inappwebview/example/lib/models/event_log_entry.dart b/flutter_inappwebview/example/lib/models/event_log_entry.dart deleted file mode 100644 index e8447a55be..0000000000 --- a/flutter_inappwebview/example/lib/models/event_log_entry.dart +++ /dev/null @@ -1,48 +0,0 @@ -/// Event types for logging -enum EventType { - navigation, - javascript, - console, - network, - error, - performance, - storage, - cookies, - messaging, - ui, -} - -/// Represents an event log entry with timestamp and metadata -class EventLogEntry { - final DateTime timestamp; - final EventType eventType; - final String message; - final Map? data; - - const EventLogEntry({ - required this.timestamp, - required this.eventType, - required this.message, - this.data, - }); - - /// Serialize to map - Map toMap() { - return { - 'timestamp': timestamp.millisecondsSinceEpoch, - 'eventType': eventType.name, - 'message': message, - 'data': data, - }; - } - - /// Deserialize from map - factory EventLogEntry.fromMap(Map map) { - return EventLogEntry( - timestamp: DateTime.fromMillisecondsSinceEpoch(map['timestamp'] as int), - eventType: EventType.values.firstWhere((e) => e.name == map['eventType']), - message: map['message'] as String, - data: map['data'] as Map?, - ); - } -} diff --git a/flutter_inappwebview/example/lib/models/navigation_section.dart b/flutter_inappwebview/example/lib/models/navigation_section.dart deleted file mode 100644 index fb41960e85..0000000000 --- a/flutter_inappwebview/example/lib/models/navigation_section.dart +++ /dev/null @@ -1,141 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; - -class NavigationItem { - const NavigationItem({ - required this.title, - required this.icon, - required this.routeName, - this.useReplacement = false, - }); - - final String title; - final IconData icon; - final String routeName; - final bool useReplacement; -} - -class NavigationSection { - const NavigationSection({this.title, required this.items}); - - final String? title; - final List items; -} - -final List defaultNavigationSections = [ - NavigationSection( - items: [ - NavigationItem( - title: 'WebView Tester', - icon: Icons.web, - routeName: '/', - useReplacement: true, - ), - NavigationItem( - title: 'Settings Editor', - icon: Icons.settings, - routeName: '/settings', - ), - NavigationItem( - title: 'Environment Settings', - icon: Icons.memory, - routeName: '/environment-settings', - ), - NavigationItem( - title: 'Platform Info', - icon: Icons.info_outline, - routeName: '/platform-info', - ), - ], - ), - NavigationSection( - title: 'Storage & Cookies', - items: [ - NavigationItem( - title: 'Cookie Manager', - icon: Icons.cookie_outlined, - routeName: '/storage/cookies', - ), - NavigationItem( - title: 'Web Storage', - icon: Icons.storage_outlined, - routeName: '/storage/webstorage', - ), - NavigationItem( - title: 'HTTP Auth Credentials', - icon: Icons.lock_outline, - routeName: '/storage/http-auth', - ), - ], - ), - NavigationSection( - title: 'Browsers', - items: [ - NavigationItem( - title: '$InAppBrowser', - icon: Icons.open_in_browser, - routeName: '/browsers/inapp-browser', - ), - NavigationItem( - title: 'Chrome/Safari Browser', - icon: Icons.public, - routeName: '/browsers/chrome-safari-browser', - ), - NavigationItem( - title: 'Headless WebView', - icon: Icons.visibility_off_outlined, - routeName: '/browsers/headless', - ), - ], - ), - NavigationSection( - title: 'Advanced', - items: [ - NavigationItem( - title: 'Controllers', - icon: Icons.tune, - routeName: '/advanced/controllers', - ), - NavigationItem( - title: 'Service Controllers', - icon: Icons.settings_applications, - routeName: '/advanced/service-controllers', - ), - NavigationItem( - title: 'Static Methods', - icon: Icons.functions, - routeName: '/advanced/static-methods', - ), - ], - ), - NavigationSection( - title: 'Testing', - items: [ - NavigationItem( - title: 'Automated Test Runner', - icon: Icons.science, - routeName: '/test-automation', - ), - NavigationItem( - title: 'Test Configuration', - icon: Icons.tune, - routeName: '/test-configuration', - ), - ], - ), - NavigationSection( - title: 'Documentation', - items: [ - NavigationItem( - title: 'API Support Matrix', - icon: Icons.grid_on, - routeName: '/support-matrix', - ), - NavigationItem( - title: 'Platform Comparison', - icon: Icons.compare_arrows, - routeName: '/platform-comparison', - ), - ], - ), -]; diff --git a/flutter_inappwebview/example/lib/models/network_request.dart b/flutter_inappwebview/example/lib/models/network_request.dart deleted file mode 100644 index e0520676e2..0000000000 --- a/flutter_inappwebview/example/lib/models/network_request.dart +++ /dev/null @@ -1,83 +0,0 @@ -/// Represents a network request with its metadata and response -class NetworkRequest { - final String id; - final String method; - final String url; - final DateTime timestamp; - final Map? headers; - final String? body; - final String? response; - final int? statusCode; - final Duration? duration; - - const NetworkRequest({ - required this.id, - required this.method, - required this.url, - required this.timestamp, - this.headers, - this.body, - this.response, - this.statusCode, - this.duration, - }); - - /// Create a copy with updated fields - NetworkRequest copyWith({ - String? id, - String? method, - String? url, - DateTime? timestamp, - Map? headers, - String? body, - String? response, - int? statusCode, - Duration? duration, - }) { - return NetworkRequest( - id: id ?? this.id, - method: method ?? this.method, - url: url ?? this.url, - timestamp: timestamp ?? this.timestamp, - headers: headers ?? this.headers, - body: body ?? this.body, - response: response ?? this.response, - statusCode: statusCode ?? this.statusCode, - duration: duration ?? this.duration, - ); - } - - /// Serialize to map - Map toMap() { - return { - 'id': id, - 'method': method, - 'url': url, - 'timestamp': timestamp.millisecondsSinceEpoch, - if (headers != null) 'headers': headers, - if (body != null) 'body': body, - if (response != null) 'response': response, - if (statusCode != null) 'statusCode': statusCode, - if (duration != null) 'duration': duration!.inMilliseconds, - }; - } - - /// Deserialize from map - factory NetworkRequest.fromMap(Map map) { - return NetworkRequest( - id: map['id'] as String, - method: map['method'] as String, - url: map['url'] as String, - timestamp: DateTime.fromMillisecondsSinceEpoch(map['timestamp'] as int), - headers: map['headers'] != null - ? Map.from(map['headers'] as Map) - : null, - body: map['body'] as String?, - response: map['response'] as String?, - statusCode: map['statusCode'] as int?, - duration: map['duration'] != null - ? Duration(milliseconds: map['duration'] as int) - : null, - ); - } -} diff --git a/flutter_inappwebview/example/lib/models/performance_metric.dart b/flutter_inappwebview/example/lib/models/performance_metric.dart deleted file mode 100644 index 7e7423eb58..0000000000 --- a/flutter_inappwebview/example/lib/models/performance_metric.dart +++ /dev/null @@ -1,34 +0,0 @@ -/// Represents a performance metric for a WebView operation -class PerformanceMetric { - final String methodName; - final Duration duration; - final DateTime timestamp; - final Map? metadata; - - const PerformanceMetric({ - required this.methodName, - required this.duration, - required this.timestamp, - this.metadata, - }); - - /// Serialize to map - Map toMap() { - return { - 'methodName': methodName, - 'duration': duration.inMilliseconds, - 'timestamp': timestamp.millisecondsSinceEpoch, - 'metadata': metadata, - }; - } - - /// Deserialize from map - factory PerformanceMetric.fromMap(Map map) { - return PerformanceMetric( - methodName: map['methodName'] as String, - duration: Duration(milliseconds: map['duration'] as int), - timestamp: DateTime.fromMillisecondsSinceEpoch(map['timestamp'] as int), - metadata: map['metadata'] as Map?, - ); - } -} diff --git a/flutter_inappwebview/example/lib/models/setting_definition.dart b/flutter_inappwebview/example/lib/models/setting_definition.dart deleted file mode 100644 index 05d835e2d5..0000000000 --- a/flutter_inappwebview/example/lib/models/setting_definition.dart +++ /dev/null @@ -1,90 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; - -/// Enum representing the type of a setting -enum SettingType { boolean, string, integer, double, enumeration } - -/// Definition of a single setting -class SettingDefinition { - final String name; - final String description; - final SettingType type; - final dynamic defaultValue; - final List? enumValues; - - /// The InAppWebViewSettings property for runtime support checking. - /// If provided, use InAppWebViewSettings.isPropertySupported to check platform support. - final InAppWebViewSettingsProperty property; - - const SettingDefinition({ - required this.name, - required this.description, - required this.type, - required this.defaultValue, - this.enumValues, - required this.property, - }); - - static String enumDisplayName(dynamic value) { - if (value == null) return '(none)'; - try { - final dynamic result = (value as dynamic).name(); - if (result is String) return result; - } catch (_) {} - try { - final dynamic result = (value as dynamic).name; - if (result is String) return result; - } catch (_) {} - return value.toString(); - } - - static dynamic enumValueToNative(dynamic value) { - if (value == null) return null; - try { - return (value as dynamic).toNativeValue(); - } catch (_) { - return value; - } - } - - String get key => property.name; - - /// Check if this setting is supported on the given platform. - /// Returns true if no property is specified (assumed to be cross-platform). - /// Note: Web platform is not mapped to TargetPlatform, so it's not checkable. - bool isSupportedOnPlatform(SupportedPlatform platform) { - // Web is not mapped to TargetPlatform in Flutter - if (platform == SupportedPlatform.web) return false; - final targetPlatform = platform.targetPlatform; - if (targetPlatform == null) return false; - return InAppWebViewSettings.isPropertySupported( - property, - platform: targetPlatform, - ); - } - - /// Check if this setting is supported on the current platform. - bool get isSupportedOnCurrentPlatform { - // On web, we can't check without TargetPlatform - if (kIsWeb) return false; - return InAppWebViewSettings.isPropertySupported(property); - } - - /// Get the set of supported platforms for this setting. - /// Note: Web platform cannot be checked via TargetPlatform. - Set get supportedPlatforms { - return SupportedPlatform.values - .where((p) => p != SupportedPlatform.web && isSupportedOnPlatform(p)) - .toSet(); - } - - /// Check if this setting has platform-specific support (not available on all platforms). - bool get hasPlatformLimitations { - // Check if the property is NOT supported on all native platforms - final nativePlatforms = SupportedPlatform.values.where( - (p) => p != SupportedPlatform.web, - ); - return nativePlatforms.any((p) => !isSupportedOnPlatform(p)); - } -} diff --git a/flutter_inappwebview/example/lib/models/settings_profile.dart b/flutter_inappwebview/example/lib/models/settings_profile.dart deleted file mode 100644 index 814cd966b3..0000000000 --- a/flutter_inappwebview/example/lib/models/settings_profile.dart +++ /dev/null @@ -1,88 +0,0 @@ -import 'dart:convert'; - -/// Model for saving/loading InAppWebViewSettings profiles -class SettingsProfile { - final String id; - final String name; - final DateTime createdAt; - final Map settings; - - const SettingsProfile({ - required this.id, - required this.name, - required this.createdAt, - required this.settings, - }); - - /// Create a new profile with a unique ID - factory SettingsProfile.create({ - required String name, - required Map settings, - }) { - return SettingsProfile( - id: DateTime.now().millisecondsSinceEpoch.toString(), - name: name, - createdAt: DateTime.now(), - settings: Map.from(settings), - ); - } - - /// Create a copy with optional modifications - SettingsProfile copyWith({ - String? id, - String? name, - DateTime? createdAt, - Map? settings, - }) { - return SettingsProfile( - id: id ?? this.id, - name: name ?? this.name, - createdAt: createdAt ?? this.createdAt, - settings: settings ?? Map.from(this.settings), - ); - } - - /// Convert to JSON map for serialization - Map toJson() { - return { - 'id': id, - 'name': name, - 'createdAt': createdAt.toIso8601String(), - 'settings': settings, - }; - } - - /// Create from JSON map - factory SettingsProfile.fromJson(Map json) { - return SettingsProfile( - id: json['id'] as String, - name: json['name'] as String, - createdAt: DateTime.parse(json['createdAt'] as String), - settings: Map.from(json['settings'] as Map), - ); - } - - /// Serialize to JSON string - String toJsonString() => jsonEncode(toJson()); - - /// Create from JSON string - factory SettingsProfile.fromJsonString(String jsonString) { - return SettingsProfile.fromJson( - jsonDecode(jsonString) as Map, - ); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - return other is SettingsProfile && other.id == id; - } - - @override - int get hashCode => id.hashCode; - - @override - String toString() { - return 'SettingsProfile(id: $id, name: $name, createdAt: $createdAt, settingsCount: ${settings.length})'; - } -} diff --git a/flutter_inappwebview/example/lib/models/test_case.dart b/flutter_inappwebview/example/lib/models/test_case.dart deleted file mode 100644 index 4d9bfcc915..0000000000 --- a/flutter_inappwebview/example/lib/models/test_case.dart +++ /dev/null @@ -1,78 +0,0 @@ -import 'package:flutter_inappwebview_example/utils/constants.dart'; -import 'package:flutter_inappwebview_example/models/test_result.dart'; - -/// Represents a single test case with metadata and execution logic -class TestCase { - final String id; - final String title; - final String description; - final List supportedPlatforms; - final TestCategory category; - final TestComplexity complexity; - final Future Function() execute; - - const TestCase({ - required this.id, - required this.title, - required this.description, - required this.supportedPlatforms, - required this.category, - required this.complexity, - required this.execute, - }); - - /// Check if this test is supported on the given platform - bool isSupportedOnPlatform(String platform) { - return supportedPlatforms.contains(platform); - } - - /// Serialize to map - Map toMap() { - return { - 'id': id, - 'title': title, - 'description': description, - 'supportedPlatforms': supportedPlatforms, - 'category': category.name, - 'complexity': complexity.name, - }; - } - - /// Deserialize from map - factory TestCase.fromMap(Map map) { - return TestCase( - id: map['id'] as String, - title: map['title'] as String, - description: map['description'] as String, - supportedPlatforms: List.from(map['supportedPlatforms'] as List), - category: TestCategory.values.firstWhere( - (e) => e.name == map['category'], - ), - complexity: TestComplexity.values.firstWhere( - (e) => e.name == map['complexity'], - ), - execute: () async => null, - ); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is TestCase && - other.id == id && - other.title == title && - other.description == description && - other.category == category && - other.complexity == complexity; - } - - @override - int get hashCode { - return id.hashCode ^ - title.hashCode ^ - description.hashCode ^ - category.hashCode ^ - complexity.hashCode; - } -} diff --git a/flutter_inappwebview/example/lib/models/test_configuration.dart b/flutter_inappwebview/example/lib/models/test_configuration.dart deleted file mode 100644 index fbcfb5a3df..0000000000 --- a/flutter_inappwebview/example/lib/models/test_configuration.dart +++ /dev/null @@ -1,1432 +0,0 @@ -import 'dart:convert'; -import 'dart:typed_data'; -import 'package:flutter/foundation.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; -import 'package:flutter_inappwebview_example/utils/constants.dart'; - -/// Specifies which type of WebView to use for test execution -enum TestWebViewType { - /// Use a visible InAppWebView widget for real-time rendering - inAppWebView, - - /// Use a headless WebView for background execution - headless, -} - -/// Specifies how to match the expected result -enum ExpectedResultType { - /// Exact string match - exact, - - /// Contains the expected value (case-sensitive) - contains, - - /// Contains the expected value (case-insensitive) - containsIgnoreCase, - - /// Matches a regular expression pattern - regex, - - /// Result is not null - notNull, - - /// Result is null - isNull, - - /// Result is truthy (not null, not false, not empty) - truthy, - - /// Result is falsy (null, false, or empty) - falsy, - - /// Result type matches (e.g., 'String', 'int', 'Map', 'List') - typeIs, - - /// Result is a non-empty string - notEmpty, - - /// Result is a Map with specific key - hasKey, - - /// Result is a List with specific length - lengthEquals, - - /// Result is a number greater than expected - greaterThan, - - /// Result is a number less than expected - lessThan, - - /// Custom JavaScript expression to validate (receives 'result' variable) - customExpression, - - /// Any result is acceptable (no validation) - any, -} - -/// Represents a custom test step that can be defined by the user -class CustomTestStep { - final String id; - final String name; - final String description; - final TestCategory category; - final CustomTestAction action; - final Map parameters; - - /// The expected result value (interpretation depends on expectedResultType) - final String? expectedResult; - - /// How to match/validate the expected result - final ExpectedResultType expectedResultType; - - final bool enabled; - final int order; - - const CustomTestStep({ - required this.id, - required this.name, - required this.description, - required this.category, - required this.action, - this.parameters = const {}, - this.expectedResult, - this.expectedResultType = ExpectedResultType.any, - this.enabled = true, - this.order = 0, - }); - - CustomTestStep copyWith({ - String? id, - String? name, - String? description, - TestCategory? category, - CustomTestAction? action, - Map? parameters, - String? expectedResult, - ExpectedResultType? expectedResultType, - bool? enabled, - int? order, - }) { - return CustomTestStep( - id: id ?? this.id, - name: name ?? this.name, - description: description ?? this.description, - category: category ?? this.category, - action: action ?? this.action, - parameters: parameters ?? this.parameters, - expectedResult: expectedResult ?? this.expectedResult, - expectedResultType: expectedResultType ?? this.expectedResultType, - enabled: enabled ?? this.enabled, - order: order ?? this.order, - ); - } - - Map toJson() { - return { - 'id': id, - 'name': name, - 'description': description, - 'category': category.name, - 'action': action.toJson(), - 'parameters': parameters, - 'expectedResult': expectedResult, - 'expectedResultType': expectedResultType.name, - 'enabled': enabled, - 'order': order, - }; - } - - factory CustomTestStep.fromJson(Map json) { - return CustomTestStep( - id: json['id'] as String, - name: json['name'] as String, - description: json['description'] as String? ?? '', - category: TestCategory.values.firstWhere( - (c) => c.name == json['category'], - orElse: () => TestCategory.advanced, - ), - action: CustomTestAction.fromJson(json['action'] as Map), - parameters: (json['parameters'] as Map?) ?? {}, - expectedResult: json['expectedResult'] as String?, - expectedResultType: ExpectedResultType.values.firstWhere( - (e) => e.name == json['expectedResultType'], - orElse: () => ExpectedResultType.any, - ), - enabled: json['enabled'] as bool? ?? true, - order: json['order'] as int? ?? 0, - ); - } - - /// Validates a result against the expected result configuration - bool validateResult(dynamic result) { - switch (expectedResultType) { - case ExpectedResultType.any: - return true; - case ExpectedResultType.exact: - return result?.toString() == expectedResult; - case ExpectedResultType.contains: - return result?.toString().contains(expectedResult ?? '') ?? false; - case ExpectedResultType.containsIgnoreCase: - return result?.toString().toLowerCase().contains( - (expectedResult ?? '').toLowerCase(), - ) ?? - false; - case ExpectedResultType.regex: - if (expectedResult == null) return false; - try { - return RegExp(expectedResult!).hasMatch(result?.toString() ?? ''); - } catch (_) { - return false; - } - case ExpectedResultType.notNull: - return result != null; - case ExpectedResultType.isNull: - return result == null; - case ExpectedResultType.truthy: - if (result == null) return false; - if (result is bool) return result; - if (result is String) return result.isNotEmpty; - if (result is num) return result != 0; - if (result is List) return result.isNotEmpty; - if (result is Map) return result.isNotEmpty; - return true; - case ExpectedResultType.falsy: - if (result == null) return true; - if (result is bool) return !result; - if (result is String) return result.isEmpty; - if (result is num) return result == 0; - if (result is List) return result.isEmpty; - if (result is Map) return result.isEmpty; - return false; - case ExpectedResultType.typeIs: - if (expectedResult == null) return false; - final typeName = result.runtimeType.toString(); - return typeName == expectedResult || - typeName.startsWith('${expectedResult}<') || - _matchesSimpleType(result, expectedResult!); - case ExpectedResultType.notEmpty: - if (result == null) return false; - if (result is String) return result.isNotEmpty; - if (result is List) return result.isNotEmpty; - if (result is Map) return result.isNotEmpty; - return true; - case ExpectedResultType.hasKey: - if (result is! Map || expectedResult == null) return false; - return result.containsKey(expectedResult); - case ExpectedResultType.lengthEquals: - if (expectedResult == null) return false; - final expectedLength = int.tryParse(expectedResult!); - if (expectedLength == null) return false; - if (result is List) return result.length == expectedLength; - if (result is String) return result.length == expectedLength; - if (result is Map) return result.length == expectedLength; - return false; - case ExpectedResultType.greaterThan: - if (expectedResult == null) return false; - final expectedNum = num.tryParse(expectedResult!); - if (expectedNum == null || result is! num) return false; - return result > expectedNum; - case ExpectedResultType.lessThan: - if (expectedResult == null) return false; - final expectedNum = num.tryParse(expectedResult!); - if (expectedNum == null || result is! num) return false; - return result < expectedNum; - case ExpectedResultType.customExpression: - // Custom expressions should be handled by the test runner with JavaScript - return true; - } - } - - /// Helper to match simple type names - static bool _matchesSimpleType(dynamic value, String typeName) { - switch (typeName.toLowerCase()) { - case 'string': - return value is String; - case 'int': - case 'integer': - return value is int; - case 'double': - case 'float': - return value is double; - case 'num': - case 'number': - return value is num; - case 'bool': - case 'boolean': - return value is bool; - case 'list': - case 'array': - return value is List; - case 'map': - case 'object': - return value is Map; - default: - return false; - } - } -} - -/// Types of actions that can be performed in a custom test -enum CustomTestActionType { - evaluateJavascript, - loadUrl, - loadHtml, - checkUrl, - checkTitle, - checkElement, - waitForElement, - clickElement, - typeText, - scrollTo, - takeScreenshot, - delay, - - /// Wait for a specific navigation event (onLoadStop, onProgressChanged, etc.) - waitForNavigationEvent, - - /// Execute an InAppWebViewController method - controllerMethod, - custom, -} - -/// Navigation events that can be waited for -enum NavigationEventType { - /// Wait for onLoadStop to fire - onLoadStop, - - /// Wait for onLoadStart to fire - onLoadStart, - - /// Wait for onProgressChanged to reach a specific value - onProgressChanged, - - /// Wait for onPageCommitVisible to fire - onPageCommitVisible, - - /// Wait for onTitleChanged to fire - onTitleChanged, - - /// Wait for onUpdateVisitedHistory to fire - onUpdateVisitedHistory, -} - -/// Represents an action to perform in a custom test -class CustomTestAction { - final CustomTestActionType type; - final String? script; - final String? url; - final String? html; - final String? selector; - final String? text; - final int? x; - final int? y; - final int? delayMs; - final String? customCode; - - /// For controllerMethod action type - the method ID from ControllerMethodsRegistry - final String? methodId; - - /// For controllerMethod action type - the method parameters - final Map? methodParameters; - - /// For waitForNavigationEvent action type - the navigation event to wait for - final NavigationEventType? navigationEvent; - - /// For waitForNavigationEvent with onProgressChanged - the target progress value (0-100) - final int? targetProgress; - - /// For waitForNavigationEvent - comparison operator for progress ('equals', 'greaterThan', 'greaterThanOrEquals') - final String? progressComparison; - - /// For waitForNavigationEvent - optional URL pattern to match (regex or contains) - final String? urlPattern; - - const CustomTestAction({ - required this.type, - this.script, - this.url, - this.html, - this.selector, - this.text, - this.x, - this.y, - this.delayMs, - this.customCode, - this.methodId, - this.methodParameters, - this.navigationEvent, - this.targetProgress, - this.progressComparison, - this.urlPattern, - }); - - Map toJson() { - return { - 'type': type.name, - 'script': script, - 'url': url, - 'html': html, - 'selector': selector, - 'text': text, - 'x': x, - 'y': y, - 'delayMs': delayMs, - 'customCode': customCode, - 'methodId': methodId, - 'methodParameters': _sanitizeParameters(methodParameters), - 'navigationEvent': navigationEvent?.name, - 'targetProgress': targetProgress, - 'progressComparison': progressComparison, - 'urlPattern': urlPattern, - }; - } - - /// Sanitizes parameters for JSON serialization by converting non-JSON-serializable - /// objects to their string representation or null - static Map? _sanitizeParameters( - Map? params, - ) { - if (params == null) return null; - final sanitized = {}; - for (final entry in params.entries) { - sanitized[entry.key] = _sanitizeValue(entry.value); - } - return sanitized; - } - - /// Sanitizes a single value for JSON serialization - static dynamic _sanitizeValue(dynamic value) { - if (value == null) return null; - if (value is String || value is num || value is bool) return value; - if (value is Uint8List) { - // Encode Uint8List as base64 with type marker - return {'_type': 'bytes', 'value': base64.encode(value)}; - } - if (value is ParameterValueHint) { - // Extract the underlying value from ParameterValueHint - // If the underlying value is null, just return null - final innerValue = value.value; - if (innerValue == null) return null; - return _sanitizeValue(innerValue); - } - if (value is List) return value.map(_sanitizeValue).toList(); - if (value is Map) { - return value.map((k, v) => MapEntry(k.toString(), _sanitizeValue(v))); - } - // For non-JSON-serializable objects, convert to string or return null - try { - // Check if the object has a toJson method - if (value is Map) return value; - return value.toString(); - } catch (_) { - return null; - } - } - - /// Deserializes a parameter value, converting special markers back to their original types - static dynamic _deserializeValue(dynamic value) { - if (value == null) return null; - if (value is String || value is num || value is bool) return value; - if (value is List) return value.map(_deserializeValue).toList(); - if (value is Map) { - // Check for special type markers - if (value['_type'] == 'bytes' && value['value'] is String) { - try { - return base64.decode(value['value'] as String); - } catch (_) { - return null; - } - } - // Regular map - recurse into values - return value.map((k, v) => MapEntry(k.toString(), _deserializeValue(v))); - } - return value; - } - - /// Deserializes method parameters from JSON - static Map? _deserializeParameters( - Map? params, - ) { - if (params == null) return null; - final result = {}; - for (final entry in params.entries) { - result[entry.key] = _deserializeValue(entry.value); - } - return result; - } - - factory CustomTestAction.fromJson(Map json) { - return CustomTestAction( - type: CustomTestActionType.values.firstWhere( - (e) => e.name == json['type'], - orElse: () => CustomTestActionType.custom, - ), - script: json['script'] as String?, - url: json['url'] as String?, - html: json['html'] as String?, - selector: json['selector'] as String?, - text: json['text'] as String?, - x: json['x'] as int?, - y: json['y'] as int?, - delayMs: json['delayMs'] as int?, - customCode: json['customCode'] as String?, - methodId: json['methodId'] as String?, - methodParameters: _deserializeParameters( - json['methodParameters'] as Map?, - ), - navigationEvent: json['navigationEvent'] != null - ? NavigationEventType.values.firstWhere( - (e) => e.name == json['navigationEvent'], - orElse: () => NavigationEventType.onLoadStop, - ) - : null, - targetProgress: json['targetProgress'] as int?, - progressComparison: json['progressComparison'] as String?, - urlPattern: json['urlPattern'] as String?, - ); - } - - /// Creates an evaluate JavaScript action - factory CustomTestAction.evaluateJs(String script) { - return CustomTestAction( - type: CustomTestActionType.evaluateJavascript, - script: script, - ); - } - - /// Creates a load URL action - factory CustomTestAction.loadUrl(String url) { - return CustomTestAction(type: CustomTestActionType.loadUrl, url: url); - } - - /// Creates a load HTML action - factory CustomTestAction.loadHtml(String html) { - return CustomTestAction(type: CustomTestActionType.loadHtml, html: html); - } - - /// Creates a check URL action - factory CustomTestAction.checkUrl(String expectedUrl) { - return CustomTestAction( - type: CustomTestActionType.checkUrl, - url: expectedUrl, - ); - } - - /// Creates a check title action - factory CustomTestAction.checkTitle(String expectedTitle) { - return CustomTestAction( - type: CustomTestActionType.checkTitle, - text: expectedTitle, - ); - } - - /// Creates a check element action - factory CustomTestAction.checkElement(String selector) { - return CustomTestAction( - type: CustomTestActionType.checkElement, - selector: selector, - ); - } - - /// Creates a wait for element action - factory CustomTestAction.waitForElement( - String selector, { - int timeoutMs = 5000, - }) { - return CustomTestAction( - type: CustomTestActionType.waitForElement, - selector: selector, - delayMs: timeoutMs, - ); - } - - /// Creates a click element action - factory CustomTestAction.clickElement(String selector) { - return CustomTestAction( - type: CustomTestActionType.clickElement, - selector: selector, - ); - } - - /// Creates a type text action - factory CustomTestAction.typeText(String selector, String text) { - return CustomTestAction( - type: CustomTestActionType.typeText, - selector: selector, - text: text, - ); - } - - /// Creates a scroll to action - factory CustomTestAction.scrollTo(int x, int y) { - return CustomTestAction(type: CustomTestActionType.scrollTo, x: x, y: y); - } - - /// Creates a delay action - factory CustomTestAction.delay(int milliseconds) { - return CustomTestAction( - type: CustomTestActionType.delay, - delayMs: milliseconds, - ); - } - - /// Creates a wait for navigation event action - factory CustomTestAction.waitForNavigationEvent( - NavigationEventType event, { - int? targetProgress, - String? progressComparison, - String? urlPattern, - }) { - return CustomTestAction( - type: CustomTestActionType.waitForNavigationEvent, - navigationEvent: event, - targetProgress: targetProgress, - progressComparison: progressComparison, - urlPattern: urlPattern, - ); - } - - /// Creates a controller method action to execute an InAppWebViewController method - factory CustomTestAction.controllerMethod( - String methodId, { - Map? parameters, - }) { - return CustomTestAction( - type: CustomTestActionType.controllerMethod, - methodId: methodId, - methodParameters: parameters, - ); - } -} - -/// Represents a complete test configuration that can be saved and loaded -class TestConfiguration { - final String id; - final String name; - final String description; - final DateTime createdAt; - final DateTime modifiedAt; - final List customSteps; - final Map> testOrdering; // category -> list of test IDs - final Set enabledBuiltInTests; - final Map metadata; - - /// The type of WebView to use for test execution - final TestWebViewType webViewType; - - /// Initial URL to load before running tests (optional) - final String? initialUrl; - - /// Width of the headless WebView in pixels (default: 1920) - final double headlessWidth; - - /// Height of the headless WebView in pixels (default: 1080) - final double headlessHeight; - - const TestConfiguration({ - required this.id, - required this.name, - this.description = '', - required this.createdAt, - required this.modifiedAt, - this.customSteps = const [], - this.testOrdering = const {}, - this.enabledBuiltInTests = const {}, - this.metadata = const {}, - this.webViewType = TestWebViewType.inAppWebView, - this.initialUrl, - this.headlessWidth = 1920, - this.headlessHeight = 1080, - }); - - TestConfiguration copyWith({ - String? id, - String? name, - String? description, - DateTime? createdAt, - DateTime? modifiedAt, - List? customSteps, - Map>? testOrdering, - Set? enabledBuiltInTests, - Map? metadata, - TestWebViewType? webViewType, - String? initialUrl, - double? headlessWidth, - double? headlessHeight, - }) { - return TestConfiguration( - id: id ?? this.id, - name: name ?? this.name, - description: description ?? this.description, - createdAt: createdAt ?? this.createdAt, - modifiedAt: modifiedAt ?? DateTime.now(), - customSteps: customSteps ?? this.customSteps, - testOrdering: testOrdering ?? this.testOrdering, - enabledBuiltInTests: enabledBuiltInTests ?? this.enabledBuiltInTests, - metadata: metadata ?? this.metadata, - webViewType: webViewType ?? this.webViewType, - initialUrl: initialUrl ?? this.initialUrl, - headlessWidth: headlessWidth ?? this.headlessWidth, - headlessHeight: headlessHeight ?? this.headlessHeight, - ); - } - - Map toJson() { - return { - 'id': id, - 'name': name, - 'description': description, - 'createdAt': createdAt.toIso8601String(), - 'modifiedAt': modifiedAt.toIso8601String(), - 'customSteps': customSteps.map((s) => s.toJson()).toList(), - 'testOrdering': testOrdering, - 'enabledBuiltInTests': enabledBuiltInTests.toList(), - 'metadata': metadata, - 'webViewType': webViewType.name, - 'initialUrl': initialUrl, - 'headlessWidth': headlessWidth, - 'headlessHeight': headlessHeight, - }; - } - - factory TestConfiguration.fromJson(Map json) { - return TestConfiguration( - id: json['id'] as String, - name: json['name'] as String, - description: json['description'] as String? ?? '', - createdAt: DateTime.parse(json['createdAt'] as String), - modifiedAt: DateTime.parse(json['modifiedAt'] as String), - customSteps: - (json['customSteps'] as List?) - ?.map((s) => CustomTestStep.fromJson(s as Map)) - .toList() ?? - [], - testOrdering: - (json['testOrdering'] as Map?)?.map( - (k, v) => MapEntry(k, (v as List).cast()), - ) ?? - {}, - enabledBuiltInTests: - (json['enabledBuiltInTests'] as List?) - ?.cast() - .toSet() ?? - {}, - metadata: (json['metadata'] as Map?) ?? {}, - webViewType: TestWebViewType.values.firstWhere( - (e) => e.name == json['webViewType'], - orElse: () => TestWebViewType.inAppWebView, - ), - initialUrl: json['initialUrl'] as String?, - headlessWidth: (json['headlessWidth'] as num?)?.toDouble() ?? 1920, - headlessHeight: (json['headlessHeight'] as num?)?.toDouble() ?? 1080, - ); - } - - /// Creates an empty default configuration - factory TestConfiguration.empty({String? name}) { - final now = DateTime.now(); - return TestConfiguration( - id: 'config_${now.millisecondsSinceEpoch}', - name: name ?? 'Default Configuration', - createdAt: now, - modifiedAt: now, - ); - } - - /// Creates a default configuration with common test steps - factory TestConfiguration.defaultConfig() { - final now = DateTime.now(); - return TestConfiguration( - id: 'default_config', - name: 'Default Test Configuration', - description: 'Default configuration with common test scenarios', - createdAt: now, - modifiedAt: now, - customSteps: _buildDefaultTestSteps(), - webViewType: TestWebViewType.inAppWebView, - initialUrl: 'https://example.com', - ); - } - - /// Build default test steps covering common scenarios - static List _buildDefaultTestSteps() { - int order = 0; - return [ - // ============================================================ - // NAVIGATION TESTS - // ============================================================ - CustomTestStep( - id: 'nav_load_url', - name: 'Load URL', - description: 'Load a test URL and verify navigation', - category: TestCategory.navigation, - action: CustomTestAction.controllerMethod( - 'loadUrl', - parameters: {'url': 'https://example.com'}, - ), - order: order++, - ), - CustomTestStep( - id: 'nav_get_url', - name: 'Get Current URL', - description: 'Retrieve and verify the current URL', - category: TestCategory.navigation, - action: CustomTestAction.controllerMethod('getUrl'), - expectedResultType: ExpectedResultType.notNull, - order: order++, - ), - CustomTestStep( - id: 'nav_load_data', - name: 'Load HTML Data', - description: 'Load HTML content directly into WebView', - category: TestCategory.navigation, - action: CustomTestAction.controllerMethod( - 'loadData', - parameters: { - 'data': '

Test Page

', - 'mimeType': 'text/html', - 'encoding': 'utf-8', - 'baseUrl': 'https://example.com', - }, - ), - order: order++, - ), - CustomTestStep( - id: 'nav_reload', - name: 'Reload Page', - description: 'Reload the current page', - category: TestCategory.navigation, - action: CustomTestAction.controllerMethod('reload'), - order: order++, - ), - CustomTestStep( - id: 'nav_can_go_back', - name: 'Can Go Back', - description: 'Check if navigation history allows going back', - category: TestCategory.navigation, - action: CustomTestAction.controllerMethod('canGoBack'), - expectedResultType: ExpectedResultType.notNull, - order: order++, - ), - CustomTestStep( - id: 'nav_can_go_forward', - name: 'Can Go Forward', - description: 'Check if navigation history allows going forward', - category: TestCategory.navigation, - action: CustomTestAction.controllerMethod('canGoForward'), - expectedResultType: ExpectedResultType.notNull, - order: order++, - ), - CustomTestStep( - id: 'nav_go_back', - name: 'Go Back', - description: 'Navigate back in history', - category: TestCategory.navigation, - action: CustomTestAction.controllerMethod('goBack'), - order: order++, - ), - CustomTestStep( - id: 'nav_go_forward', - name: 'Go Forward', - description: 'Navigate forward in history', - category: TestCategory.navigation, - action: CustomTestAction.controllerMethod('goForward'), - order: order++, - ), - CustomTestStep( - id: 'nav_stop_loading', - name: 'Stop Loading', - description: 'Stop the current page loading', - category: TestCategory.navigation, - action: CustomTestAction.controllerMethod('stopLoading'), - order: order++, - ), - - // ============================================================ - // CONTENT/PAGE INFO TESTS - // ============================================================ - CustomTestStep( - id: 'content_get_title', - name: 'Get Page Title', - description: 'Retrieve the current page title', - category: TestCategory.content, - action: CustomTestAction.controllerMethod('getTitle'), - order: order++, - ), - CustomTestStep( - id: 'content_get_html', - name: 'Get HTML Source', - description: 'Retrieve the page HTML source', - category: TestCategory.content, - action: CustomTestAction.controllerMethod('getHtml'), - expectedResultType: ExpectedResultType.notEmpty, - order: order++, - ), - CustomTestStep( - id: 'content_get_progress', - name: 'Get Loading Progress', - description: 'Get the current page loading progress', - category: TestCategory.content, - action: CustomTestAction.controllerMethod('getProgress'), - expectedResultType: ExpectedResultType.notNull, - order: order++, - ), - CustomTestStep( - id: 'content_get_favicons', - name: 'Get Favicons', - description: 'Get page favicon URLs', - category: TestCategory.content, - action: CustomTestAction.controllerMethod('getFavicons'), - order: order++, - ), - CustomTestStep( - id: 'content_get_original_url', - name: 'Get Original URL', - description: 'Get the original URL before any redirects', - category: TestCategory.content, - action: CustomTestAction.controllerMethod('getOriginalUrl'), - order: order++, - ), - - // ============================================================ - // JAVASCRIPT TESTS - // ============================================================ - CustomTestStep( - id: 'js_evaluate_simple', - name: 'Evaluate Simple JS', - description: 'Execute simple JavaScript expression', - category: TestCategory.javascript, - action: CustomTestAction.controllerMethod( - 'evaluateJavascript', - parameters: {'source': '1 + 1'}, - ), - expectedResult: '2', - expectedResultType: ExpectedResultType.contains, - order: order++, - ), - CustomTestStep( - id: 'js_evaluate_string', - name: 'Evaluate JS String', - description: 'Execute JavaScript returning a string', - category: TestCategory.javascript, - action: CustomTestAction.controllerMethod( - 'evaluateJavascript', - parameters: {'source': '"Hello" + " " + "World"'}, - ), - expectedResult: 'Hello World', - expectedResultType: ExpectedResultType.exact, - order: order++, - ), - CustomTestStep( - id: 'js_evaluate_document_title', - name: 'Get Document Title via JS', - description: 'Execute JavaScript to get document title', - category: TestCategory.javascript, - action: CustomTestAction.controllerMethod( - 'evaluateJavascript', - parameters: {'source': 'document.title'}, - ), - order: order++, - ), - CustomTestStep( - id: 'js_evaluate_object', - name: 'Evaluate JS Object', - description: 'Execute JavaScript returning an object', - category: TestCategory.javascript, - action: CustomTestAction.controllerMethod( - 'evaluateJavascript', - parameters: {'source': 'JSON.stringify({name: "test", value: 42})'}, - ), - expectedResultType: ExpectedResultType.notEmpty, - order: order++, - ), - CustomTestStep( - id: 'js_call_async', - name: 'Call Async JavaScript', - description: 'Execute async JavaScript with await', - category: TestCategory.javascript, - action: CustomTestAction.controllerMethod( - 'callAsyncJavaScript', - parameters: { - 'functionBody': ''' - await new Promise(resolve => setTimeout(resolve, 100)); - return "async result"; - ''', - }, - ), - order: order++, - ), - CustomTestStep( - id: 'js_inject_css', - name: 'Inject CSS Code', - description: 'Inject CSS styles into the page', - category: TestCategory.javascript, - action: CustomTestAction.controllerMethod( - 'injectCSSCode', - parameters: { - 'source': 'body { background-color: #f0f0f0 !important; }', - }, - ), - order: order++, - ), - - // ============================================================ - // SCROLL TESTS - // ============================================================ - CustomTestStep( - id: 'scroll_to', - name: 'Scroll To Position', - description: 'Scroll to a specific position', - category: TestCategory.advanced, - action: CustomTestAction.controllerMethod( - 'scrollTo', - parameters: {'x': 0, 'y': 100}, - ), - order: order++, - ), - CustomTestStep( - id: 'scroll_by', - name: 'Scroll By Offset', - description: 'Scroll by a relative offset', - category: TestCategory.advanced, - action: CustomTestAction.controllerMethod( - 'scrollBy', - parameters: {'x': 0, 'y': 50}, - ), - order: order++, - ), - CustomTestStep( - id: 'scroll_get_x', - name: 'Get Scroll X', - description: 'Get horizontal scroll position', - category: TestCategory.advanced, - action: CustomTestAction.controllerMethod('getScrollX'), - expectedResultType: ExpectedResultType.notNull, - order: order++, - ), - CustomTestStep( - id: 'scroll_get_y', - name: 'Get Scroll Y', - description: 'Get vertical scroll position', - category: TestCategory.advanced, - action: CustomTestAction.controllerMethod('getScrollY'), - expectedResultType: ExpectedResultType.notNull, - order: order++, - ), - - // ============================================================ - // SCREENSHOT & PRINT TESTS - // ============================================================ - CustomTestStep( - id: 'screenshot_take', - name: 'Take Screenshot', - description: 'Capture a screenshot of the WebView', - category: TestCategory.advanced, - action: CustomTestAction.controllerMethod('takeScreenshot'), - expectedResultType: ExpectedResultType.notNull, - order: order++, - ), - - // ============================================================ - // SECURITY TESTS - // ============================================================ - CustomTestStep( - id: 'security_is_secure_context', - name: 'Check Secure Context', - description: 'Verify if the page is in a secure context (HTTPS)', - category: TestCategory.advanced, - action: CustomTestAction.controllerMethod('isSecureContext'), - expectedResultType: ExpectedResultType.notNull, - order: order++, - ), - CustomTestStep( - id: 'security_get_certificate', - name: 'Get SSL Certificate', - description: 'Retrieve SSL certificate information', - category: TestCategory.advanced, - action: CustomTestAction.controllerMethod('getCertificate'), - order: order++, - ), - - // ============================================================ - // STORAGE TESTS - COOKIES - // ============================================================ - CustomTestStep( - id: 'storage_set_cookie', - name: 'Set Cookie', - description: 'Set a test cookie', - category: TestCategory.storage, - action: CustomTestAction.evaluateJs(''' - document.cookie = "test_cookie=test_value; path=/"; - document.cookie; - '''), - expectedResultType: ExpectedResultType.contains, - expectedResult: 'test_cookie', - order: order++, - ), - CustomTestStep( - id: 'storage_get_cookies', - name: 'Get Cookies via JS', - description: 'Retrieve cookies using JavaScript', - category: TestCategory.storage, - action: CustomTestAction.evaluateJs('document.cookie'), - order: order++, - ), - - // ============================================================ - // STORAGE TESTS - LOCAL STORAGE - // ============================================================ - CustomTestStep( - id: 'storage_local_set', - name: 'LocalStorage Set Item', - description: 'Set an item in localStorage', - category: TestCategory.storage, - action: CustomTestAction.evaluateJs(''' - localStorage.setItem("test_key", "test_value"); - localStorage.getItem("test_key"); - '''), - expectedResult: 'test_value', - expectedResultType: ExpectedResultType.exact, - order: order++, - ), - CustomTestStep( - id: 'storage_local_get', - name: 'LocalStorage Get Item', - description: 'Get an item from localStorage', - category: TestCategory.storage, - action: CustomTestAction.evaluateJs('localStorage.getItem("test_key")'), - order: order++, - ), - CustomTestStep( - id: 'storage_local_remove', - name: 'LocalStorage Remove Item', - description: 'Remove an item from localStorage', - category: TestCategory.storage, - action: CustomTestAction.evaluateJs(''' - localStorage.removeItem("test_key"); - localStorage.getItem("test_key"); - '''), - expectedResultType: ExpectedResultType.isNull, - order: order++, - ), - - // ============================================================ - // STORAGE TESTS - SESSION STORAGE - // ============================================================ - CustomTestStep( - id: 'storage_session_set', - name: 'SessionStorage Set Item', - description: 'Set an item in sessionStorage', - category: TestCategory.storage, - action: CustomTestAction.evaluateJs(''' - sessionStorage.setItem("session_key", "session_value"); - sessionStorage.getItem("session_key"); - '''), - expectedResult: 'session_value', - expectedResultType: ExpectedResultType.exact, - order: order++, - ), - CustomTestStep( - id: 'storage_session_get', - name: 'SessionStorage Get Item', - description: 'Get an item from sessionStorage', - category: TestCategory.storage, - action: CustomTestAction.evaluateJs( - 'sessionStorage.getItem("session_key")', - ), - order: order++, - ), - - // ============================================================ - // CONTENT SIZE & ZOOM TESTS - // ============================================================ - CustomTestStep( - id: 'content_height', - name: 'Get Content Height', - description: 'Get the content height of the page', - category: TestCategory.content, - action: CustomTestAction.controllerMethod('getContentHeight'), - order: order++, - ), - CustomTestStep( - id: 'content_width', - name: 'Get Content Width', - description: 'Get the content width of the page', - category: TestCategory.content, - action: CustomTestAction.controllerMethod('getContentWidth'), - order: order++, - ), - CustomTestStep( - id: 'zoom_get_scale', - name: 'Get Zoom Scale', - description: 'Get the current zoom scale', - category: TestCategory.advanced, - action: CustomTestAction.controllerMethod('getZoomScale'), - order: order++, - ), - CustomTestStep( - id: 'zoom_set_scale', - name: 'Set Zoom Scale', - description: 'Set the zoom scale to 1.0', - category: TestCategory.advanced, - action: CustomTestAction.controllerMethod( - 'zoomBy', - parameters: {'zoomFactor': 1.0}, - ), - order: order++, - ), - - // ============================================================ - // DOM ELEMENT TESTS - // ============================================================ - CustomTestStep( - id: 'dom_check_element', - name: 'Check Element Exists', - description: 'Check if body element exists', - category: TestCategory.content, - action: CustomTestAction.checkElement('body'), - order: order++, - ), - - // ============================================================ - // FIND INTERACTION TESTS - // ============================================================ - ]; - } - - /// Export configuration as formatted JSON string - String toJsonString() { - return const JsonEncoder.withIndent(' ').convert(toJson()); - } - - /// Import configuration from JSON string - static TestConfiguration fromJsonString(String jsonString) { - final json = jsonDecode(jsonString) as Map; - return TestConfiguration.fromJson(json); - } -} - -/// Provider for managing test configurations with persistence -class TestConfigurationManager extends ChangeNotifier { - static const String _savedConfigsKey = 'test_saved_configs'; - static const String _currentConfigKey = 'test_current_config'; - - SharedPreferences? _prefs; - TestConfiguration _currentConfig = TestConfiguration.empty(); - List _savedConfigs = []; - bool _isLoading = true; - - TestConfiguration get currentConfig => _currentConfig; - List get savedConfigs => List.unmodifiable(_savedConfigs); - bool get isLoading => _isLoading; - - /// Initialize the configuration manager and load persisted data - Future init() async { - _prefs = await SharedPreferences.getInstance(); - await _loadSavedConfigs(); - await _loadCurrentConfig(); - _isLoading = false; - notifyListeners(); - } - - /// Load saved configurations from SharedPreferences - Future _loadSavedConfigs() async { - final configsJson = _prefs?.getStringList(_savedConfigsKey); - if (configsJson != null) { - _savedConfigs = configsJson - .map((json) { - try { - return TestConfiguration.fromJsonString(json); - } catch (e) { - debugPrint('Failed to parse saved config: $e'); - return null; - } - }) - .whereType() - .toList(); - } - } - - /// Load current configuration from SharedPreferences - Future _loadCurrentConfig() async { - final configJson = _prefs?.getString(_currentConfigKey); - if (configJson != null) { - try { - _currentConfig = TestConfiguration.fromJsonString(configJson); - } catch (e) { - debugPrint('Failed to parse current config: $e'); - _currentConfig = TestConfiguration.empty(); - } - } - } - - /// Save configurations to SharedPreferences - Future _saveConfigs() async { - final configsJson = _savedConfigs.map((c) => c.toJsonString()).toList(); - await _prefs?.setStringList(_savedConfigsKey, configsJson); - await _prefs?.setString(_currentConfigKey, _currentConfig.toJsonString()); - } - - /// Set the WebView type - void setWebViewType(TestWebViewType type) { - _currentConfig = _currentConfig.copyWith(webViewType: type); - _saveConfigs(); - notifyListeners(); - } - - /// Set the initial URL - void setInitialUrl(String? url) { - _currentConfig = _currentConfig.copyWith(initialUrl: url); - _saveConfigs(); - notifyListeners(); - } - - /// Set the headless WebView size - void setHeadlessSize(double width, double height) { - _currentConfig = _currentConfig.copyWith( - headlessWidth: width, - headlessHeight: height, - ); - _saveConfigs(); - notifyListeners(); - } - - /// Add a custom test step - void addCustomStep(CustomTestStep step) { - final newSteps = [..._currentConfig.customSteps, step]; - _currentConfig = _currentConfig.copyWith(customSteps: newSteps); - _saveConfigs(); - notifyListeners(); - } - - /// Update a custom test step - void updateCustomStep(String stepId, CustomTestStep updatedStep) { - final newSteps = _currentConfig.customSteps.map((s) { - return s.id == stepId ? updatedStep : s; - }).toList(); - _currentConfig = _currentConfig.copyWith(customSteps: newSteps); - _saveConfigs(); - notifyListeners(); - } - - /// Remove a custom test step - void removeCustomStep(String stepId) { - final newSteps = _currentConfig.customSteps - .where((s) => s.id != stepId) - .toList(); - _currentConfig = _currentConfig.copyWith(customSteps: newSteps); - _saveConfigs(); - notifyListeners(); - } - - /// Reorder custom test steps - void reorderCustomSteps(int oldIndex, int newIndex) { - final steps = [..._currentConfig.customSteps]; - if (newIndex > oldIndex) newIndex--; - final step = steps.removeAt(oldIndex); - steps.insert(newIndex, step); - - // Update order values - final updatedSteps = steps.asMap().entries.map((e) { - return e.value.copyWith(order: e.key); - }).toList(); - - _currentConfig = _currentConfig.copyWith(customSteps: updatedSteps); - _saveConfigs(); - notifyListeners(); - } - - /// Set test ordering for a category - void setTestOrdering(String category, List testIds) { - final newOrdering = Map>.from( - _currentConfig.testOrdering, - ); - newOrdering[category] = testIds; - _currentConfig = _currentConfig.copyWith(testOrdering: newOrdering); - _saveConfigs(); - notifyListeners(); - } - - /// Toggle a built-in test enabled state - void toggleBuiltInTest(String testId, bool enabled) { - final newEnabled = Set.from(_currentConfig.enabledBuiltInTests); - if (enabled) { - newEnabled.add(testId); - } else { - newEnabled.remove(testId); - } - _currentConfig = _currentConfig.copyWith(enabledBuiltInTests: newEnabled); - _saveConfigs(); - notifyListeners(); - } - - /// Save current configuration - Future saveCurrentConfig({String? name}) async { - if (name != null) { - _currentConfig = _currentConfig.copyWith(name: name); - } - - // Check if config already exists - final existingIndex = _savedConfigs.indexWhere( - (c) => c.id == _currentConfig.id, - ); - if (existingIndex >= 0) { - _savedConfigs[existingIndex] = _currentConfig; - } else { - _savedConfigs.add(_currentConfig); - } - await _saveConfigs(); - notifyListeners(); - } - - /// Load a saved configuration - Future loadConfig(String configId) async { - final config = _savedConfigs.firstWhere( - (c) => c.id == configId, - orElse: () => TestConfiguration.empty(), - ); - _currentConfig = config; - await _saveConfigs(); - notifyListeners(); - } - - /// Delete a saved configuration - Future deleteConfig(String configId) async { - _savedConfigs.removeWhere((c) => c.id == configId); - await _saveConfigs(); - notifyListeners(); - } - - /// Import configuration from JSON string - Future importConfig(String jsonString) async { - try { - final config = TestConfiguration.fromJsonString(jsonString); - _currentConfig = config; - await _saveConfigs(); - notifyListeners(); - } catch (e) { - debugPrint('Failed to import configuration: $e'); - rethrow; - } - } - - /// Export current configuration as JSON string - String exportConfig() { - return _currentConfig.toJsonString(); - } - - /// Reset to empty configuration - Future resetConfig() async { - _currentConfig = TestConfiguration.empty(); - await _saveConfigs(); - notifyListeners(); - } - - /// Clear all saved configurations - Future clearAllSavedConfigs() async { - _savedConfigs.clear(); - await _saveConfigs(); - notifyListeners(); - } -} diff --git a/flutter_inappwebview/example/lib/models/test_result.dart b/flutter_inappwebview/example/lib/models/test_result.dart deleted file mode 100644 index bdab7ce4ce..0000000000 --- a/flutter_inappwebview/example/lib/models/test_result.dart +++ /dev/null @@ -1,48 +0,0 @@ -/// Represents the result of a test execution -class TestResult { - final bool passed; - final String message; - final Duration duration; - final Map? data; - - const TestResult({ - required this.passed, - required this.message, - required this.duration, - this.data, - }); - - /// Format duration as a human-readable string - String get durationFormatted { - final ms = duration.inMilliseconds; - if (ms < 1000) { - return '${ms}ms'; - } else if (ms < 60000) { - return '${(ms / 1000).toStringAsFixed(2)}s'; - } else { - final minutes = duration.inMinutes; - final seconds = duration.inSeconds % 60; - return '$minutes:${seconds.toString().padLeft(2, '0')}'; - } - } - - /// Serialize to map - Map toMap() { - return { - 'passed': passed, - 'message': message, - 'duration': duration.inMilliseconds, - 'data': data, - }; - } - - /// Deserialize from map - factory TestResult.fromMap(Map map) { - return TestResult( - passed: map['passed'] as bool, - message: map['message'] as String, - duration: Duration(milliseconds: map['duration'] as int), - data: map['data'] as Map?, - ); - } -} diff --git a/flutter_inappwebview/example/lib/models/test_runner_models.dart b/flutter_inappwebview/example/lib/models/test_runner_models.dart deleted file mode 100644 index 3199df003c..0000000000 --- a/flutter_inappwebview/example/lib/models/test_runner_models.dart +++ /dev/null @@ -1,146 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/models/test_result.dart'; -import 'package:flutter_inappwebview_example/utils/constants.dart'; - -/// Status of the test runner -enum TestStatus { idle, running, paused, completed, error } - -/// Extended test result with additional metadata -class ExtendedTestResult { - final String testId; - final String testTitle; - final TestCategory category; - final bool success; - final String message; - final Duration duration; - final DateTime timestamp; - final Map? data; - final bool skipped; - final String? skipReason; - - const ExtendedTestResult({ - required this.testId, - required this.testTitle, - required this.category, - required this.success, - required this.message, - required this.duration, - required this.timestamp, - this.data, - this.skipped = false, - this.skipReason, - }); - - Map toJson() { - return { - 'testId': testId, - 'testTitle': testTitle, - 'category': category.name, - 'success': success, - 'message': message, - 'durationMs': duration.inMilliseconds, - 'timestamp': timestamp.toIso8601String(), - 'data': data, - 'skipped': skipped, - 'skipReason': skipReason, - }; - } - - factory ExtendedTestResult.fromJson(Map json) { - return ExtendedTestResult( - testId: json['testId'] as String, - testTitle: json['testTitle'] as String, - category: TestCategory.values.firstWhere( - (c) => c.name == json['category'], - ), - success: json['success'] as bool, - message: json['message'] as String, - duration: Duration(milliseconds: json['durationMs'] as int), - timestamp: DateTime.parse(json['timestamp'] as String), - data: json['data'] as Map?, - skipped: json['skipped'] as bool? ?? false, - skipReason: json['skipReason'] as String?, - ); - } -} - -/// A single test case that can be executed -class ExecutableTestCase { - final String id; - final String title; - final String description; - final TestCategory category; - final Future Function(InAppWebViewController? controller) execute; - final List supportedPlatforms; - final dynamic supportedMethod; - final bool Function(dynamic method, {TargetPlatform? platform})? - isMethodSupported; - - const ExecutableTestCase({ - required this.id, - required this.title, - required this.description, - required this.category, - required this.execute, - this.supportedPlatforms = const [ - 'android', - 'ios', - 'macos', - 'windows', - 'linux', - 'web', - ], - this.supportedMethod, - this.isMethodSupported, - }); - - bool isSupportedOnCurrentPlatform() { - if (isMethodSupported != null && supportedMethod != null) { - return isMethodSupported!( - supportedMethod, - platform: _getCurrentTargetPlatform(), - ); - } - - final currentPlatform = _getCurrentPlatform(); - return supportedPlatforms.contains(currentPlatform); - } - - static String _getCurrentPlatform() { - if (kIsWeb) return 'web'; - switch (defaultTargetPlatform) { - case TargetPlatform.android: - return 'android'; - case TargetPlatform.iOS: - return 'ios'; - case TargetPlatform.macOS: - return 'macos'; - case TargetPlatform.windows: - return 'windows'; - case TargetPlatform.linux: - return 'linux'; - default: - return 'unknown'; - } - } - - static TargetPlatform? _getCurrentTargetPlatform() { - if (kIsWeb) return null; - return defaultTargetPlatform; - } -} - -/// Category with its test cases -class TestCategoryGroup { - final TestCategory category; - final List tests; - - const TestCategoryGroup({required this.category, required this.tests}); - - /// The display name derived from category.displayName - String get name => category.displayName; - - /// The description derived from category.description - String get description => category.description; -} diff --git a/flutter_inappwebview/example/lib/models/webview_environment_profile.dart b/flutter_inappwebview/example/lib/models/webview_environment_profile.dart deleted file mode 100644 index e56fce152e..0000000000 --- a/flutter_inappwebview/example/lib/models/webview_environment_profile.dart +++ /dev/null @@ -1,88 +0,0 @@ -import 'dart:convert'; - -/// Model for saving/loading WebViewEnvironmentSettings profiles -class WebViewEnvironmentProfile { - final String id; - final String name; - final DateTime createdAt; - final Map settings; - - const WebViewEnvironmentProfile({ - required this.id, - required this.name, - required this.createdAt, - required this.settings, - }); - - /// Create a new profile with a unique ID - factory WebViewEnvironmentProfile.create({ - required String name, - required Map settings, - }) { - return WebViewEnvironmentProfile( - id: DateTime.now().millisecondsSinceEpoch.toString(), - name: name, - createdAt: DateTime.now(), - settings: Map.from(settings), - ); - } - - /// Create a copy with optional modifications - WebViewEnvironmentProfile copyWith({ - String? id, - String? name, - DateTime? createdAt, - Map? settings, - }) { - return WebViewEnvironmentProfile( - id: id ?? this.id, - name: name ?? this.name, - createdAt: createdAt ?? this.createdAt, - settings: settings ?? Map.from(this.settings), - ); - } - - /// Convert to JSON map for serialization - Map toJson() { - return { - 'id': id, - 'name': name, - 'createdAt': createdAt.toIso8601String(), - 'settings': settings, - }; - } - - /// Create from JSON map - factory WebViewEnvironmentProfile.fromJson(Map json) { - return WebViewEnvironmentProfile( - id: json['id'] as String, - name: json['name'] as String, - createdAt: DateTime.parse(json['createdAt'] as String), - settings: Map.from(json['settings'] as Map), - ); - } - - /// Serialize to JSON string - String toJsonString() => jsonEncode(toJson()); - - /// Create from JSON string - factory WebViewEnvironmentProfile.fromJsonString(String jsonString) { - return WebViewEnvironmentProfile.fromJson( - jsonDecode(jsonString) as Map, - ); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - return other is WebViewEnvironmentProfile && other.id == id; - } - - @override - int get hashCode => id.hashCode; - - @override - String toString() { - return 'WebViewEnvironmentProfile(id: $id, name: $name, createdAt: $createdAt, settingsCount: ${settings.length})'; - } -} diff --git a/flutter_inappwebview/example/lib/providers/event_log_provider.dart b/flutter_inappwebview/example/lib/providers/event_log_provider.dart deleted file mode 100644 index 90d9c8abfd..0000000000 --- a/flutter_inappwebview/example/lib/providers/event_log_provider.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_example/models/event_log_entry.dart'; - -/// Provider for managing event logs with buffer management, filtering, and search -class EventLogProvider extends ChangeNotifier { - static const int maxEvents = 1000; - final List _events = []; - - /// Get all events - List get events => List.unmodifiable(_events); - - /// Add an event to the log - void addEvent(EventLogEntry event) { - _events.add(event); - - // Maintain buffer limit - if (_events.length > maxEvents) { - _events.removeAt(0); - } - - notifyListeners(); - } - - /// Filter events by type - List filterByType(EventType? eventType) { - if (eventType == null) { - return List.unmodifiable(_events); - } - return _events.where((event) => event.eventType == eventType).toList(); - } - - /// Search events by message content (case-insensitive) - List search(String query) { - if (query.isEmpty) { - return List.unmodifiable(_events); - } - - final lowerQuery = query.toLowerCase(); - return _events - .where((event) => event.message.toLowerCase().contains(lowerQuery)) - .toList(); - } - - /// Clear all events - void clear() { - _events.clear(); - notifyListeners(); - } -} diff --git a/flutter_inappwebview/example/lib/providers/network_monitor.dart b/flutter_inappwebview/example/lib/providers/network_monitor.dart deleted file mode 100644 index 8bd4df6837..0000000000 --- a/flutter_inappwebview/example/lib/providers/network_monitor.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_example/models/network_request.dart'; - -/// Network monitor for tracking network requests -class NetworkMonitor extends ChangeNotifier { - final List _requests = []; - bool _isMonitoring = false; - - /// Get all network requests - List get requests => List.unmodifiable(_requests); - - /// Check if monitoring is enabled - bool get isMonitoring => _isMonitoring; - - /// Toggle network monitoring - void toggleMonitoring() { - _isMonitoring = !_isMonitoring; - notifyListeners(); - } - - /// Add a network request to the monitor - void addRequest(NetworkRequest request) { - _requests.add(request); - notifyListeners(); - } - - /// Update an existing request with response data - void updateRequest( - String id, { - String? response, - int? statusCode, - Duration? duration, - }) { - final index = _requests.indexWhere((req) => req.id == id); - if (index != -1) { - _requests[index] = _requests[index].copyWith( - response: response, - statusCode: statusCode, - duration: duration, - ); - notifyListeners(); - } - } - - /// Clear all network requests - void clearRequests() { - _requests.clear(); - notifyListeners(); - } -} diff --git a/flutter_inappwebview/example/lib/providers/settings_manager.dart b/flutter_inappwebview/example/lib/providers/settings_manager.dart deleted file mode 100644 index 34ea48337b..0000000000 --- a/flutter_inappwebview/example/lib/providers/settings_manager.dart +++ /dev/null @@ -1,556 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:flutter_inappwebview_example/models/settings_profile.dart'; -import 'package:flutter_inappwebview_example/models/webview_environment_profile.dart'; -import 'package:flutter_inappwebview_example/models/setting_definition.dart'; -import 'package:flutter_inappwebview_example/models/environment_setting_definition.dart'; -import 'package:flutter_inappwebview_example/utils/settings_defaults.dart' - as settings_defaults; -import 'package:flutter_inappwebview_example/utils/settings_definitions.dart' - as settings_definitions; -import 'package:flutter_inappwebview_example/utils/environment_settings_definitions.dart' - as environment_settings_definitions; - -/// Settings manager for the testing interface -/// Manages InAppWebViewSettings profiles with save/load functionality -class SettingsManager extends ChangeNotifier { - static const String _profilesKey = 'settings_profiles'; - static const String _currentProfileKey = 'current_profile_id'; - static const String _modifiedSettingsKey = 'modified_settings'; - static const String _environmentProfilesKey = 'environment_profiles'; - static const String _currentEnvironmentProfileKey = - 'current_environment_profile_id'; - - SettingsManager({ - Future Function(WebViewEnvironmentSettings? settings)? - environmentFactory, - bool Function()? environmentSupportChecker, - }) : _environmentFactory = environmentFactory ?? _defaultEnvironmentFactory, - _environmentSupportChecker = - environmentSupportChecker ?? _defaultEnvironmentSupportChecker; - - SharedPreferences? _prefs; - List _profiles = []; - String? _currentProfileId; - Map _currentSettings = {}; - Set _modifiedSettings = {}; - List _environmentProfiles = []; - String? _currentEnvironmentProfileId; - Map _currentEnvironmentSettings = {}; - WebViewEnvironment? _webViewEnvironment; - bool _isEnvironmentLoading = false; - int _settingsRevision = 0; - int _environmentRevision = 0; - final Future Function(WebViewEnvironmentSettings?) - _environmentFactory; - final bool Function() _environmentSupportChecker; - bool _isLoading = true; - - /// Get all saved profiles - List get profiles => List.unmodifiable(_profiles); - - /// Get the current profile ID - String? get currentProfileId => _currentProfileId; - - /// Get the current settings revision - int get settingsRevision => _settingsRevision; - - /// Get the current profile - SettingsProfile? get currentProfile { - if (_currentProfileId == null) return null; - try { - return _profiles.firstWhere((p) => p.id == _currentProfileId); - } catch (e) { - return null; - } - } - - /// Get the current settings state - Map get currentSettings => - Map.unmodifiable(_currentSettings); - - /// Get all saved environment profiles - List get environmentProfiles => - List.unmodifiable(_environmentProfiles); - - /// Get the current environment profile ID - String? get currentEnvironmentProfileId => _currentEnvironmentProfileId; - - /// Get the current environment profile - WebViewEnvironmentProfile? get currentEnvironmentProfile { - if (_currentEnvironmentProfileId == null) return null; - try { - return _environmentProfiles.firstWhere( - (p) => p.id == _currentEnvironmentProfileId, - ); - } catch (e) { - return null; - } - } - - /// Get the current environment settings map - Map get currentEnvironmentSettings => - Map.unmodifiable(_currentEnvironmentSettings); - - /// Current WebViewEnvironment instance - WebViewEnvironment? get webViewEnvironment => _webViewEnvironment; - - /// Check if environment is supported on the current platform - bool get isEnvironmentSupported => _environmentSupportChecker(); - - /// Check if environment is being created or disposed - bool get isEnvironmentLoading => _isEnvironmentLoading; - - /// Environment revision for rebuild triggers - int get environmentRevision => _environmentRevision; - - /// Get the set of modified setting keys - Set get modifiedSettings => Set.unmodifiable(_modifiedSettings); - - /// Check if loading is in progress - bool get isLoading => _isLoading; - - /// Initialize the settings manager - Future init() async { - _prefs = await SharedPreferences.getInstance(); - await _loadProfiles(); - await _loadModifiedSettings(); - await _loadEnvironmentProfiles(); - await _recreateEnvironment(); - _isLoading = false; - notifyListeners(); - } - - /// Load profiles from shared preferences - Future _loadProfiles() async { - final profilesJson = _prefs?.getStringList(_profilesKey); - if (profilesJson != null) { - _profiles = profilesJson - .map((json) => SettingsProfile.fromJsonString(json)) - .toList(); - } - _currentProfileId = _prefs?.getString(_currentProfileKey); - - // Load current profile settings or use defaults - final profile = currentProfile; - if (profile != null) { - _currentSettings = Map.from(profile.settings); - } else { - _currentSettings = _getDefaultSettings(); - } - } - - /// Load modified settings tracking from shared preferences - Future _loadModifiedSettings() async { - final modifiedJson = _prefs?.getStringList(_modifiedSettingsKey); - if (modifiedJson != null) { - _modifiedSettings = modifiedJson.toSet(); - } - } - - /// Load environment profiles from shared preferences - Future _loadEnvironmentProfiles() async { - final profilesJson = _prefs?.getStringList(_environmentProfilesKey); - if (profilesJson != null) { - _environmentProfiles = profilesJson - .map((json) => WebViewEnvironmentProfile.fromJsonString(json)) - .toList(); - } - _currentEnvironmentProfileId = _prefs?.getString( - _currentEnvironmentProfileKey, - ); - - final profile = currentEnvironmentProfile; - if (profile != null) { - _currentEnvironmentSettings = Map.from(profile.settings); - } else { - _currentEnvironmentSettings = _getDefaultEnvironmentSettings(); - } - } - - /// Save profiles to shared preferences - Future _saveProfiles() async { - final profilesJson = _profiles.map((p) => p.toJsonString()).toList(); - await _prefs?.setStringList(_profilesKey, profilesJson); - if (_currentProfileId != null) { - await _prefs?.setString(_currentProfileKey, _currentProfileId!); - } else { - await _prefs?.remove(_currentProfileKey); - } - } - - /// Save environment profiles to shared preferences - Future _saveEnvironmentProfiles() async { - final profilesJson = _environmentProfiles - .map((p) => p.toJsonString()) - .toList(); - await _prefs?.setStringList(_environmentProfilesKey, profilesJson); - if (_currentEnvironmentProfileId != null) { - await _prefs?.setString( - _currentEnvironmentProfileKey, - _currentEnvironmentProfileId!, - ); - } else { - await _prefs?.remove(_currentEnvironmentProfileKey); - } - } - - /// Save modified settings tracking to shared preferences - Future _saveModifiedSettings() async { - await _prefs?.setStringList( - _modifiedSettingsKey, - _modifiedSettings.toList(), - ); - } - - /// Create a new settings profile - Future createProfile( - String name, { - Map? settings, - }) async { - final profile = SettingsProfile.create( - name: name, - settings: settings ?? Map.from(_currentSettings), - ); - _profiles.add(profile); - await _saveProfiles(); - notifyListeners(); - return profile; - } - - /// Create a new environment profile - Future createEnvironmentProfile( - String name, { - Map? settings, - }) async { - final profile = WebViewEnvironmentProfile.create( - name: name, - settings: - settings ?? Map.from(_currentEnvironmentSettings), - ); - _environmentProfiles.add(profile); - await _saveEnvironmentProfiles(); - notifyListeners(); - return profile; - } - - /// Update an existing profile - Future updateProfile( - String profileId, { - String? name, - Map? settings, - }) async { - final index = _profiles.indexWhere((p) => p.id == profileId); - if (index != -1) { - _profiles[index] = _profiles[index].copyWith( - name: name, - settings: settings, - ); - await _saveProfiles(); - notifyListeners(); - } - } - - /// Update an existing environment profile - Future updateEnvironmentProfile( - String profileId, { - String? name, - Map? settings, - }) async { - final index = _environmentProfiles.indexWhere((p) => p.id == profileId); - if (index != -1) { - _environmentProfiles[index] = _environmentProfiles[index].copyWith( - name: name, - settings: settings, - ); - if (_currentEnvironmentProfileId == profileId && settings != null) { - _currentEnvironmentSettings = Map.from(settings); - await _recreateEnvironment(); - } else { - notifyListeners(); - } - await _saveEnvironmentProfiles(); - } - } - - /// Delete a profile - Future deleteProfile(String profileId) async { - _profiles.removeWhere((p) => p.id == profileId); - if (_currentProfileId == profileId) { - _currentProfileId = null; - } - await _saveProfiles(); - notifyListeners(); - } - - /// Delete an environment profile - Future deleteEnvironmentProfile(String profileId) async { - _environmentProfiles.removeWhere((p) => p.id == profileId); - if (_currentEnvironmentProfileId == profileId) { - _currentEnvironmentProfileId = null; - _currentEnvironmentSettings = _getDefaultEnvironmentSettings(); - await _recreateEnvironment(); - } - await _saveEnvironmentProfiles(); - notifyListeners(); - } - - /// Load a profile as the current settings - Future loadProfile(String profileId) async { - final profile = _profiles.firstWhere( - (p) => p.id == profileId, - orElse: () => throw Exception('Profile not found'), - ); - _currentProfileId = profileId; - _currentSettings = Map.from(profile.settings); - _modifiedSettings.clear(); - _settingsRevision++; - await _saveProfiles(); - await _saveModifiedSettings(); - notifyListeners(); - } - - /// Load an environment profile as the current environment settings - Future loadEnvironmentProfile(String profileId) async { - final profile = _environmentProfiles.firstWhere( - (p) => p.id == profileId, - orElse: () => throw Exception('Environment profile not found'), - ); - _currentEnvironmentProfileId = profileId; - _currentEnvironmentSettings = Map.from(profile.settings); - await _saveEnvironmentProfiles(); - await _recreateEnvironment(); - } - - /// Clear current environment selection - Future clearEnvironmentSelection() async { - _currentEnvironmentProfileId = null; - _currentEnvironmentSettings = _getDefaultEnvironmentSettings(); - await _saveEnvironmentProfiles(); - await _recreateEnvironment(); - } - - /// Save current settings to the current profile or create a new one - Future saveCurrentSettings(String name) async { - if (_currentProfileId != null) { - await updateProfile(_currentProfileId!, settings: _currentSettings); - _modifiedSettings.clear(); - await _saveModifiedSettings(); - return currentProfile!; - } else { - final profile = await createProfile(name, settings: _currentSettings); - _currentProfileId = profile.id; - _modifiedSettings.clear(); - await _saveProfiles(); - await _saveModifiedSettings(); - notifyListeners(); - return profile; - } - } - - /// Save current environment settings to the current profile or create a new one - Future saveCurrentEnvironmentSettings( - String name, - ) async { - if (_currentEnvironmentProfileId != null) { - await updateEnvironmentProfile( - _currentEnvironmentProfileId!, - name: name, - settings: _currentEnvironmentSettings, - ); - return currentEnvironmentProfile!; - } else { - final profile = await createEnvironmentProfile( - name, - settings: _currentEnvironmentSettings, - ); - _currentEnvironmentProfileId = profile.id; - await _saveEnvironmentProfiles(); - notifyListeners(); - return profile; - } - } - - /// Update a single setting value - void updateSetting(String key, dynamic value) { - final defaultSettings = _getDefaultSettings(); - final defaultValue = defaultSettings[key]; - - if (value == defaultValue) { - _currentSettings.remove(key); - _modifiedSettings.remove(key); - } else { - _currentSettings[key] = value; - _modifiedSettings.add(key); - } - _settingsRevision++; - notifyListeners(); - } - - /// Get a setting value with fallback to default - dynamic getSetting(String key) { - if (_currentSettings.containsKey(key)) { - return _currentSettings[key]; - } - return _getDefaultSettings()[key]; - } - - /// Check if a setting has been modified from default - bool isSettingModified(String key) { - return _modifiedSettings.contains(key); - } - - /// Reset all settings to defaults - Future resetToDefaults() async { - _currentSettings = _getDefaultSettings(); - _modifiedSettings.clear(); - _currentProfileId = null; - _settingsRevision++; - await _saveProfiles(); - await _saveModifiedSettings(); - notifyListeners(); - } - - /// Reset a single setting to default - void resetSetting(String key) { - final defaultValue = _getDefaultSettings()[key]; - _currentSettings[key] = defaultValue; - _modifiedSettings.remove(key); - _settingsRevision++; - notifyListeners(); - } - - /// Export settings as JSON string - String exportSettingsAsJson() { - final exportData = { - 'exportedAt': DateTime.now().toIso8601String(), - 'settings': _currentSettings, - }; - return const JsonEncoder.withIndent(' ').convert(exportData); - } - - /// Import settings from JSON string - Future importSettingsFromJson(String json) async { - try { - final importData = jsonDecode(json) as Map; - if (importData.containsKey('settings')) { - final settings = importData['settings'] as Map; - _currentSettings = Map.from(settings); - _modifiedSettings = settings.keys.toSet(); - _currentProfileId = null; - _settingsRevision++; - await _saveModifiedSettings(); - notifyListeners(); - return true; - } - return false; - } catch (e) { - debugPrint('Error importing settings: $e'); - return false; - } - } - - /// Build InAppWebViewSettings from current settings - InAppWebViewSettings buildSettings() { - final defaults = _getDefaultSettings(); - final merged = Map.from(defaults) - ..addAll(_currentSettings); - - return InAppWebViewSettings.fromMap( - merged, - enumMethod: EnumMethod.nativeValue, - ) ?? - InAppWebViewSettings(); - } - - /// Build WebViewEnvironmentSettings from current environment settings - WebViewEnvironmentSettings buildEnvironmentSettings() { - final defaults = _getDefaultEnvironmentSettings(); - final merged = Map.from(defaults) - ..addAll(_currentEnvironmentSettings); - - return WebViewEnvironmentSettings.fromMap( - merged, - enumMethod: EnumMethod.nativeValue, - ) ?? - WebViewEnvironmentSettings(); - } - - /// Recreate the WebViewEnvironment using current selection - Future recreateEnvironment() async { - await _recreateEnvironment(); - } - - /// Dispose the current WebViewEnvironment instance - Future disposeEnvironment() async { - _isEnvironmentLoading = true; - notifyListeners(); - await _webViewEnvironment?.dispose(); - _webViewEnvironment = null; - _environmentRevision++; - _isEnvironmentLoading = false; - notifyListeners(); - } - - Future _recreateEnvironment() async { - _isEnvironmentLoading = true; - notifyListeners(); - await _webViewEnvironment?.dispose(); - _webViewEnvironment = null; - - if (_currentEnvironmentProfileId != null && isEnvironmentSupported) { - final settings = buildEnvironmentSettings(); - _webViewEnvironment = await _environmentFactory(settings); - } - - _environmentRevision++; - _isEnvironmentLoading = false; - notifyListeners(); - } - - static Future _defaultEnvironmentFactory( - WebViewEnvironmentSettings? settings, - ) async { - if (!_defaultEnvironmentSupportChecker()) { - return null; - } - return WebViewEnvironment.create(settings: settings); - } - - static bool _defaultEnvironmentSupportChecker() { - return !kIsWeb && WebViewEnvironment.isClassSupported(); - } - - Map _getDefaultEnvironmentSettings() { - return settings_defaults.defaultWebViewEnvironmentSettings().toMap( - enumMethod: EnumMethod.nativeValue, - ); - } - - /// Get default settings map - Map _getDefaultSettings() { - return settings_defaults.defaultInAppWebViewSettings().toMap( - enumMethod: EnumMethod.nativeValue, - ); - } - - @override - void dispose() { - _webViewEnvironment?.dispose(); - super.dispose(); - } - - /// Get all setting definitions organized by category - static Map> getSettingDefinitions() { - return settings_definitions.getSettingDefinitions(); - } - - /// Get all environment setting definitions organized by category - static Map> - getEnvironmentSettingDefinitions() { - return environment_settings_definitions.getEnvironmentSettingDefinitions(); - } -} diff --git a/flutter_inappwebview/example/lib/providers/test_runner.dart b/flutter_inappwebview/example/lib/providers/test_runner.dart deleted file mode 100644 index e5e6453167..0000000000 --- a/flutter_inappwebview/example/lib/providers/test_runner.dart +++ /dev/null @@ -1,745 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:ui'; - -import 'package:flutter/material.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import '../models/test_configuration.dart'; -import '../models/test_result.dart'; -import '../models/test_runner_models.dart'; -import '../utils/constants.dart'; -import '../utils/controller_methods_registry.dart'; - -/// Test runner for executing automated tests -class TestRunner extends ChangeNotifier { - TestStatus _status = TestStatus.idle; - List _results = []; - String? _currentTest; - int _progress = 0; - int _total = 0; - bool _shouldStop = false; - DateTime? _startTime; - DateTime? _endTime; - - /// The current test configuration being used - TestConfiguration? _currentConfiguration; - - /// The type of WebView being used - TestWebViewType _webViewType = TestWebViewType.inAppWebView; - - /// Headless WebView instance (when using headless mode) - HeadlessInAppWebView? _headlessWebView; - - /// Controller for WebView (both headless and visible) - InAppWebViewController? _webViewController; - - /// Whether the WebView is ready - bool _webViewReady = false; - - /// Key to force WebView recreation - Key _webViewKey = UniqueKey(); - - /// Initial URL for the WebView - String _initialUrl = 'about:blank'; - - // Event StreamControllers for listening to WebView events - final _onLoadStopController = StreamController.broadcast(); - final _onLoadStartController = StreamController.broadcast(); - final _onProgressChangedController = StreamController.broadcast(); - final _onPageCommitVisibleController = StreamController.broadcast(); - final _onTitleChangedController = StreamController.broadcast(); - final _onUpdateVisitedHistoryController = - StreamController.broadcast(); - - // Store target progress for onProgressChanged event filtering - int _targetProgress = 100; - String _progressComparison = 'greaterThanOrEquals'; - - // Getters - TestStatus get status => _status; - List get results => List.unmodifiable(_results); - String? get currentTest => _currentTest; - int get progress => _progress; - int get total => _total; - int get passed => _results.where((r) => r.success && !r.skipped).length; - int get failed => _results.where((r) => !r.success && !r.skipped).length; - int get skipped => _results.where((r) => r.skipped).length; - DateTime? get startTime => _startTime; - DateTime? get endTime => _endTime; - TestConfiguration? get currentConfiguration => _currentConfiguration; - TestWebViewType get webViewType => _webViewType; - bool get isUsingHeadless => _webViewType == TestWebViewType.headless; - HeadlessInAppWebView? get headlessWebView => _headlessWebView; - InAppWebViewController? get webViewController => _webViewController; - bool get webViewReady => _webViewReady; - Key get webViewKey => _webViewKey; - - Duration get elapsedTime { - if (_startTime == null) return Duration.zero; - final end = _endTime ?? DateTime.now(); - return end.difference(_startTime!); - } - - double get successRate { - final executed = _results.where((r) => !r.skipped).length; - if (executed == 0) return 0; - return (passed / executed) * 100; - } - - /// Set the WebView type to use for testing - void setWebViewType(TestWebViewType type) { - if (_webViewType != type) { - _webViewType = type; - _webViewReady = false; - _webViewController = null; - _webViewKey = UniqueKey(); - notifyListeners(); - } - } - - /// Set the test configuration to use - void setConfiguration(TestConfiguration? config) { - _currentConfiguration = config; - if (config != null) { - _webViewType = config.webViewType; - _initialUrl = config.initialUrl ?? 'about:blank'; - } - _webViewReady = false; - _webViewController = null; - _webViewKey = UniqueKey(); - notifyListeners(); - } - - /// Set the initial URL for the WebView - void setInitialUrl(String url) { - _initialUrl = url; - notifyListeners(); - } - - /// Recreate the WebView (forces a new key) - void recreateWebView() { - _webViewReady = false; - _webViewController = null; - _webViewKey = UniqueKey(); - notifyListeners(); - } - - /// Build the InAppWebView widget for visible mode - /// This should be used by the UI to display the WebView - Widget buildInAppWebView({double? width, double? height}) { - return InAppWebView( - key: _webViewKey, - initialUrlRequest: URLRequest( - url: WebUri(_currentConfiguration?.initialUrl ?? _initialUrl), - ), - initialSettings: InAppWebViewSettings(javaScriptEnabled: true), - onWebViewCreated: (controller) { - _webViewController = controller; - notifyListeners(); - }, - onLoadStart: (controller, url) { - _onLoadStartController.add(url); - }, - onLoadStop: (controller, url) { - _onLoadStopController.add(url); - if (!_webViewReady) { - _webViewReady = true; - notifyListeners(); - } - }, - onProgressChanged: (controller, progress) { - _onProgressChangedController.add(progress); - }, - onPageCommitVisible: (controller, url) { - _onPageCommitVisibleController.add(url); - }, - onTitleChanged: (controller, title) { - _onTitleChangedController.add(title); - }, - onUpdateVisitedHistory: (controller, url, isReload) { - _onUpdateVisitedHistoryController.add(url); - }, - ); - } - - /// Initialize headless WebView for testing - Future initializeHeadlessWebView({ - String? initialUrl, - double? width, - double? height, - }) async { - if (_headlessWebView != null) { - await disposeHeadlessWebView(); - } - - final completer = Completer(); - - _headlessWebView = HeadlessInAppWebView( - initialUrlRequest: URLRequest(url: WebUri(initialUrl ?? _initialUrl)), - initialSize: Size(width ?? 1920, height ?? 1080), - onWebViewCreated: (controller) { - _webViewController = controller; - notifyListeners(); - }, - onLoadStart: (controller, url) { - _onLoadStartController.add(url); - }, - onLoadStop: (controller, url) { - _onLoadStopController.add(url); - if (!completer.isCompleted) { - completer.complete(); - } - if (!_webViewReady) { - _webViewReady = true; - notifyListeners(); - } - }, - onProgressChanged: (controller, progress) { - _onProgressChangedController.add(progress); - }, - onPageCommitVisible: (controller, url) { - _onPageCommitVisibleController.add(url); - }, - onTitleChanged: (controller, title) { - _onTitleChangedController.add(title); - }, - onUpdateVisitedHistory: (controller, url, isReload) { - _onUpdateVisitedHistoryController.add(url); - }, - ); - - await _headlessWebView!.run(); - - // Wait for initial load or timeout - await completer.future.timeout( - const Duration(seconds: 10), - onTimeout: () {}, - ); - - _webViewReady = true; - notifyListeners(); - } - - /// Dispose headless WebView - Future disposeHeadlessWebView() async { - if (_headlessWebView != null) { - await _headlessWebView!.dispose(); - _headlessWebView = null; - _webViewController = null; - _webViewReady = false; - notifyListeners(); - } - } - - /// Run tests from a custom configuration - Future runConfiguration(TestConfiguration config) async { - _currentConfiguration = config; - _webViewType = config.webViewType; - - // Get appropriate controller based on WebView type - if (config.webViewType == TestWebViewType.headless) { - // Always recreate headless WebView to ensure fresh state and correct size - await initializeHeadlessWebView( - initialUrl: config.initialUrl, - width: config.headlessWidth, - height: config.headlessHeight, - ); - } - - // Run custom steps if any - if (config.customSteps.isNotEmpty) { - await _runCustomSteps(config.customSteps, _webViewController); - } - } - - /// Run tests using the current WebView state - /// Call this after ensuring the WebView is ready - Future runConfigurationWithCurrentWebView( - TestConfiguration config, - ) async { - _currentConfiguration = config; - - // Run custom steps if any - if (config.customSteps.isNotEmpty) { - await _runCustomSteps(config.customSteps, _webViewController); - } - } - - /// Run custom test steps - Future _runCustomSteps( - List steps, - InAppWebViewController? controller, { - bool append = false, - }) async { - if (_status == TestStatus.running) return; - - _status = TestStatus.running; - _shouldStop = false; - if (!append) { - _results = []; - } - _progress = 0; - _total = steps.length; - _startTime = DateTime.now(); - _endTime = null; - notifyListeners(); - - for (var i = 0; i < steps.length; i++) { - if (_shouldStop) { - _status = TestStatus.paused; - notifyListeners(); - break; - } - - final step = steps[i]; - if (!step.enabled) { - _results = [ - ..._results, - ExtendedTestResult( - testId: step.id, - testTitle: step.name, - category: step.category, - success: true, - message: 'Skipped - disabled', - duration: Duration.zero, - timestamp: DateTime.now(), - skipped: true, - skipReason: 'Step is disabled', - ), - ]; - continue; - } - - _currentTest = step.name; - _progress = i; - notifyListeners(); - - final result = await _executeCustomStep(step, controller); - if (!result.success) { - debugPrint('Test "${result.testId}" failed: ${result.message}'); - } - _results = [..._results, result]; - notifyListeners(); - - // Small delay between steps - await Future.delayed(const Duration(milliseconds: 100)); - } - - _status = _shouldStop ? TestStatus.paused : TestStatus.completed; - _currentTest = null; - _progress = steps.length; - _endTime = DateTime.now(); - _shouldStop = false; - notifyListeners(); - } - - /// Execute a single custom test step - Future _executeCustomStep( - CustomTestStep step, - InAppWebViewController? controller, - ) async { - final stopwatch = Stopwatch()..start(); - - try { - dynamic result; - - switch (step.action.type) { - case CustomTestActionType.controllerMethod: - final methodId = step.action.methodId; - final methodEntry = methodId == null - ? null - : ControllerMethodsRegistry.instance.findMethodById(methodId); - final targetPlatform = _getCurrentTargetPlatform(); - - if (methodEntry != null && - !InAppWebViewController.isMethodSupported( - methodEntry.methodEnum, - platform: targetPlatform, - )) { - stopwatch.stop(); - return ExtendedTestResult( - testId: step.id, - testTitle: step.name, - category: step.category, - success: true, - message: - 'Skipped - method ${methodEntry.methodEnum.name} not supported', - duration: Duration.zero, - timestamp: DateTime.now(), - skipped: true, - skipReason: - 'Method ${methodEntry.methodEnum.name} not supported on ${targetPlatform ?? 'web'}', - ); - } - - result = await _executeControllerMethod(step.action, controller); - break; - case CustomTestActionType.evaluateJavascript: - if (controller == null) throw Exception('Controller not available'); - result = await controller.evaluateJavascript( - source: step.action.script ?? '', - ); - break; - case CustomTestActionType.loadUrl: - if (controller == null) throw Exception('Controller not available'); - await controller.loadUrl( - urlRequest: URLRequest(url: WebUri(step.action.url ?? '')), - ); - result = 'URL loaded'; - break; - case CustomTestActionType.loadHtml: - if (controller == null) throw Exception('Controller not available'); - await controller.loadData(data: step.action.html ?? ''); - result = 'HTML loaded'; - break; - case CustomTestActionType.checkUrl: - if (controller == null) throw Exception('Controller not available'); - final currentUrl = await controller.getUrl(); - final matches = currentUrl?.toString() == step.action.url; - result = matches ? 'URL matches' : 'URL mismatch: $currentUrl'; - if (!matches) throw Exception(result); - break; - case CustomTestActionType.checkTitle: - if (controller == null) throw Exception('Controller not available'); - final title = await controller.getTitle(); - final matches = title == step.action.text; - result = matches ? 'Title matches' : 'Title mismatch: $title'; - if (!matches) throw Exception(result); - break; - case CustomTestActionType.checkElement: - if (controller == null) throw Exception('Controller not available'); - final exists = await controller.evaluateJavascript( - source: - 'document.querySelector("${step.action.selector}") !== null', - ); - if (exists != true && exists != 'true') { - throw Exception('Element not found: ${step.action.selector}'); - } - result = 'Element found'; - break; - case CustomTestActionType.waitForElement: - if (controller == null) throw Exception('Controller not available'); - final timeout = step.action.delayMs ?? 5000; - final startWait = DateTime.now(); - bool found = false; - while (DateTime.now().difference(startWait).inMilliseconds < - timeout) { - final exists = await controller.evaluateJavascript( - source: - 'document.querySelector("${step.action.selector}") !== null', - ); - if (exists == true || exists == 'true') { - found = true; - break; - } - await Future.delayed(const Duration(milliseconds: 100)); - } - if (!found) { - throw Exception( - 'Element not found within ${timeout}ms: ${step.action.selector}', - ); - } - result = 'Element found'; - break; - case CustomTestActionType.clickElement: - if (controller == null) throw Exception('Controller not available'); - await controller.evaluateJavascript( - source: - 'document.querySelector("${step.action.selector}")?.click()', - ); - result = 'Clicked element'; - break; - case CustomTestActionType.typeText: - if (controller == null) throw Exception('Controller not available'); - await controller.evaluateJavascript( - source: - ''' - var el = document.querySelector("${step.action.selector}"); - if (el) { el.value = "${step.action.text}"; } - ''', - ); - result = 'Typed text'; - break; - case CustomTestActionType.scrollTo: - if (controller == null) throw Exception('Controller not available'); - await controller.scrollTo( - x: step.action.x ?? 0, - y: step.action.y ?? 0, - ); - result = 'Scrolled to (${step.action.x}, ${step.action.y})'; - break; - case CustomTestActionType.takeScreenshot: - if (controller == null) throw Exception('Controller not available'); - final screenshot = await controller.takeScreenshot(); - result = screenshot != null - ? 'Screenshot taken: ${screenshot.length} bytes' - : 'Screenshot failed'; - break; - case CustomTestActionType.delay: - await Future.delayed( - Duration(milliseconds: step.action.delayMs ?? 1000), - ); - result = 'Delayed ${step.action.delayMs}ms'; - break; - case CustomTestActionType.waitForNavigationEvent: - result = await _executeWaitForNavigationEvent( - step.action, - controller, - ); - break; - case CustomTestActionType.custom: - // Custom code execution would require eval or predefined functions - result = 'Custom action executed'; - break; - } - - stopwatch.stop(); - - // Validate result using the step's validation configuration - if (!step.validateResult(result)) { - return ExtendedTestResult( - testId: step.id, - testTitle: step.name, - category: step.category, - success: false, - message: - 'Validation failed (${step.expectedResultType.name}): expected "${step.expectedResult ?? 'N/A'}" but got "${result?.toString() ?? 'null'}"', - duration: stopwatch.elapsed, - timestamp: DateTime.now(), - data: {'result': result}, - ); - } - - return ExtendedTestResult( - testId: step.id, - testTitle: step.name, - category: step.category, - success: true, - message: result?.toString() ?? 'Success', - duration: stopwatch.elapsed, - timestamp: DateTime.now(), - data: {'result': result}, - ); - } catch (e, stackTrace) { - stopwatch.stop(); - debugPrint('Custom step ${step.id} failed: $e'); - debugPrint('Stack trace: $stackTrace'); - - return ExtendedTestResult( - testId: step.id, - testTitle: step.name, - category: step.category, - success: false, - message: 'Error: $e', - duration: stopwatch.elapsed, - timestamp: DateTime.now(), - data: {'error': e.toString(), 'stackTrace': stackTrace.toString()}, - ); - } - } - - /// Execute a controller method action - Future _executeControllerMethod( - CustomTestAction action, - InAppWebViewController? controller, - ) async { - if (controller == null) { - throw Exception('Controller not available'); - } - - final methodId = action.methodId; - if (methodId == null) { - throw Exception('Method ID not specified'); - } - - final method = ControllerMethodsRegistry.instance.findMethodById(methodId); - if (method == null) { - throw Exception('Method not found: $methodId'); - } - - // Merge default parameters with custom parameters - final params = { - ...method.parameters, - if (action.methodParameters != null) ...action.methodParameters!, - }; - - return await method.execute(controller, params); - } - - TargetPlatform? _getCurrentTargetPlatform() { - if (kIsWeb) return null; - return defaultTargetPlatform; - } - - /// Execute a wait for navigation event action - Future _executeWaitForNavigationEvent( - CustomTestAction action, - InAppWebViewController? controller, - ) async { - if (controller == null) { - throw Exception('Controller not available'); - } - - final event = action.navigationEvent; - if (event == null) { - throw Exception('Navigation event type not specified'); - } - - // Use broadcast streams to listen for the next event - // .first will return the next value published to the stream - switch (event) { - case NavigationEventType.onLoadStop: - final url = await _onLoadStopController.stream.first; - return 'onLoadStop triggered - loaded: $url'; - - case NavigationEventType.onLoadStart: - final url = await _onLoadStartController.stream.first; - return 'onLoadStart triggered - navigation started to $url'; - - case NavigationEventType.onProgressChanged: - _targetProgress = action.targetProgress ?? 100; - _progressComparison = - action.progressComparison ?? 'greaterThanOrEquals'; - // Filter the stream to only get progress values that match the condition - final progress = await _onProgressChangedController.stream.firstWhere(( - progress, - ) { - switch (_progressComparison) { - case 'equals': - return progress == _targetProgress; - case 'greaterThan': - return progress > _targetProgress; - case 'greaterThanOrEquals': - default: - return progress >= _targetProgress; - } - }); - return 'onProgressChanged reached $progress (target: $_progressComparison $_targetProgress)'; - - case NavigationEventType.onPageCommitVisible: - final url = await _onPageCommitVisibleController.stream.first; - return 'onPageCommitVisible triggered - page visible: $url'; - - case NavigationEventType.onTitleChanged: - final title = await _onTitleChangedController.stream.first; - return 'onTitleChanged triggered - title changed to: $title'; - - case NavigationEventType.onUpdateVisitedHistory: - final url = await _onUpdateVisitedHistoryController.stream.first; - return 'onUpdateVisitedHistory triggered - URL changed to: $url'; - } - } - - /// Run all tests from the default configuration - Future runAllTests() async { - final config = _currentConfiguration ?? TestConfiguration.defaultConfig(); - await _runCustomSteps(config.customSteps, _webViewController); - } - - /// Run tests for a specific category from the default configuration - Future runCategoryTests(TestCategory category) async { - final config = _currentConfiguration ?? TestConfiguration.defaultConfig(); - final categorySteps = config.customSteps - .where((step) => step.category == category) - .toList(); - await _runCustomSteps(categorySteps, _webViewController); - } - - /// Run tests from selected categories - Future runSelectedCategories(List categories) async { - final config = _currentConfiguration ?? TestConfiguration.defaultConfig(); - final selectedSteps = config.customSteps - .where((step) => categories.contains(step.category)) - .toList(); - await _runCustomSteps(selectedSteps, _webViewController); - } - - /// Re-run failed tests - Future rerunFailedTests() async { - final failedTestIds = _results - .where((r) => !r.success && !r.skipped) - .map((r) => r.testId) - .toSet(); - - final config = _currentConfiguration ?? TestConfiguration.defaultConfig(); - final failedSteps = config.customSteps - .where((step) => failedTestIds.contains(step.id)) - .toList(); - - // Remove old failed results - _results = _results.where((r) => r.success || r.skipped).toList(); - - await _runCustomSteps(failedSteps, _webViewController, append: true); - } - - /// Get test categories from the current or default configuration - static List getTestCategories() { - final config = TestConfiguration.defaultConfig(); - final Map> categorizedSteps = {}; - - for (final step in config.customSteps) { - categorizedSteps.putIfAbsent(step.category, () => []).add(step); - } - - return categorizedSteps.entries.map((entry) { - return TestCategoryGroup( - category: entry.key, - tests: entry.value.map((step) => _convertStepToTestCase(step)).toList(), - ); - }).toList(); - } - - /// Convert a CustomTestStep to an ExecutableTestCase for compatibility - static ExecutableTestCase _convertStepToTestCase(CustomTestStep step) { - return ExecutableTestCase( - id: step.id, - title: step.name, - description: step.description, - category: step.category, - execute: (controller) async { - // This is a placeholder - actual execution happens through _executeCustomStep - return TestResult( - passed: true, - message: 'Executed via configuration', - duration: Duration.zero, - ); - }, - ); - } - - /// Stop running tests - void stopTests() { - _shouldStop = true; - notifyListeners(); - } - - /// Clear results - void clearResults() { - _results = []; - _status = TestStatus.idle; - _currentTest = null; - _progress = 0; - _total = 0; - _startTime = null; - _endTime = null; - notifyListeners(); - } - - /// Export results as JSON - String exportResultsAsJson() { - final export = { - 'exportedAt': DateTime.now().toIso8601String(), - 'status': _status.name, - 'startTime': _startTime?.toIso8601String(), - 'endTime': _endTime?.toIso8601String(), - 'totalTests': _total, - 'passed': passed, - 'failed': failed, - 'skipped': skipped, - 'successRate': successRate, - 'results': _results.map((r) => r.toJson()).toList(), - }; - return const JsonEncoder.withIndent(' ').convert(export); - } -} diff --git a/flutter_inappwebview/example/lib/screens/advanced/controllers_screen.dart b/flutter_inappwebview/example/lib/screens/advanced/controllers_screen.dart deleted file mode 100644 index a8b9c3b26a..0000000000 --- a/flutter_inappwebview/example/lib/screens/advanced/controllers_screen.dart +++ /dev/null @@ -1,1333 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/widgets/common/app_drawer.dart'; -import 'package:flutter_inappwebview_example/widgets/common/appbar_loading_indicator.dart'; -import 'package:flutter_inappwebview_example/widgets/common/event_log_card.dart'; -import 'package:flutter_inappwebview_example/widgets/common/resize_handle.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/models/event_log_entry.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; -import 'package:flutter_inappwebview_example/widgets/common/support_badge.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_result_history.dart'; - -/// Screen for testing various WebView Controllers -class ControllersScreen extends StatefulWidget { - const ControllersScreen({super.key}); - - @override - State createState() => _ControllersScreenState(); -} - -class _ControllersScreenState extends State { - final TextEditingController _searchController = TextEditingController(); - final TextEditingController _messageController = TextEditingController(); - - InAppWebViewController? _webViewController; - FindInteractionController? _findInteractionController; - PullToRefreshController? _pullToRefreshController; - bool _webViewReady = false; - bool _isLoading = false; - double _webViewHeight = 180; - static const double _minWebViewHeight = 120; - static const double _minContentHeight = 260; - static const double _dividerHeight = 6; - static const double _minChromeHeight = 140; - - // Find interaction state - int _matchCount = 0; - int _currentMatch = 0; - - // Pull to refresh state - bool _pullToRefreshEnabled = true; - Color _pullToRefreshColor = Colors.blue; - - // Web message channel state - WebMessageChannel? _webMessageChannel; - final List _receivedMessages = []; - - final Map> _methodHistory = {}; - final Map _selectedHistoryIndex = {}; - static const int _maxHistoryEntries = 3; - - SupportedPlatform? get _currentPlatform { - if (kIsWeb) return SupportedPlatform.web; - if (Platform.isAndroid) return SupportedPlatform.android; - if (Platform.isIOS) return SupportedPlatform.ios; - if (Platform.isMacOS) return SupportedPlatform.macos; - if (Platform.isWindows) return SupportedPlatform.windows; - if (Platform.isLinux) return SupportedPlatform.linux; - return null; - } - - Set _getFindSupportedPlatforms( - PlatformFindInteractionControllerMethod method, - ) { - return SupportCheckHelper.supportedPlatformsForMethod( - method: method, - checker: FindInteractionController.isMethodSupported, - ); - } - - Set _getPullToRefreshSupportedPlatforms( - PlatformPullToRefreshControllerMethod method, - ) { - return SupportCheckHelper.supportedPlatformsForMethod( - method: method, - checker: PullToRefreshController.isMethodSupported, - ); - } - - @override - void initState() { - super.initState(); - _initControllers(); - } - - void _initControllers() { - try { - _findInteractionController = FindInteractionController( - onFindResultReceived: - (controller, activeMatchOrdinal, numberOfMatches, isDoneCounting) { - setState(() { - _currentMatch = activeMatchOrdinal; - _matchCount = numberOfMatches; - }); - _logEvent( - EventType.ui, - PlatformFindInteractionControllerCreationParamsProperty - .onFindResultReceived - .name, - data: { - 'activeMatchOrdinal': activeMatchOrdinal, - 'numberOfMatches': numberOfMatches, - 'isDoneCounting': isDoneCounting, - }, - ); - }, - ); - - _pullToRefreshController = PullToRefreshController( - settings: PullToRefreshSettings( - enabled: _pullToRefreshEnabled, - color: _pullToRefreshColor, - ), - onRefresh: () async { - _logEvent( - EventType.ui, - PlatformPullToRefreshControllerCreationParamsProperty - .onRefresh - .name, - ); - if (_webViewController != null) { - await _webViewController!.reload(); - } - }, - ); - } catch (e) { - _showInitError('Unable to initialize controllers: $e'); - } - } - - @override - void dispose() { - _searchController.dispose(); - _messageController.dispose(); - _findInteractionController?.dispose(); - _pullToRefreshController?.dispose(); - _webMessageChannel?.dispose(); - super.dispose(); - } - - void _logEvent(EventType type, String message, {Map? data}) { - context.read().addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: type, - message: message, - data: data, - ), - ); - } - - void _recordMethodResult( - String methodName, - String message, { - required bool isError, - dynamic value, - }) { - setState(() { - final entries = List.from( - _methodHistory[methodName] ?? const [], - ); - entries.insert( - 0, - MethodResultEntry( - message: message, - isError: isError, - timestamp: DateTime.now(), - value: value, - ), - ); - if (entries.length > _maxHistoryEntries) { - entries.removeRange(_maxHistoryEntries, entries.length); - } - _methodHistory[methodName] = entries; - _selectedHistoryIndex[methodName] = 0; - }); - } - - Widget _buildMethodHistory(String methodName, {String? title}) { - final entries = _methodHistory[methodName] ?? const []; - if (entries.isEmpty) { - return const SizedBox.shrink(); - } - return MethodResultHistory( - entries: entries, - selectedIndex: _selectedHistoryIndex[methodName], - title: title ?? methodName, - onSelected: (index) { - setState(() => _selectedHistoryIndex[methodName] = index); - }, - ); - } - - void _showInitError(String message) { - _recordMethodResult('initControllers', message, isError: true); - } - - Widget _buildInitStatusSection() { - final entries = _methodHistory['initControllers'] ?? const []; - if (entries.isEmpty) { - return const SizedBox.shrink(); - } - return Column( - children: [ - _buildMethodHistory('initControllers', title: 'Initialization'), - const SizedBox(height: 16), - ], - ); - } - - // Find Interaction methods - Future _findAll() async { - final params = await showParameterDialog( - context: context, - title: 'Find All', - parameters: {'find': _searchController.text.trim()}, - requiredPaths: ['find'], - ); - - if (params == null) return; - final query = params['find']?.toString() ?? ''; - if (query.isEmpty) { - _recordMethodResult( - PlatformFindInteractionControllerMethod.findAll.name, - 'Please enter search text', - isError: true, - ); - return; - } - _searchController.text = query; - await _findInteractionController?.findAll(find: query); - _recordMethodResult( - PlatformFindInteractionControllerMethod.findAll.name, - 'Searching for: $query', - isError: false, - ); - } - - Future _findNext() async { - await _findInteractionController?.findNext(forward: true); - _recordMethodResult( - PlatformFindInteractionControllerMethod.findNext.name, - 'Moved to next match', - isError: false, - ); - } - - Future _findPrevious() async { - await _findInteractionController?.findNext(forward: false); - _recordMethodResult( - '${PlatformFindInteractionControllerMethod.findNext.name} (previous)', - 'Moved to previous match', - isError: false, - ); - } - - Future _clearMatches() async { - await _findInteractionController?.clearMatches(); - setState(() { - _matchCount = 0; - _currentMatch = 0; - }); - _recordMethodResult( - PlatformFindInteractionControllerMethod.clearMatches.name, - 'Matches cleared', - isError: false, - ); - } - - Future _setSearchText() async { - final params = await showParameterDialog( - context: context, - title: 'Set Search Text', - parameters: {'searchText': _searchController.text.trim()}, - requiredPaths: ['searchText'], - ); - - if (params == null) return; - final text = params['searchText']?.toString() ?? ''; - if (text.isEmpty) { - _recordMethodResult( - PlatformFindInteractionControllerMethod.setSearchText.name, - 'Please enter search text', - isError: true, - ); - return; - } - _searchController.text = text; - await _findInteractionController?.setSearchText(text); - _recordMethodResult( - PlatformFindInteractionControllerMethod.setSearchText.name, - 'Search text set', - isError: false, - ); - } - - Future _getSearchText() async { - final text = await _findInteractionController?.getSearchText(); - _recordMethodResult( - PlatformFindInteractionControllerMethod.getSearchText.name, - 'Search text: $text', - isError: false, - ); - } - - Future _presentFindNavigator() async { - await _findInteractionController?.presentFindNavigator(); - _recordMethodResult( - PlatformFindInteractionControllerMethod.presentFindNavigator.name, - 'Find navigator presented', - isError: false, - ); - } - - Future _dismissFindNavigator() async { - await _findInteractionController?.dismissFindNavigator(); - _recordMethodResult( - PlatformFindInteractionControllerMethod.dismissFindNavigator.name, - 'Find navigator dismissed', - isError: false, - ); - } - - Future _isFindNavigatorVisible() async { - final visible = await _findInteractionController?.isFindNavigatorVisible(); - _recordMethodResult( - PlatformFindInteractionControllerMethod.isFindNavigatorVisible.name, - 'Find navigator visible: $visible', - isError: false, - ); - } - - Future _getActiveFindSession() async { - final session = await _findInteractionController?.getActiveFindSession(); - _recordMethodResult( - PlatformFindInteractionControllerMethod.getActiveFindSession.name, - 'Active session: ${session?.resultCount ?? 0} results, highlight index: ${session?.highlightedResultIndex ?? -1}', - isError: false, - ); - } - - // Pull to Refresh methods - Future _setEnabled(bool enabled) async { - await _pullToRefreshController?.setEnabled(enabled); - setState(() => _pullToRefreshEnabled = enabled); - _recordMethodResult( - PlatformPullToRefreshControllerMethod.setEnabled.name, - 'Pull to refresh ${enabled ? "enabled" : "disabled"}', - isError: false, - ); - } - - Future _isEnabled() async { - final enabled = await _pullToRefreshController?.isEnabled(); - _recordMethodResult( - PlatformPullToRefreshControllerMethod.isEnabled.name, - 'Pull to refresh enabled: $enabled', - isError: false, - ); - } - - Future _beginRefreshing() async { - await _pullToRefreshController?.beginRefreshing(); - _recordMethodResult( - PlatformPullToRefreshControllerMethod.beginRefreshing.name, - 'Refreshing started', - isError: false, - ); - } - - Future _endRefreshing() async { - await _pullToRefreshController?.endRefreshing(); - _recordMethodResult( - PlatformPullToRefreshControllerMethod.endRefreshing.name, - 'Refreshing ended', - isError: false, - ); - } - - Future _isRefreshing() async { - final refreshing = await _pullToRefreshController?.isRefreshing(); - _recordMethodResult( - PlatformPullToRefreshControllerMethod.isRefreshing.name, - 'Is refreshing: $refreshing', - isError: false, - ); - } - - Future _setColor(Color color) async { - await _pullToRefreshController?.setColor(color); - setState(() => _pullToRefreshColor = color); - _recordMethodResult( - PlatformPullToRefreshControllerMethod.setColor.name, - 'Color set', - isError: false, - ); - } - - Future _setBackgroundColor(Color color) async { - await _pullToRefreshController?.setBackgroundColor(color); - _recordMethodResult( - PlatformPullToRefreshControllerMethod.setBackgroundColor.name, - 'Background color set', - isError: false, - ); - } - - Future _promptSetColor() async { - final params = await showParameterDialog( - context: context, - title: 'Set Refresh Indicator Color', - parameters: {'color': _pullToRefreshColor}, - requiredPaths: ['color'], - ); - - if (params == null) return; - final color = params['color'] as Color?; - if (color == null) { - _recordMethodResult( - PlatformPullToRefreshControllerMethod.setColor.name, - 'Please pick a color', - isError: true, - ); - return; - } - await _setColor(color); - } - - Future _promptSetBackgroundColor() async { - final params = await showParameterDialog( - context: context, - title: 'Set Background Color', - parameters: {'color': Colors.grey.shade200}, - requiredPaths: ['color'], - ); - - if (params == null) return; - final color = params['color'] as Color?; - if (color == null) { - _recordMethodResult( - PlatformPullToRefreshControllerMethod.setBackgroundColor.name, - 'Please pick a color', - isError: true, - ); - return; - } - await _setBackgroundColor(color); - } - - Future _getDefaultSlingshotDistance() async { - final distance = await _pullToRefreshController - ?.getDefaultSlingshotDistance(); - _recordMethodResult( - PlatformPullToRefreshControllerMethod.getDefaultSlingshotDistance.name, - 'Default slingshot distance: $distance', - isError: false, - ); - } - - // Web Message Channel methods - Future _createWebMessageChannel() async { - if (_webViewController == null) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.createWebMessageChannel.name, - 'WebView not ready', - isError: true, - ); - return; - } - - try { - _webMessageChannel = await _webViewController!.createWebMessageChannel(); - if (_webMessageChannel != null) { - await _webMessageChannel!.port1.setWebMessageCallback((message) { - setState(() { - _receivedMessages.add(message?.data?.toString() ?? 'null'); - }); - _logEvent( - EventType.messaging, - 'Message received', - data: {'message': message?.data?.toString()}, - ); - }); - _recordMethodResult( - PlatformInAppWebViewControllerMethod.createWebMessageChannel.name, - 'Web message channel created', - isError: false, - ); - } - } catch (e) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.createWebMessageChannel.name, - 'Error creating channel: $e', - isError: true, - ); - } - } - - Future _postWebMessage() async { - if (_webMessageChannel == null) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.postWebMessage.name, - 'Create a channel first', - isError: true, - ); - return; - } - - final params = await showParameterDialog( - context: context, - title: 'Post Web Message', - parameters: {'message': _messageController.text.trim()}, - requiredPaths: ['message'], - ); - - if (params == null) return; - final message = params['message']?.toString() ?? ''; - if (message.isEmpty) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.postWebMessage.name, - 'Please enter a message', - isError: true, - ); - return; - } - _messageController.text = message; - - try { - await _webMessageChannel!.port1.postMessage(WebMessage(data: message)); - _recordMethodResult( - PlatformInAppWebViewControllerMethod.postWebMessage.name, - 'Message sent', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.postWebMessage.name, - 'Error sending message: $e', - isError: true, - ); - } - } - - void _closeWebMessageChannel() { - _webMessageChannel?.dispose(); - _webMessageChannel = null; - setState(() { - _receivedMessages.clear(); - }); - _recordMethodResult( - '$WebMessageChannel.${PlatformWebMessageChannelMethod.dispose.name}', - 'Channel closed', - isError: false, - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Controllers'), - actions: [ - AppBarLoadingIndicator(isLoading: _isLoading), - IconButton( - icon: const Icon(Icons.clear_all), - tooltip: 'Clear Events', - onPressed: () { - context.read().clear(); - }, - ), - ], - ), - drawer: AppDrawer(), - body: LayoutBuilder( - builder: (context, constraints) { - final minRequiredHeight = - _minWebViewHeight + - _minContentHeight + - _dividerHeight + - _minChromeHeight; - final useScroll = constraints.maxHeight < minRequiredHeight; - - if (useScroll) { - return _buildScrollableBody(); - } - - return _buildResizableBody(constraints); - }, - ), - ); - } - - Widget _buildResizableBody(BoxConstraints constraints) { - final maxWebViewHeight = - constraints.maxHeight - _minContentHeight - _dividerHeight; - final effectiveMax = maxWebViewHeight < _minWebViewHeight - ? _minWebViewHeight - : maxWebViewHeight; - final webViewHeight = _webViewHeight - .clamp(_minWebViewHeight, effectiveMax) - .toDouble(); - - return Column( - children: [ - SizedBox(height: webViewHeight, child: _buildWebViewSection()), - ResizeHandle( - height: _dividerHeight, - onDrag: (delta) { - setState(() { - _webViewHeight = (_webViewHeight + delta) - .clamp(_minWebViewHeight, effectiveMax) - .toDouble(); - }); - }, - ), - Expanded( - child: ListView( - padding: const EdgeInsets.all(16), - children: [ - _buildInitStatusSection(), - _buildFindInteractionSection(), - const SizedBox(height: 16), - _buildPullToRefreshSection(), - const SizedBox(height: 16), - _buildWebMessageChannelSection(), - const SizedBox(height: 16), - _buildPrintJobSection(), - const SizedBox(height: 16), - const EventLogCard(), - ], - ), - ), - ], - ); - } - - Widget _buildScrollableBody() { - return SingleChildScrollView( - child: Column( - children: [ - SizedBox(height: _minWebViewHeight, child: _buildWebViewSection()), - Container(height: _dividerHeight, color: Colors.grey.shade300), - Padding( - padding: const EdgeInsets.all(16), - child: Column( - children: [ - _buildInitStatusSection(), - _buildFindInteractionSection(), - const SizedBox(height: 16), - _buildPullToRefreshSection(), - const SizedBox(height: 16), - _buildWebMessageChannelSection(), - const SizedBox(height: 16), - _buildPrintJobSection(), - const SizedBox(height: 16), - const EventLogCard(), - ], - ), - ), - ], - ), - ); - } - - Widget _buildWebViewSection() { - return Container( - height: 150, - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: Stack( - children: [ - InAppWebView( - initialUrlRequest: URLRequest(url: WebUri('https://flutter.dev')), - initialSettings: InAppWebViewSettings(javaScriptEnabled: true), - findInteractionController: _findInteractionController, - pullToRefreshController: _pullToRefreshController, - onWebViewCreated: (controller) { - _webViewController = controller; - }, - onLoadStop: (controller, url) { - setState(() => _webViewReady = true); - _pullToRefreshController?.endRefreshing(); - }, - ), - Positioned( - top: 4, - left: 4, - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.7), - borderRadius: BorderRadius.circular(4), - ), - child: Text( - _webViewReady ? 'WebView Ready ✓' : 'Loading...', - style: TextStyle( - color: _webViewReady ? Colors.green : Colors.white, - fontSize: 12, - ), - ), - ), - ), - ], - ), - ); - } - - Widget _buildFindInteractionSection() { - final supportedPlatforms = SupportChecker.getSupportedPlatformsForClass( - '$FindInteractionController', - ); - - return Card( - child: ExpansionTile( - title: Row( - children: [ - Text( - '$FindInteractionController', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(width: 8), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - ), - ), - ], - ), - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Column( - children: [ - // Search input - Row( - children: [ - Expanded( - child: TextField( - controller: _searchController, - decoration: const InputDecoration( - labelText: 'Search text', - border: OutlineInputBorder(), - isDense: true, - ), - ), - ), - const SizedBox(width: 8), - ElevatedButton( - onPressed: _webViewReady ? _findAll : null, - child: const Text('Find'), - ), - ], - ), - const SizedBox(height: 8), - _buildMethodHistory( - PlatformFindInteractionControllerMethod.findAll.name, - ), - const SizedBox(height: 12), - - // Match navigation - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - IconButton( - onPressed: _webViewReady ? _findPrevious : null, - icon: const Icon(Icons.arrow_back), - tooltip: 'Previous', - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 8, - ), - decoration: BoxDecoration( - color: Colors.grey.shade200, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - '$_currentMatch / $_matchCount', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ), - IconButton( - onPressed: _webViewReady ? _findNext : null, - icon: const Icon(Icons.arrow_forward), - tooltip: 'Next', - ), - IconButton( - onPressed: _webViewReady ? _clearMatches : null, - icon: const Icon(Icons.clear), - tooltip: 'Clear', - ), - ], - ), - const Divider(), - - // Other methods - Wrap( - spacing: 8, - runSpacing: 8, - children: [ - _buildMethodChip( - PlatformFindInteractionControllerMethod - .setSearchText - .name, - _getFindSupportedPlatforms( - PlatformFindInteractionControllerMethod.setSearchText, - ), - _webViewReady ? _setSearchText : null, - ), - _buildMethodChip( - PlatformFindInteractionControllerMethod - .getSearchText - .name, - _getFindSupportedPlatforms( - PlatformFindInteractionControllerMethod.getSearchText, - ), - _webViewReady ? _getSearchText : null, - ), - _buildMethodChip( - PlatformFindInteractionControllerMethod - .presentFindNavigator - .name, - _getFindSupportedPlatforms( - PlatformFindInteractionControllerMethod - .presentFindNavigator, - ), - _webViewReady ? _presentFindNavigator : null, - ), - _buildMethodChip( - PlatformFindInteractionControllerMethod - .dismissFindNavigator - .name, - _getFindSupportedPlatforms( - PlatformFindInteractionControllerMethod - .dismissFindNavigator, - ), - _webViewReady ? _dismissFindNavigator : null, - ), - _buildMethodChip( - PlatformFindInteractionControllerMethod - .isFindNavigatorVisible - .name, - _getFindSupportedPlatforms( - PlatformFindInteractionControllerMethod - .isFindNavigatorVisible, - ), - _webViewReady ? _isFindNavigatorVisible : null, - ), - _buildMethodChip( - PlatformFindInteractionControllerMethod - .getActiveFindSession - .name, - _getFindSupportedPlatforms( - PlatformFindInteractionControllerMethod - .getActiveFindSession, - ), - _webViewReady ? _getActiveFindSession : null, - ), - ], - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildPullToRefreshSection() { - final supportedPlatforms = SupportChecker.getSupportedPlatformsForClass( - '$PullToRefreshController', - ); - - return Card( - child: ExpansionTile( - title: Row( - children: [ - Text( - '$PullToRefreshController', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(width: 8), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - ), - ), - ], - ), - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Column( - children: [ - // Enable toggle - SwitchListTile( - title: const Text('Enabled'), - value: _pullToRefreshEnabled, - onChanged: _webViewReady ? _setEnabled : null, - ), - _buildMethodHistory( - PlatformPullToRefreshControllerMethod.setEnabled.name, - ), - const Divider(), - - // Color selection - Row( - children: [ - const Text('Indicator Color:'), - const SizedBox(width: 16), - Container( - width: 32, - height: 32, - decoration: BoxDecoration( - color: _pullToRefreshColor, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: Colors.black12), - ), - ), - const SizedBox(width: 12), - ElevatedButton( - onPressed: _webViewReady ? _promptSetColor : null, - child: const Text('Pick Color'), - ), - ], - ), - const SizedBox(height: 8), - _buildMethodHistory( - PlatformPullToRefreshControllerMethod.setColor.name, - ), - const SizedBox(height: 16), - - // Methods - Wrap( - spacing: 8, - runSpacing: 8, - children: [ - _buildMethodChip( - PlatformPullToRefreshControllerMethod.isEnabled.name, - _getPullToRefreshSupportedPlatforms( - PlatformPullToRefreshControllerMethod.isEnabled, - ), - _webViewReady ? _isEnabled : null, - ), - _buildMethodChip( - PlatformPullToRefreshControllerMethod - .beginRefreshing - .name, - _getPullToRefreshSupportedPlatforms( - PlatformPullToRefreshControllerMethod.beginRefreshing, - ), - _webViewReady ? _beginRefreshing : null, - ), - _buildMethodChip( - PlatformPullToRefreshControllerMethod.endRefreshing.name, - _getPullToRefreshSupportedPlatforms( - PlatformPullToRefreshControllerMethod.endRefreshing, - ), - _webViewReady ? _endRefreshing : null, - ), - _buildMethodChip( - PlatformPullToRefreshControllerMethod.isRefreshing.name, - _getPullToRefreshSupportedPlatforms( - PlatformPullToRefreshControllerMethod.isRefreshing, - ), - _webViewReady ? _isRefreshing : null, - ), - _buildMethodChip( - PlatformPullToRefreshControllerMethod - .setBackgroundColor - .name, - _getPullToRefreshSupportedPlatforms( - PlatformPullToRefreshControllerMethod - .setBackgroundColor, - ), - _webViewReady ? _promptSetBackgroundColor : null, - ), - _buildMethodChip( - PlatformPullToRefreshControllerMethod - .getDefaultSlingshotDistance - .name, - _getPullToRefreshSupportedPlatforms( - PlatformPullToRefreshControllerMethod - .getDefaultSlingshotDistance, - ), - _webViewReady ? _getDefaultSlingshotDistance : null, - ), - ], - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildWebMessageChannelSection() { - final supportedPlatforms = SupportChecker.getSupportedPlatformsForClass( - '$WebMessageChannel', - ); - - return Card( - child: ExpansionTile( - title: Row( - children: [ - Text( - '$WebMessageChannel', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(width: 8), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - ), - ), - ], - ), - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Channel status - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: _webMessageChannel != null - ? Colors.green.shade50 - : Colors.grey.shade100, - borderRadius: BorderRadius.circular(4), - ), - child: Row( - children: [ - Icon( - _webMessageChannel != null - ? Icons.check_circle - : Icons.cancel, - color: _webMessageChannel != null - ? Colors.green - : Colors.grey, - size: 20, - ), - const SizedBox(width: 8), - Text( - _webMessageChannel != null - ? 'Channel Active' - : 'No Channel', - style: TextStyle( - color: _webMessageChannel != null - ? Colors.green - : Colors.grey, - ), - ), - ], - ), - ), - const SizedBox(height: 12), - - // Create/Close buttons - Row( - children: [ - Expanded( - child: ElevatedButton( - onPressed: _webViewReady && _webMessageChannel == null - ? _createWebMessageChannel - : null, - child: const Text('Create Channel'), - ), - ), - const SizedBox(width: 8), - Expanded( - child: ElevatedButton( - onPressed: _webMessageChannel != null - ? _closeWebMessageChannel - : null, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.red, - foregroundColor: Colors.white, - ), - child: const Text('Close Channel'), - ), - ), - ], - ), - const SizedBox(height: 8), - _buildMethodHistory( - PlatformInAppWebViewControllerMethod - .createWebMessageChannel - .name, - ), - _buildMethodHistory( - '$WebMessageChannel.${PlatformWebMessageChannelMethod.dispose.name}', - ), - const SizedBox(height: 12), - - // Message input - Row( - children: [ - Expanded( - child: TextField( - controller: _messageController, - decoration: const InputDecoration( - labelText: 'Message', - border: OutlineInputBorder(), - isDense: true, - ), - ), - ), - const SizedBox(width: 8), - ElevatedButton( - onPressed: _webMessageChannel != null - ? _postWebMessage - : null, - child: const Text('Send'), - ), - ], - ), - const SizedBox(height: 8), - _buildMethodHistory( - PlatformInAppWebViewControllerMethod.postWebMessage.name, - ), - const SizedBox(height: 12), - - // Received messages - const Text( - 'Received Messages:', - style: TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(height: 8), - Container( - height: 100, - width: double.infinity, - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.grey.shade100, - borderRadius: BorderRadius.circular(4), - border: Border.all(color: Colors.grey.shade300), - ), - child: _receivedMessages.isEmpty - ? const Center( - child: Text( - 'No messages received', - style: TextStyle(color: Colors.grey), - ), - ) - : ListView.builder( - itemCount: _receivedMessages.length, - itemBuilder: (context, index) { - return Text( - '${index + 1}. ${_receivedMessages[index]}', - style: const TextStyle(fontSize: 12), - ); - }, - ), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildPrintJobSection() { - final supportedPlatforms = SupportChecker.getSupportedPlatformsForClass( - '$PrintJobController', - ); - - return Card( - child: ExpansionTile( - title: Row( - children: [ - Text( - '$PrintJobController', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(width: 8), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - ), - ), - ], - ), - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '$PrintJobController is obtained from onPrintRequest callback when printing.', - style: TextStyle(fontSize: 12, color: Colors.grey), - ), - const SizedBox(height: 12), - ElevatedButton.icon( - onPressed: _webViewReady - ? () async { - await _webViewController?.printCurrentPage(); - _logEvent(EventType.ui, 'Print requested'); - } - : null, - icon: const Icon(Icons.print), - label: const Text('Print Page'), - ), - const SizedBox(height: 12), - Text( - 'Available methods when $PrintJobController is obtained:', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 12, - ), - ), - const SizedBox(height: 8), - Wrap( - spacing: 8, - runSpacing: 8, - children: [ - _buildMethodChip( - PlatformPrintJobControllerMethod.cancel.name, - SupportCheckHelper.supportedPlatformsForMethod( - method: PlatformPrintJobControllerMethod.cancel, - checker: PrintJobController.isMethodSupported, - ), - null, - enabled: false, - ), - _buildMethodChip( - PlatformPrintJobControllerMethod.restart.name, - SupportCheckHelper.supportedPlatformsForMethod( - method: PlatformPrintJobControllerMethod.restart, - checker: PrintJobController.isMethodSupported, - ), - null, - enabled: false, - ), - _buildMethodChip( - PlatformPrintJobControllerMethod.dismiss.name, - SupportCheckHelper.supportedPlatformsForMethod( - method: PlatformPrintJobControllerMethod.dismiss, - checker: PrintJobController.isMethodSupported, - ), - null, - enabled: false, - ), - _buildMethodChip( - PlatformPrintJobControllerMethod.getInfo.name, - SupportCheckHelper.supportedPlatformsForMethod( - method: PlatformPrintJobControllerMethod.getInfo, - checker: PrintJobController.isMethodSupported, - ), - null, - enabled: false, - ), - ], - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildMethodChip( - String label, - Set supportedPlatforms, - VoidCallback? onPressed, { - bool enabled = true, - }) { - final currentPlatform = _currentPlatform; - final isSupported = - currentPlatform != null && supportedPlatforms.contains(currentPlatform); - final canPress = enabled && isSupported && onPressed != null; - - return Tooltip( - message: 'Availability depends on platform', - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ActionChip( - label: Text( - label, - style: TextStyle( - fontSize: 12, - color: canPress ? Colors.black : Colors.grey.shade600, - ), - ), - backgroundColor: canPress - ? Colors.blue.shade50 - : Colors.grey.shade100, - side: canPress - ? BorderSide(color: Colors.blue.shade200) - : BorderSide(color: Colors.grey.shade300), - onPressed: canPress ? onPressed : null, - ), - const SizedBox(height: 4), - SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - const SizedBox(height: 6), - _buildMethodHistory(label), - ], - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/screens/advanced/service_controllers_screen.dart b/flutter_inappwebview/example/lib/screens/advanced/service_controllers_screen.dart deleted file mode 100644 index 114dc4ce27..0000000000 --- a/flutter_inappwebview/example/lib/screens/advanced/service_controllers_screen.dart +++ /dev/null @@ -1,1710 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/widgets/common/app_drawer.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/models/event_log_entry.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; -import 'package:flutter_inappwebview_example/widgets/common/support_badge.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_result_history.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; -import 'package:flutter_inappwebview_example/widgets/common/profile_selector_card.dart'; -import 'package:flutter_inappwebview_example/utils/responsive_utils.dart'; -import 'package:flutter_inappwebview_example/widgets/common/responsive_row.dart'; - -/// Screen for testing service-level controllers -class ServiceControllersScreen extends StatefulWidget { - const ServiceControllersScreen({super.key}); - - @override - State createState() => - _ServiceControllersScreenState(); -} - -class _ServiceControllersScreenState extends State { - bool _isLoading = false; - - // ServiceWorkerController state - bool _allowContentAccess = true; - bool _allowFileAccess = true; - bool _blockNetworkLoads = false; - CacheMode? _cacheMode = CacheMode.LOAD_DEFAULT; - - // ProxyController state - final TextEditingController _proxyHostController = TextEditingController( - text: '127.0.0.1', - ); - final TextEditingController _proxyPortController = TextEditingController( - text: '8080', - ); - final TextEditingController _bypassListController = TextEditingController(); - - // TracingController state - bool _isTracing = false; - - // WebViewEnvironment state - String? _availableVersion; - List _processInfos = []; - int _lastEnvironmentRevision = -1; - - // ProcessGlobalConfig state - final TextEditingController _dataDirSuffixController = TextEditingController( - text: 'test_suffix', - ); - - final Map> _methodHistory = {}; - final Map _selectedHistoryIndex = {}; - static const int _maxHistoryEntries = 3; - - Set _mergePlatforms( - Set first, - Set second, - ) { - return {...first, ...second}; - } - - Set _serviceWorkerPlatforms( - PlatformServiceWorkerControllerMethod method, - ) { - return SupportCheckHelper.supportedPlatformsForMethod( - method: method, - checker: ServiceWorkerController.isMethodSupported, - ); - } - - Set _proxyControllerPlatforms( - PlatformProxyControllerMethod method, - ) { - return SupportCheckHelper.supportedPlatformsForMethod( - method: method, - checker: ProxyController.isMethodSupported, - ); - } - - Set _tracingControllerPlatforms( - PlatformTracingControllerMethod method, - ) { - return SupportCheckHelper.supportedPlatformsForMethod( - method: method, - checker: TracingController.isMethodSupported, - ); - } - - Set _webViewEnvironmentPlatforms( - PlatformWebViewEnvironmentMethod method, - ) { - return SupportCheckHelper.supportedPlatformsForMethod( - method: method, - checker: WebViewEnvironment.isMethodSupported, - ); - } - - Set _processGlobalConfigPlatforms( - PlatformProcessGlobalConfigMethod method, - ) { - return SupportCheckHelper.supportedPlatformsForMethod( - method: method, - checker: ProcessGlobalConfig.isMethodSupported, - ); - } - - @override - void dispose() { - _proxyHostController.dispose(); - _proxyPortController.dispose(); - _bypassListController.dispose(); - _dataDirSuffixController.dispose(); - super.dispose(); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - final settingsManager = context.watch(); - if (_lastEnvironmentRevision != settingsManager.environmentRevision) { - _lastEnvironmentRevision = settingsManager.environmentRevision; - setState(() { - _processInfos = []; - _availableVersion = null; - }); - } - } - - void _logEvent(EventType type, String message, {Map? data}) { - context.read().addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: type, - message: message, - data: data, - ), - ); - } - - void _recordMethodResult( - String methodName, - String message, { - required bool isError, - dynamic value, - }) { - setState(() { - final entries = List.from( - _methodHistory[methodName] ?? const [], - ); - entries.insert( - 0, - MethodResultEntry( - message: message, - isError: isError, - timestamp: DateTime.now(), - value: value, - ), - ); - if (entries.length > _maxHistoryEntries) { - entries.removeRange(_maxHistoryEntries, entries.length); - } - _methodHistory[methodName] = entries; - _selectedHistoryIndex[methodName] = 0; - }); - } - - Widget _buildMethodHistory(String methodName, {String? title}) { - final entries = _methodHistory[methodName] ?? const []; - if (entries.isEmpty) { - return const SizedBox.shrink(); - } - return MethodResultHistory( - entries: entries, - selectedIndex: _selectedHistoryIndex[methodName], - title: title ?? methodName, - onSelected: (index) { - setState(() => _selectedHistoryIndex[methodName] = index); - }, - ); - } - - TracingMode _parseTracingMode(String? value) { - if (value == null || value.isEmpty) { - return TracingMode.RECORD_CONTINUOUSLY; - } - return TracingMode.values.firstWhere( - (mode) => mode.name().toLowerCase() == value.toLowerCase(), - orElse: () => TracingMode.RECORD_CONTINUOUSLY, - ); - } - - List _parseTracingCategories(dynamic raw) { - if (raw is! List) { - return [TracingCategory.CATEGORIES_WEB_DEVELOPER]; - } - final categories = []; - for (final entry in raw) { - final name = entry.toString().toLowerCase(); - final matched = TracingCategory.values.firstWhere( - (category) => category.name().toLowerCase() == name, - orElse: () => TracingCategory.CATEGORIES_WEB_DEVELOPER, - ); - categories.add(matched); - } - return categories.isEmpty - ? [TracingCategory.CATEGORIES_WEB_DEVELOPER] - : categories; - } - - // ServiceWorkerController methods - Future _getAllowContentAccess() async { - setState(() => _isLoading = true); - try { - final value = await ServiceWorkerController.getAllowContentAccess(); - setState(() => _allowContentAccess = value); - _recordMethodResult( - PlatformServiceWorkerControllerMethod.getAllowContentAccess.name, - 'Allow content access: $value', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformServiceWorkerControllerMethod.getAllowContentAccess.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _setAllowContentAccess(bool value) async { - setState(() => _isLoading = true); - try { - await ServiceWorkerController.setAllowContentAccess(value); - setState(() => _allowContentAccess = value); - _recordMethodResult( - PlatformServiceWorkerControllerMethod.setAllowContentAccess.name, - 'Allow content access set to: $value', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformServiceWorkerControllerMethod.setAllowContentAccess.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getAllowFileAccess() async { - setState(() => _isLoading = true); - try { - final value = await ServiceWorkerController.getAllowFileAccess(); - setState(() => _allowFileAccess = value); - _recordMethodResult( - PlatformServiceWorkerControllerMethod.getAllowFileAccess.name, - 'Allow file access: $value', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformServiceWorkerControllerMethod.getAllowFileAccess.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _setAllowFileAccess(bool value) async { - setState(() => _isLoading = true); - try { - await ServiceWorkerController.setAllowFileAccess(value); - setState(() => _allowFileAccess = value); - _recordMethodResult( - PlatformServiceWorkerControllerMethod.setAllowFileAccess.name, - 'Allow file access set to: $value', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformServiceWorkerControllerMethod.setAllowFileAccess.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getBlockNetworkLoads() async { - setState(() => _isLoading = true); - try { - final value = await ServiceWorkerController.getBlockNetworkLoads(); - setState(() => _blockNetworkLoads = value); - _recordMethodResult( - PlatformServiceWorkerControllerMethod.getBlockNetworkLoads.name, - 'Block network loads: $value', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformServiceWorkerControllerMethod.getBlockNetworkLoads.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _setBlockNetworkLoads(bool value) async { - setState(() => _isLoading = true); - try { - await ServiceWorkerController.setBlockNetworkLoads(value); - setState(() => _blockNetworkLoads = value); - _recordMethodResult( - PlatformServiceWorkerControllerMethod.setBlockNetworkLoads.name, - 'Block network loads set to: $value', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformServiceWorkerControllerMethod.setBlockNetworkLoads.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getCacheMode() async { - setState(() => _isLoading = true); - try { - final value = await ServiceWorkerController.getCacheMode(); - setState(() => _cacheMode = value); - _recordMethodResult( - PlatformServiceWorkerControllerMethod.getCacheMode.name, - 'Cache mode: ${value?.name}', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformServiceWorkerControllerMethod.getCacheMode.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _setCacheMode(CacheMode mode) async { - setState(() => _isLoading = true); - try { - await ServiceWorkerController.setCacheMode(mode); - setState(() => _cacheMode = mode); - _recordMethodResult( - PlatformServiceWorkerControllerMethod.setCacheMode.name, - 'Cache mode set to: ${mode.name}', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformServiceWorkerControllerMethod.setCacheMode.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - // ProxyController methods - Future _setProxyOverride() async { - final params = await showParameterDialog( - context: context, - title: 'Set Proxy Override', - parameters: { - 'host': _proxyHostController.text.trim(), - 'port': int.tryParse(_proxyPortController.text.trim()) ?? 8080, - 'bypassList': _bypassListController.text - .split(',') - .map((e) => e.trim()) - .where((e) => e.isNotEmpty) - .toList(), - }, - requiredPaths: ['host', 'port'], - ); - - if (params == null) return; - final host = params['host']?.toString() ?? ''; - final port = (params['port'] as num?)?.toInt() ?? 8080; - final bypassList = - (params['bypassList'] as List?) - ?.map((e) => e.toString().trim()) - .where((e) => e.isNotEmpty) - .toList() ?? - []; - - _proxyHostController.text = host; - _proxyPortController.text = port.toString(); - _bypassListController.text = bypassList.join(', '); - - setState(() => _isLoading = true); - try { - await ProxyController.instance().setProxyOverride( - settings: ProxySettings( - proxyRules: [ProxyRule(url: '$host:$port')], - bypassRules: bypassList, - ), - ); - _recordMethodResult( - PlatformProxyControllerMethod.setProxyOverride.name, - 'Proxy override set', - isError: false, - ); - _logEvent( - EventType.network, - 'Proxy set', - data: {'host': host, 'port': port, 'bypassList': bypassList}, - ); - } catch (e) { - _recordMethodResult( - PlatformProxyControllerMethod.setProxyOverride.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _clearProxyOverride() async { - setState(() => _isLoading = true); - try { - await ProxyController.instance().clearProxyOverride(); - _recordMethodResult( - PlatformProxyControllerMethod.clearProxyOverride.name, - 'Proxy override cleared', - isError: false, - ); - _logEvent(EventType.network, 'Proxy cleared'); - } catch (e) { - _recordMethodResult( - PlatformProxyControllerMethod.clearProxyOverride.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - // TracingController methods - Future _startTracing() async { - final params = await showParameterDialog( - context: context, - title: 'Start Tracing', - parameters: { - 'tracingMode': 'RECORD_CONTINUOUSLY', - 'categories': ['CATEGORIES_WEB_DEVELOPER'], - }, - requiredPaths: ['tracingMode'], - ); - - if (params == null) return; - final tracingMode = _parseTracingMode(params['tracingMode']?.toString()); - final categories = _parseTracingCategories(params['categories']); - - setState(() => _isLoading = true); - try { - await TracingController.instance().start( - settings: TracingSettings( - tracingMode: tracingMode, - categories: categories, - ), - ); - setState(() => _isTracing = true); - _recordMethodResult( - PlatformTracingControllerMethod.start.name, - 'Tracing started', - isError: false, - ); - _logEvent(EventType.performance, 'Tracing started'); - } catch (e) { - _recordMethodResult( - PlatformTracingControllerMethod.start.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _stopTracing() async { - setState(() => _isLoading = true); - try { - final result = await TracingController.instance().stop(); - setState(() => _isTracing = false); - _recordMethodResult( - PlatformTracingControllerMethod.stop.name, - 'Tracing stopped: $result', - isError: false, - ); - _logEvent( - EventType.performance, - 'Tracing stopped', - data: {'result': result}, - ); - } catch (e) { - _recordMethodResult( - PlatformTracingControllerMethod.stop.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _checkIsTracing() async { - setState(() => _isLoading = true); - try { - final tracing = await TracingController.instance().isTracing(); - setState(() => _isTracing = tracing); - _recordMethodResult( - PlatformTracingControllerMethod.isTracing.name, - 'Is tracing: $tracing', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformTracingControllerMethod.isTracing.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - // WebViewEnvironment methods - Future _createWebViewEnvironment() async { - setState(() => _isLoading = true); - try { - await context.read().recreateEnvironment(); - _recordMethodResult( - PlatformWebViewEnvironmentMethod.create.name, - '$WebViewEnvironment created', - isError: false, - ); - _logEvent(EventType.ui, '$WebViewEnvironment created'); - } catch (e) { - _recordMethodResult( - PlatformWebViewEnvironmentMethod.create.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getAvailableVersion() async { - setState(() => _isLoading = true); - try { - final version = await WebViewEnvironment.getAvailableVersion(); - setState(() => _availableVersion = version); - _recordMethodResult( - PlatformWebViewEnvironmentMethod.getAvailableVersion.name, - 'Available version: $version', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformWebViewEnvironmentMethod.getAvailableVersion.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _compareBrowserVersions() async { - final params = await showParameterDialog( - context: context, - title: 'Compare Browser Versions', - parameters: {'version1': '100.0.0.0', 'version2': '99.0.0.0'}, - requiredPaths: ['version1', 'version2'], - ); - - if (params == null) return; - final version1 = params['version1']?.toString() ?? ''; - final version2 = params['version2']?.toString() ?? ''; - if (version1.isEmpty || version2.isEmpty) { - _recordMethodResult( - PlatformWebViewEnvironmentMethod.compareBrowserVersions.name, - 'Both versions are required', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final result = await WebViewEnvironment.compareBrowserVersions( - version1: version1, - version2: version2, - ); - _recordMethodResult( - PlatformWebViewEnvironmentMethod.compareBrowserVersions.name, - 'Compare versions: $result (positive = v1 > v2, negative = v1 < v2)', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformWebViewEnvironmentMethod.compareBrowserVersions.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getProcessInfos() async { - final environment = context.read().webViewEnvironment; - if (environment == null) { - _recordMethodResult( - PlatformWebViewEnvironmentMethod.getProcessInfos.name, - 'Create or select $WebViewEnvironment first', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final infos = await environment.getProcessInfos(); - setState(() => _processInfos = infos); - _recordMethodResult( - PlatformWebViewEnvironmentMethod.getProcessInfos.name, - 'Found ${infos.length} processes', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformWebViewEnvironmentMethod.getProcessInfos.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getFailureReportFolderPath() async { - final environment = context.read().webViewEnvironment; - if (environment == null) { - _recordMethodResult( - PlatformWebViewEnvironmentMethod.getFailureReportFolderPath.name, - 'Create or select $WebViewEnvironment first', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final path = await environment.getFailureReportFolderPath(); - _recordMethodResult( - PlatformWebViewEnvironmentMethod.getFailureReportFolderPath.name, - 'Failure report folder: $path', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformWebViewEnvironmentMethod.getFailureReportFolderPath.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _disposeWebViewEnvironment() async { - setState(() => _isLoading = true); - try { - await context.read().disposeEnvironment(); - setState(() => _processInfos = []); - _recordMethodResult( - PlatformWebViewEnvironmentMethod.dispose.name, - '$WebViewEnvironment disposed', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformWebViewEnvironmentMethod.dispose.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - // ProcessGlobalConfig methods - Future _applyProcessGlobalConfig() async { - final params = await showParameterDialog( - context: context, - title: 'Apply Process Global Config', - parameters: {'dataDirectorySuffix': _dataDirSuffixController.text.trim()}, - requiredPaths: ['dataDirectorySuffix'], - ); - - if (params == null) return; - final suffix = params['dataDirectorySuffix']?.toString() ?? ''; - if (suffix.isEmpty) { - _recordMethodResult( - PlatformProcessGlobalConfigMethod.apply.name, - 'Please enter a data directory suffix', - isError: true, - ); - return; - } - _dataDirSuffixController.text = suffix; - - setState(() => _isLoading = true); - try { - await ProcessGlobalConfig.instance().apply( - settings: ProcessGlobalConfigSettings(dataDirectorySuffix: suffix), - ); - _recordMethodResult( - PlatformProcessGlobalConfigMethod.apply.name, - '$ProcessGlobalConfig applied', - isError: false, - ); - _logEvent( - EventType.ui, - '$ProcessGlobalConfig applied', - data: {'dataDirectorySuffix': suffix}, - ); - } catch (e) { - _recordMethodResult( - PlatformProcessGlobalConfigMethod.apply.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Service Controllers'), - actions: [ - if (_isLoading) - const Padding( - padding: EdgeInsets.all(16), - child: SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - strokeWidth: 2, - color: Colors.white, - ), - ), - ), - IconButton( - icon: const Icon(Icons.clear_all), - tooltip: 'Clear Events', - onPressed: () { - context.read().clear(); - }, - ), - ], - ), - drawer: AppDrawer(), - body: ListView( - padding: const EdgeInsets.all(16), - children: [ - ProfileSelectorCard( - onEditSettingsProfile: () => - Navigator.pushNamed(context, '/settings'), - ), - const SizedBox(height: 16), - _buildServiceWorkerSection(), - const SizedBox(height: 16), - _buildProxyControllerSection(), - const SizedBox(height: 16), - _buildTracingControllerSection(), - const SizedBox(height: 16), - _buildWebViewEnvironmentSection(), - const SizedBox(height: 16), - _buildProcessGlobalConfigSection(), - const SizedBox(height: 16), - _buildEventLog(), - ], - ), - ); - } - - Widget _buildServiceWorkerSection() { - final supportedPlatforms = SupportChecker.getSupportedPlatformsForClass( - '$ServiceWorkerController', - ); - - return Card( - child: ExpansionTile( - title: Row( - children: [ - Text( - '$ServiceWorkerController', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(width: 8), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - ), - ), - ], - ), - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Column( - children: [ - // Boolean settings - _buildSwitchRow( - 'Allow Content Access', - _allowContentAccess, - (value) => _setAllowContentAccess(value), - _getAllowContentAccess, - _mergePlatforms( - _serviceWorkerPlatforms( - PlatformServiceWorkerControllerMethod - .getAllowContentAccess, - ), - _serviceWorkerPlatforms( - PlatformServiceWorkerControllerMethod - .setAllowContentAccess, - ), - ), - getMethodName: PlatformServiceWorkerControllerMethod - .getAllowContentAccess - .name, - setMethodName: PlatformServiceWorkerControllerMethod - .setAllowContentAccess - .name, - ), - _buildSwitchRow( - 'Allow File Access', - _allowFileAccess, - (value) => _setAllowFileAccess(value), - _getAllowFileAccess, - _mergePlatforms( - _serviceWorkerPlatforms( - PlatformServiceWorkerControllerMethod.getAllowFileAccess, - ), - _serviceWorkerPlatforms( - PlatformServiceWorkerControllerMethod.setAllowFileAccess, - ), - ), - getMethodName: PlatformServiceWorkerControllerMethod - .getAllowFileAccess - .name, - setMethodName: PlatformServiceWorkerControllerMethod - .setAllowFileAccess - .name, - ), - _buildSwitchRow( - 'Block Network Loads', - _blockNetworkLoads, - (value) => _setBlockNetworkLoads(value), - _getBlockNetworkLoads, - _mergePlatforms( - _serviceWorkerPlatforms( - PlatformServiceWorkerControllerMethod - .getBlockNetworkLoads, - ), - _serviceWorkerPlatforms( - PlatformServiceWorkerControllerMethod - .setBlockNetworkLoads, - ), - ), - getMethodName: PlatformServiceWorkerControllerMethod - .getBlockNetworkLoads - .name, - setMethodName: PlatformServiceWorkerControllerMethod - .setBlockNetworkLoads - .name, - ), - const Divider(), - - // Cache mode dropdown - Row( - children: [ - const Text('Cache Mode:'), - const SizedBox(width: 16), - Expanded( - child: DropdownButton( - value: _cacheMode, - isExpanded: true, - items: CacheMode.values - .map( - (mode) => DropdownMenuItem( - value: mode, - child: Text( - mode.name(), - style: const TextStyle(fontSize: 12), - ), - ), - ) - .toList(), - onChanged: (mode) { - if (mode != null) { - _setCacheMode(mode); - } - }, - ), - ), - IconButton( - icon: const Icon(Icons.refresh, size: 20), - onPressed: _getCacheMode, - tooltip: 'Get current', - ), - ], - ), - const SizedBox(height: 8), - SupportBadgesRow( - supportedPlatforms: _mergePlatforms( - _serviceWorkerPlatforms( - PlatformServiceWorkerControllerMethod.getCacheMode, - ), - _serviceWorkerPlatforms( - PlatformServiceWorkerControllerMethod.setCacheMode, - ), - ), - compact: true, - ), - const SizedBox(height: 6), - _buildMethodHistory( - PlatformServiceWorkerControllerMethod.getCacheMode.name, - title: - PlatformServiceWorkerControllerMethod.getCacheMode.name, - ), - _buildMethodHistory( - PlatformServiceWorkerControllerMethod.setCacheMode.name, - title: - PlatformServiceWorkerControllerMethod.setCacheMode.name, - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildSwitchRow( - String label, - bool value, - Function(bool) onChanged, - VoidCallback onRefresh, - Set supportedPlatforms, { - required String getMethodName, - required String setMethodName, - }) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LayoutBuilder( - builder: (context, constraints) { - final isMobile = ResponsiveBreakpoints.isMobileWidth( - constraints.maxWidth, - ); - final controls = Row( - mainAxisSize: MainAxisSize.min, - children: [ - Switch(value: value, onChanged: onChanged), - IconButton( - icon: const Icon(Icons.refresh, size: 20), - onPressed: onRefresh, - tooltip: 'Get current', - ), - ], - ); - - return ResponsiveRow( - spacing: 8, - runSpacing: 8, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - isMobile ? Text(label) : Expanded(child: Text(label)), - controls, - ], - ); - }, - ), - SupportBadgesRow(supportedPlatforms: supportedPlatforms, compact: true), - const SizedBox(height: 6), - _buildMethodHistory(setMethodName, title: setMethodName), - _buildMethodHistory(getMethodName, title: getMethodName), - const SizedBox(height: 8), - ], - ); - } - - Widget _buildProxyControllerSection() { - final supportedPlatforms = SupportChecker.getSupportedPlatformsForClass( - '$ProxyController', - ); - - return Card( - child: ExpansionTile( - title: Row( - children: [ - Text( - '$ProxyController', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(width: 8), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - ), - ), - ], - ), - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Column( - children: [ - LayoutBuilder( - builder: (context, constraints) { - final isMobile = ResponsiveBreakpoints.isMobileWidth( - constraints.maxWidth, - ); - final hostField = TextField( - controller: _proxyHostController, - decoration: const InputDecoration( - labelText: 'Host', - border: OutlineInputBorder(), - isDense: true, - ), - ); - final portField = TextField( - controller: _proxyPortController, - decoration: const InputDecoration( - labelText: 'Port', - border: OutlineInputBorder(), - isDense: true, - ), - keyboardType: TextInputType.number, - ); - - return ResponsiveRow( - rowKey: const Key('service_controllers_proxy_row'), - columnKey: const Key('service_controllers_proxy_column'), - spacing: 8, - runSpacing: 8, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isMobile - ? hostField - : Expanded(flex: 2, child: hostField), - isMobile ? portField : Expanded(child: portField), - ], - ); - }, - ), - const SizedBox(height: 12), - TextField( - controller: _bypassListController, - decoration: const InputDecoration( - labelText: 'Bypass List (comma-separated)', - hintText: 'localhost, 127.0.0.1', - border: OutlineInputBorder(), - isDense: true, - ), - ), - const SizedBox(height: 12), - LayoutBuilder( - builder: (context, constraints) { - final isMobile = ResponsiveBreakpoints.isMobileWidth( - constraints.maxWidth, - ); - final setButton = _buildMethodButton( - 'Set Proxy', - _setProxyOverride, - supportedPlatforms: _proxyControllerPlatforms( - PlatformProxyControllerMethod.setProxyOverride, - ), - methodName: - PlatformProxyControllerMethod.setProxyOverride.name, - ); - final clearButton = _buildMethodButton( - 'Clear Proxy', - _clearProxyOverride, - supportedPlatforms: _proxyControllerPlatforms( - PlatformProxyControllerMethod.clearProxyOverride, - ), - methodName: - PlatformProxyControllerMethod.clearProxyOverride.name, - ); - - return ResponsiveRow( - spacing: 8, - runSpacing: 8, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isMobile ? setButton : Expanded(child: setButton), - isMobile ? clearButton : Expanded(child: clearButton), - ], - ); - }, - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildTracingControllerSection() { - final supportedPlatforms = SupportChecker.getSupportedPlatformsForClass( - '$TracingController', - ); - - return Card( - child: ExpansionTile( - title: Row( - children: [ - Text( - '$TracingController', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(width: 8), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - ), - ), - ], - ), - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Column( - children: [ - // Status indicator - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: _isTracing - ? Colors.green.shade50 - : Colors.grey.shade100, - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - Icon( - _isTracing ? Icons.fiber_manual_record : Icons.stop, - color: _isTracing ? Colors.red : Colors.grey, - size: 24, - ), - const SizedBox(width: 8), - Text( - _isTracing ? 'Tracing Active' : 'Tracing Stopped', - style: TextStyle( - fontWeight: FontWeight.bold, - color: _isTracing ? Colors.green : Colors.grey, - ), - ), - ], - ), - ), - const SizedBox(height: 12), - - // Control buttons - LayoutBuilder( - builder: (context, constraints) { - final isMobile = ResponsiveBreakpoints.isMobileWidth( - constraints.maxWidth, - ); - final startButton = _buildMethodButton( - 'Start', - !_isTracing ? _startTracing : null, - supportedPlatforms: _tracingControllerPlatforms( - PlatformTracingControllerMethod.start, - ), - methodName: PlatformTracingControllerMethod.start.name, - ); - final stopButton = _buildMethodButton( - 'Stop', - _isTracing ? _stopTracing : null, - supportedPlatforms: _tracingControllerPlatforms( - PlatformTracingControllerMethod.stop, - ), - methodName: PlatformTracingControllerMethod.stop.name, - ); - final statusButton = _buildMethodButton( - 'Is Tracing', - _checkIsTracing, - supportedPlatforms: _tracingControllerPlatforms( - PlatformTracingControllerMethod.isTracing, - ), - methodName: - PlatformTracingControllerMethod.isTracing.name, - ); - - return ResponsiveRow( - spacing: 8, - runSpacing: 8, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isMobile ? startButton : Expanded(child: startButton), - isMobile ? stopButton : Expanded(child: stopButton), - isMobile ? statusButton : Expanded(child: statusButton), - ], - ); - }, - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildWebViewEnvironmentSection() { - final settingsManager = context.watch(); - final environment = settingsManager.webViewEnvironment; - final supportedPlatforms = SupportChecker.getSupportedPlatformsForClass( - '$WebViewEnvironment', - ); - - return Card( - child: ExpansionTile( - title: Row( - children: [ - Text( - '$WebViewEnvironment', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(width: 8), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - ), - ), - ], - ), - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Environment status - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: environment != null - ? Colors.green.shade50 - : Colors.grey.shade100, - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - Icon( - environment != null ? Icons.check_circle : Icons.cancel, - color: environment != null ? Colors.green : Colors.grey, - size: 24, - ), - const SizedBox(width: 8), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - environment != null - ? 'Environment Active' - : 'No Environment', - style: const TextStyle( - fontWeight: FontWeight.bold, - ), - ), - if (environment != null) - Text( - 'ID: ${environment.id}', - style: TextStyle( - fontSize: 12, - color: Colors.grey.shade600, - ), - ), - if (_availableVersion != null) - Text( - 'Version: $_availableVersion', - style: TextStyle( - fontSize: 12, - color: Colors.grey.shade600, - ), - ), - ], - ), - ), - ], - ), - ), - const SizedBox(height: 12), - - // Create/Dispose buttons - LayoutBuilder( - builder: (context, constraints) { - final isMobile = ResponsiveBreakpoints.isMobileWidth( - constraints.maxWidth, - ); - final createButton = _buildMethodButton( - 'Create', - environment == null ? _createWebViewEnvironment : null, - supportedPlatforms: _webViewEnvironmentPlatforms( - PlatformWebViewEnvironmentMethod.create, - ), - methodName: PlatformWebViewEnvironmentMethod.create.name, - ); - final disposeButton = _buildMethodButton( - 'Dispose', - environment != null ? _disposeWebViewEnvironment : null, - supportedPlatforms: _webViewEnvironmentPlatforms( - PlatformWebViewEnvironmentMethod.dispose, - ), - methodName: PlatformWebViewEnvironmentMethod.dispose.name, - ); - - return ResponsiveRow( - spacing: 8, - runSpacing: 8, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isMobile ? createButton : Expanded(child: createButton), - isMobile - ? disposeButton - : Expanded(child: disposeButton), - ], - ); - }, - ), - const SizedBox(height: 8), - - // Static methods - LayoutBuilder( - builder: (context, constraints) { - final isMobile = ResponsiveBreakpoints.isMobileWidth( - constraints.maxWidth, - ); - final versionButton = _buildMethodButton( - 'Get Version', - _getAvailableVersion, - supportedPlatforms: _webViewEnvironmentPlatforms( - PlatformWebViewEnvironmentMethod.getAvailableVersion, - ), - methodName: PlatformWebViewEnvironmentMethod - .getAvailableVersion - .name, - ); - final compareButton = _buildMethodButton( - 'Compare Versions', - _compareBrowserVersions, - supportedPlatforms: _webViewEnvironmentPlatforms( - PlatformWebViewEnvironmentMethod.compareBrowserVersions, - ), - methodName: PlatformWebViewEnvironmentMethod - .compareBrowserVersions - .name, - ); - - return ResponsiveRow( - spacing: 8, - runSpacing: 8, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isMobile - ? versionButton - : Expanded(child: versionButton), - isMobile - ? compareButton - : Expanded(child: compareButton), - ], - ); - }, - ), - const SizedBox(height: 8), - - // Instance methods - LayoutBuilder( - builder: (context, constraints) { - final isMobile = ResponsiveBreakpoints.isMobileWidth( - constraints.maxWidth, - ); - final processesButton = _buildMethodButton( - 'Get Processes', - environment != null ? _getProcessInfos : null, - supportedPlatforms: _webViewEnvironmentPlatforms( - PlatformWebViewEnvironmentMethod.getProcessInfos, - ), - methodName: - PlatformWebViewEnvironmentMethod.getProcessInfos.name, - ); - final failureButton = _buildMethodButton( - 'Failure Folder', - environment != null ? _getFailureReportFolderPath : null, - supportedPlatforms: _webViewEnvironmentPlatforms( - PlatformWebViewEnvironmentMethod - .getFailureReportFolderPath, - ), - methodName: PlatformWebViewEnvironmentMethod - .getFailureReportFolderPath - .name, - ); - - return ResponsiveRow( - spacing: 8, - runSpacing: 8, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isMobile - ? processesButton - : Expanded(child: processesButton), - isMobile - ? failureButton - : Expanded(child: failureButton), - ], - ); - }, - ), - - // Process list - if (_processInfos.isNotEmpty) ...[ - const SizedBox(height: 12), - const Text( - 'Process Infos:', - style: TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(height: 8), - Container( - height: 100, - decoration: BoxDecoration( - color: Colors.grey.shade100, - borderRadius: BorderRadius.circular(4), - ), - child: ListView.builder( - itemCount: _processInfos.length, - itemBuilder: (context, index) { - final info = _processInfos[index]; - return ListTile( - dense: true, - title: Text('Process ${index + 1}'), - subtitle: Text('Kind: ${info.kind.name()}'), - ); - }, - ), - ), - ], - ], - ), - ), - ], - ), - ); - } - - Widget _buildProcessGlobalConfigSection() { - final supportedPlatforms = SupportChecker.getSupportedPlatformsForClass( - '$ProcessGlobalConfig', - ); - - return Card( - child: ExpansionTile( - title: Row( - children: [ - Text( - '$ProcessGlobalConfig', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(width: 8), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - ), - ), - ], - ), - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.orange.shade50, - borderRadius: BorderRadius.circular(4), - ), - child: LayoutBuilder( - builder: (context, constraints) { - final isMobile = ResponsiveBreakpoints.isMobileWidth( - constraints.maxWidth, - ); - final noteText = Text( - 'Note: $ProcessGlobalConfig can only be applied once, before any WebView is created.', - style: const TextStyle(fontSize: 12), - ); - - return ResponsiveRow( - spacing: 8, - runSpacing: 8, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Icon( - Icons.warning, - color: Colors.orange, - size: 20, - ), - isMobile ? noteText : Expanded(child: noteText), - ], - ); - }, - ), - ), - const SizedBox(height: 12), - TextField( - controller: _dataDirSuffixController, - decoration: const InputDecoration( - labelText: 'Data Directory Suffix', - border: OutlineInputBorder(), - isDense: true, - ), - ), - const SizedBox(height: 12), - SizedBox( - width: double.infinity, - child: _buildMethodButton( - 'Apply Config', - _applyProcessGlobalConfig, - supportedPlatforms: _processGlobalConfigPlatforms( - PlatformProcessGlobalConfigMethod.apply, - ), - methodName: PlatformProcessGlobalConfigMethod.apply.name, - ), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildMethodButton( - String label, - VoidCallback? onPressed, { - Set? supportedPlatforms, - String? methodName, - }) { - final canPress = onPressed != null && !_isLoading; - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ElevatedButton( - onPressed: canPress ? onPressed : null, - child: Text(label, style: const TextStyle(fontSize: 12)), - ), - if (supportedPlatforms != null) ...[ - const SizedBox(height: 6), - SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - ], - if (methodName != null) ...[ - const SizedBox(height: 6), - _buildMethodHistory(methodName, title: methodName), - ], - ], - ); - } - - Widget _buildEventLog() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Event Log', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - TextButton( - onPressed: () => context.read().clear(), - child: const Text('Clear'), - ), - ], - ), - const SizedBox(height: 8), - Consumer( - builder: (context, provider, _) { - final events = provider.events.reversed.take(15).toList(); - if (events.isEmpty) { - return Container( - padding: const EdgeInsets.all(16), - child: const Center( - child: Text( - 'No events yet', - style: TextStyle(color: Colors.grey), - ), - ), - ); - } - return Container( - height: 150, - decoration: BoxDecoration( - color: Colors.grey.shade100, - borderRadius: BorderRadius.circular(8), - ), - child: ListView.builder( - itemCount: events.length, - itemBuilder: (context, index) { - final event = events[index]; - return ListTile( - dense: true, - title: Text( - event.message, - style: const TextStyle(fontSize: 12), - ), - subtitle: Text( - event.data?.toString() ?? '', - style: TextStyle( - fontSize: 10, - color: Colors.grey.shade600, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - leading: Text( - '${event.timestamp.hour}:${event.timestamp.minute.toString().padLeft(2, '0')}:${event.timestamp.second.toString().padLeft(2, '0')}', - style: TextStyle( - fontSize: 10, - color: Colors.grey.shade500, - ), - ), - ); - }, - ), - ); - }, - ), - ], - ), - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/screens/advanced/static_methods_screen.dart b/flutter_inappwebview/example/lib/screens/advanced/static_methods_screen.dart deleted file mode 100644 index 58d34100e8..0000000000 --- a/flutter_inappwebview/example/lib/screens/advanced/static_methods_screen.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview_example/widgets/webview/static_method_tester_widget.dart'; -import 'package:flutter_inappwebview_example/widgets/common/app_drawer.dart'; - -/// Screen for testing static methods from various InAppWebView classes -/// without requiring a WebView instance. -class StaticMethodsScreen extends StatelessWidget { - const StaticMethodsScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Static Methods'), - backgroundColor: Colors.blue, - ), - drawer: AppDrawer(), - body: const StaticMethodTesterWidget(), - ); - } -} diff --git a/flutter_inappwebview/example/lib/screens/browsers/chrome_safari_browser_screen.dart b/flutter_inappwebview/example/lib/screens/browsers/chrome_safari_browser_screen.dart deleted file mode 100644 index 65926227b9..0000000000 --- a/flutter_inappwebview/example/lib/screens/browsers/chrome_safari_browser_screen.dart +++ /dev/null @@ -1,1192 +0,0 @@ -import 'dart:typed_data'; - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/widgets/common/app_drawer.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; -import 'package:flutter_inappwebview_example/widgets/common/support_badge.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_result_history.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/models/event_log_entry.dart'; - -/// Custom ChromeSafariBrowser implementation for testing -class TestChromeSafariBrowser extends ChromeSafariBrowser { - final void Function(String event, Map? data)? onEvent; - - TestChromeSafariBrowser({this.onEvent}); - - @override - void onOpened() { - onEvent?.call(PlatformChromeSafariBrowserEventsMethod.onOpened.name, { - 'id': id, - }); - } - - @override - void onCompletedInitialLoad(bool? didLoadSuccessfully) { - onEvent?.call( - PlatformChromeSafariBrowserEventsMethod.onCompletedInitialLoad.name, - {'didLoadSuccessfully': didLoadSuccessfully}, - ); - } - - @override - void onInitialLoadDidRedirect(WebUri? url) { - onEvent?.call( - PlatformChromeSafariBrowserEventsMethod.onInitialLoadDidRedirect.name, - {'url': url?.toString()}, - ); - } - - @override - void onNavigationEvent(CustomTabsNavigationEventType? navigationEvent) { - onEvent?.call( - PlatformChromeSafariBrowserEventsMethod.onNavigationEvent.name, - {'navigationEvent': navigationEvent?.name()}, - ); - } - - @override - void onServiceConnected() { - onEvent?.call( - PlatformChromeSafariBrowserEventsMethod.onServiceConnected.name, - null, - ); - } - - @override - void onClosed() { - onEvent?.call(PlatformChromeSafariBrowserEventsMethod.onClosed.name, null); - } - - @override - void onWillOpenInBrowser() { - onEvent?.call( - PlatformChromeSafariBrowserEventsMethod.onWillOpenInBrowser.name, - null, - ); - } - - @override - void onRelationshipValidationResult( - CustomTabsRelationType? relation, - WebUri? requestedOrigin, - bool result, - ) { - onEvent?.call( - PlatformChromeSafariBrowserEventsMethod - .onRelationshipValidationResult - .name, - { - 'relation': relation?.name(), - 'requestedOrigin': requestedOrigin?.toString(), - 'result': result, - }, - ); - } - - @override - void onMessageChannelReady() { - onEvent?.call( - PlatformChromeSafariBrowserEventsMethod.onMessageChannelReady.name, - null, - ); - } - - @override - void onPostMessage(String message) { - onEvent?.call(PlatformChromeSafariBrowserEventsMethod.onPostMessage.name, { - 'message': message, - }); - } - - @override - void onVerticalScrollEvent(bool isDirectionUp) { - onEvent?.call( - PlatformChromeSafariBrowserEventsMethod.onVerticalScrollEvent.name, - {'isDirectionUp': isDirectionUp}, - ); - } - - @override - void onGreatestScrollPercentageIncreased(int scrollPercentage) { - onEvent?.call( - PlatformChromeSafariBrowserEventsMethod - .onGreatestScrollPercentageIncreased - .name, - {'scrollPercentage': scrollPercentage}, - ); - } - - @override - void onSessionEnded(bool didUserInteract) { - onEvent?.call(PlatformChromeSafariBrowserEventsMethod.onSessionEnded.name, { - 'didUserInteract': didUserInteract, - }); - } -} - -/// Screen for testing ChromeSafariBrowser functionality -class ChromeSafariBrowserScreen extends StatefulWidget { - const ChromeSafariBrowserScreen({super.key}); - - @override - State createState() => - _ChromeSafariBrowserScreenState(); -} - -class _ChromeSafariBrowserScreenState extends State { - final TextEditingController _urlController = TextEditingController( - text: 'https://flutter.dev', - ); - final TextEditingController _messageController = TextEditingController(); - - TestChromeSafariBrowser? _browser; - bool _isLoading = false; - bool _browserOpened = false; - Color _toolbarColor = Colors.blue; - final List _menuItems = []; - - final Map> _methodHistory = {}; - final Map _selectedHistoryIndex = {}; - static const int _maxHistoryEntries = 3; - - void _initBrowser() { - try { - _browser = TestChromeSafariBrowser( - onEvent: (event, data) { - _logEvent(EventType.ui, event, data: data); - if (event == PlatformChromeSafariBrowserEventsMethod.onClosed.name) { - setState(() => _browserOpened = false); - } else if (event == - PlatformChromeSafariBrowserEventsMethod.onOpened.name) { - setState(() => _browserOpened = true); - } - }, - ); - } catch (e) { - _showInitError('Unable to create browser: $e'); - } - } - - String _staticMethodName(PlatformChromeSafariBrowserMethod method) { - return '${method.name} (static)'; - } - - @override - void initState() { - super.initState(); - _initBrowser(); - } - - @override - void dispose() { - _urlController.dispose(); - _messageController.dispose(); - _browser?.dispose(); - super.dispose(); - } - - void _logEvent(EventType type, String message, {Map? data}) { - context.read().addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: type, - message: message, - data: data, - ), - ); - } - - Future _open() async { - final url = _urlController.text.trim(); - if (url.isEmpty) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.open.name, - 'Please enter a URL', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - await _browser?.open( - url: WebUri(url), - settings: ChromeSafariBrowserSettings( - shareState: CustomTabsShareState.SHARE_STATE_ON, - toolbarBackgroundColor: _toolbarColor, - isSingleInstance: false, - isTrustedWebActivity: false, - keepAliveEnabled: true, - barCollapsingEnabled: true, - presentationStyle: ModalPresentationStyle.FULL_SCREEN, - dismissButtonStyle: DismissButtonStyle.CLOSE, - ), - ); - _recordMethodResult( - PlatformChromeSafariBrowserMethod.open.name, - 'Browser opened', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.open.name, - 'Error opening browser: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _launchUrl() async { - final url = _urlController.text.trim(); - if (url.isEmpty) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.launchUrl.name, - 'Please enter a URL', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - await _browser?.launchUrl(url: WebUri(url)); - _recordMethodResult( - PlatformChromeSafariBrowserMethod.launchUrl.name, - 'URL launched', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.launchUrl.name, - 'Error launching URL: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _mayLaunchUrl() async { - final url = _urlController.text.trim(); - if (url.isEmpty) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.mayLaunchUrl.name, - 'Please enter a URL', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final result = await _browser?.mayLaunchUrl(url: WebUri(url)); - _recordMethodResult( - PlatformChromeSafariBrowserMethod.mayLaunchUrl.name, - 'mayLaunchUrl result: $result', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.mayLaunchUrl.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _validateRelationship() async { - final url = _urlController.text.trim(); - if (url.isEmpty) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.validateRelationship.name, - 'Please enter a URL', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final result = await _browser?.validateRelationship( - relation: CustomTabsRelationType.USE_AS_ORIGIN, - origin: WebUri(url), - ); - _recordMethodResult( - PlatformChromeSafariBrowserMethod.validateRelationship.name, - 'validateRelationship result: $result', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.validateRelationship.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _close() async { - setState(() => _isLoading = true); - try { - await _browser?.close(); - setState(() => _browserOpened = false); - _recordMethodResult( - PlatformChromeSafariBrowserMethod.close.name, - 'Browser closed', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.close.name, - 'Error closing browser: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _setActionButton() async { - setState(() => _isLoading = true); - try { - // Create a simple colored icon - final iconData = await _createActionButtonIcon(); - _browser?.setActionButton( - ChromeSafariBrowserActionButton( - id: 1, - description: 'Test Action', - icon: iconData, - onClick: (url, title) { - _logEvent( - EventType.ui, - 'Action button clicked', - data: {'url': url?.toString(), 'title': title}, - ); - _recordMethodResult( - PlatformChromeSafariBrowserMethod.setActionButton.name, - 'Action button clicked', - isError: false, - ); - }, - ), - ); - _recordMethodResult( - PlatformChromeSafariBrowserMethod.setActionButton.name, - 'Action button set', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.setActionButton.name, - 'Error setting action button: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _createActionButtonIcon() async { - // Return a simple icon bytes - in real app you'd load from assets - try { - final byteData = await rootBundle.load('assets/images/flutter-logo.png'); - return byteData.buffer.asUint8List(); - } catch (e) { - // Return empty bytes if asset not found - return Uint8List(0); - } - } - - Future _updateActionButton() async { - setState(() => _isLoading = true); - try { - final iconData = await _createActionButtonIcon(); - await _browser?.updateActionButton( - icon: iconData, - description: 'Updated Action', - ); - _recordMethodResult( - PlatformChromeSafariBrowserMethod.updateActionButton.name, - 'Action button updated', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.updateActionButton.name, - 'Error updating action button: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - void _addMenuItem() { - final menuItem = ChromeSafariBrowserMenuItem( - id: _menuItems.length + 1, - label: 'Menu Item ${_menuItems.length + 1}', - onClick: (url, title) { - _logEvent( - EventType.ui, - 'Menu item clicked', - data: {'url': url, 'title': title}, - ); - _recordMethodResult( - PlatformChromeSafariBrowserMethod.addMenuItem.name, - 'Menu item clicked', - isError: false, - ); - }, - ); - - _browser?.addMenuItem(menuItem); - setState(() { - _menuItems.add(menuItem); - }); - _recordMethodResult( - PlatformChromeSafariBrowserMethod.addMenuItem.name, - 'Menu item added', - isError: false, - ); - } - - Future _requestPostMessageChannel() async { - final url = _urlController.text.trim(); - if (url.isEmpty) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.requestPostMessageChannel.name, - 'Please enter a URL', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final result = await _browser?.requestPostMessageChannel( - sourceOrigin: WebUri(url), - ); - _recordMethodResult( - PlatformChromeSafariBrowserMethod.requestPostMessageChannel.name, - 'requestPostMessageChannel result: $result', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.requestPostMessageChannel.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _postMessage() async { - final message = _messageController.text.trim(); - if (message.isEmpty) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.postMessage.name, - 'Please enter a message', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final result = await _browser?.postMessage(message); - _recordMethodResult( - PlatformChromeSafariBrowserMethod.postMessage.name, - 'postMessage result: ${result?.name}', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.postMessage.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _isEngagementSignalsApiAvailable() async { - setState(() => _isLoading = true); - try { - final result = await _browser?.isEngagementSignalsApiAvailable(); - _recordMethodResult( - PlatformChromeSafariBrowserMethod.isEngagementSignalsApiAvailable.name, - 'isEngagementSignalsApiAvailable: $result', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformChromeSafariBrowserMethod.isEngagementSignalsApiAvailable.name, - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - void _checkIsOpened() { - final opened = _browser?.isOpened() ?? false; - _recordMethodResult( - PlatformChromeSafariBrowserMethod.isOpened.name, - 'Browser is opened: $opened', - isError: false, - ); - } - - Future _isAvailable() async { - setState(() => _isLoading = true); - try { - final available = await ChromeSafariBrowser.isAvailable(); - _recordMethodResult( - _staticMethodName(PlatformChromeSafariBrowserMethod.isAvailable), - '$ChromeSafariBrowser is available: $available', - isError: false, - ); - } catch (e) { - _recordMethodResult( - _staticMethodName(PlatformChromeSafariBrowserMethod.isAvailable), - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getMaxToolbarItems() async { - setState(() => _isLoading = true); - try { - final maxItems = await ChromeSafariBrowser.getMaxToolbarItems(); - _recordMethodResult( - _staticMethodName(PlatformChromeSafariBrowserMethod.getMaxToolbarItems), - 'Max toolbar items: $maxItems', - isError: false, - ); - } catch (e) { - _recordMethodResult( - _staticMethodName(PlatformChromeSafariBrowserMethod.getMaxToolbarItems), - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getPackageName() async { - setState(() => _isLoading = true); - try { - final packageName = await ChromeSafariBrowser.getPackageName(); - _recordMethodResult( - _staticMethodName(PlatformChromeSafariBrowserMethod.getPackageName), - 'Package name: $packageName', - isError: false, - ); - } catch (e) { - _recordMethodResult( - _staticMethodName(PlatformChromeSafariBrowserMethod.getPackageName), - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _clearWebsiteData() async { - setState(() => _isLoading = true); - try { - await ChromeSafariBrowser.clearWebsiteData(); - _recordMethodResult( - _staticMethodName(PlatformChromeSafariBrowserMethod.clearWebsiteData), - 'Website data cleared', - isError: false, - ); - } catch (e) { - _recordMethodResult( - _staticMethodName(PlatformChromeSafariBrowserMethod.clearWebsiteData), - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _prewarmConnections() async { - final url = _urlController.text.trim(); - if (url.isEmpty) { - _recordMethodResult( - _staticMethodName(PlatformChromeSafariBrowserMethod.prewarmConnections), - 'Please enter a URL', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final token = await ChromeSafariBrowser.prewarmConnections([WebUri(url)]); - _recordMethodResult( - _staticMethodName(PlatformChromeSafariBrowserMethod.prewarmConnections), - 'Prewarm token: ${token?.id}', - isError: false, - ); - } catch (e) { - _recordMethodResult( - _staticMethodName(PlatformChromeSafariBrowserMethod.prewarmConnections), - 'Error: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - void _recordMethodResult( - String methodName, - String message, { - required bool isError, - dynamic value, - }) { - setState(() { - final entries = List.from( - _methodHistory[methodName] ?? const [], - ); - entries.insert( - 0, - MethodResultEntry( - message: message, - isError: isError, - timestamp: DateTime.now(), - value: value, - ), - ); - if (entries.length > _maxHistoryEntries) { - entries.removeRange(_maxHistoryEntries, entries.length); - } - _methodHistory[methodName] = entries; - _selectedHistoryIndex[methodName] = 0; - }); - } - - Widget _buildMethodHistory(String methodName, {String? title}) { - final entries = _methodHistory[methodName] ?? const []; - if (entries.isEmpty) { - return const SizedBox.shrink(); - } - return MethodResultHistory( - entries: entries, - selectedIndex: _selectedHistoryIndex[methodName], - title: title ?? methodName, - onSelected: (index) { - setState(() => _selectedHistoryIndex[methodName] = index); - }, - ); - } - - void _showInitError(String message) { - _recordMethodResult('initBrowser', message, isError: true); - } - - Widget _buildInitStatusSection() { - final entries = _methodHistory['initBrowser'] ?? const []; - if (entries.isEmpty) { - return const SizedBox.shrink(); - } - return Column( - children: [ - _buildMethodHistory('initBrowser', title: 'Initialization'), - const SizedBox(height: 16), - ], - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Chrome/Safari Browser'), - actions: [ - if (_isLoading) - const Padding( - padding: EdgeInsets.all(16), - child: SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - strokeWidth: 2, - color: Colors.white, - ), - ), - ), - IconButton( - icon: const Icon(Icons.clear_all), - tooltip: 'Clear Events', - onPressed: () { - context.read().clear(); - }, - ), - ], - ), - drawer: AppDrawer(), - body: ListView( - padding: const EdgeInsets.all(16), - children: [ - _buildStatusCard(), - const SizedBox(height: 16), - _buildInitStatusSection(), - _buildInputSection(), - const SizedBox(height: 16), - _buildOpenMethods(), - const SizedBox(height: 16), - _buildToolbarMethods(), - const SizedBox(height: 16), - _buildMessagingMethods(), - const SizedBox(height: 16), - _buildStaticMethods(), - const SizedBox(height: 16), - _buildEventLog(), - ], - ), - ); - } - - Widget _buildStatusCard() { - return Card( - color: _browserOpened ? Colors.green.shade50 : Colors.grey.shade100, - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - children: [ - Icon( - _browserOpened ? Icons.web : Icons.web_asset_off, - color: _browserOpened ? Colors.green : Colors.grey, - size: 32, - ), - const SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - _browserOpened ? 'Browser Open' : 'Browser Closed', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: _browserOpened ? Colors.green : Colors.grey, - ), - ), - Text( - 'ID: ${_browser?.id ?? "N/A"}', - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - ], - ), - ), - ], - ), - ), - ); - } - - Widget _buildInputSection() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Input', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 12), - TextField( - controller: _urlController, - decoration: const InputDecoration( - labelText: 'URL', - hintText: 'https://flutter.dev', - border: OutlineInputBorder(), - isDense: true, - ), - ), - const SizedBox(height: 12), - TextField( - controller: _messageController, - decoration: const InputDecoration( - labelText: 'Message (for postMessage)', - border: OutlineInputBorder(), - isDense: true, - ), - ), - const SizedBox(height: 12), - Row( - children: [ - const Text('Toolbar Color:'), - const SizedBox(width: 16), - ...[ - Colors.blue, - Colors.green, - Colors.red, - Colors.purple, - Colors.orange, - ].map( - (color) => GestureDetector( - onTap: () => setState(() => _toolbarColor = color), - child: Container( - width: 32, - height: 32, - margin: const EdgeInsets.only(right: 8), - decoration: BoxDecoration( - color: color, - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: _toolbarColor == color - ? Colors.black - : Colors.transparent, - width: 2, - ), - ), - ), - ), - ), - ], - ), - ], - ), - ), - ); - } - - Widget _buildOpenMethods() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Open Methods', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 12), - _buildMethodTile( - PlatformChromeSafariBrowserMethod.open.name, - 'Open Chrome Custom Tab / Safari View Controller', - PlatformChromeSafariBrowserMethod.open, - _open, - ), - _buildMethodTile( - PlatformChromeSafariBrowserMethod.launchUrl.name, - 'Launch URL in already opened browser', - PlatformChromeSafariBrowserMethod.launchUrl, - _browserOpened ? _launchUrl : null, - ), - _buildMethodTile( - PlatformChromeSafariBrowserMethod.mayLaunchUrl.name, - 'Hint browser to preload URL', - PlatformChromeSafariBrowserMethod.mayLaunchUrl, - _mayLaunchUrl, - ), - _buildMethodTile( - PlatformChromeSafariBrowserMethod.validateRelationship.name, - 'Validate Digital Asset Links', - PlatformChromeSafariBrowserMethod.validateRelationship, - _validateRelationship, - ), - _buildMethodTile( - PlatformChromeSafariBrowserMethod.close.name, - 'Close the browser', - PlatformChromeSafariBrowserMethod.close, - _browserOpened ? _close : null, - ), - _buildMethodTile( - PlatformChromeSafariBrowserMethod.isOpened.name, - 'Check if browser is opened', - PlatformChromeSafariBrowserMethod.isOpened, - _checkIsOpened, - ), - ], - ), - ), - ); - } - - Widget _buildToolbarMethods() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Toolbar & Menu', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 12), - _buildMethodTile( - PlatformChromeSafariBrowserMethod.setActionButton.name, - 'Set action button (before open)', - PlatformChromeSafariBrowserMethod.setActionButton, - _setActionButton, - ), - _buildMethodTile( - PlatformChromeSafariBrowserMethod.updateActionButton.name, - 'Update action button icon', - PlatformChromeSafariBrowserMethod.updateActionButton, - _browserOpened ? _updateActionButton : null, - ), - _buildMethodTile( - PlatformChromeSafariBrowserMethod.addMenuItem.name, - 'Add menu item (before open)', - PlatformChromeSafariBrowserMethod.addMenuItem, - _addMenuItem, - ), - if (_menuItems.isNotEmpty) ...[ - const Divider(), - Text( - 'Menu Items: ${_menuItems.length}', - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - ], - ], - ), - ), - ); - } - - Widget _buildMessagingMethods() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Messaging', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 12), - _buildMethodTile( - PlatformChromeSafariBrowserMethod.requestPostMessageChannel.name, - 'Request post message channel', - PlatformChromeSafariBrowserMethod.requestPostMessageChannel, - _browserOpened ? _requestPostMessageChannel : null, - ), - _buildMethodTile( - PlatformChromeSafariBrowserMethod.postMessage.name, - 'Send a message to the browser', - PlatformChromeSafariBrowserMethod.postMessage, - _browserOpened ? _postMessage : null, - ), - _buildMethodTile( - PlatformChromeSafariBrowserMethod - .isEngagementSignalsApiAvailable - .name, - 'Check if engagement signals API is available', - PlatformChromeSafariBrowserMethod.isEngagementSignalsApiAvailable, - _isEngagementSignalsApiAvailable, - ), - ], - ), - ), - ); - } - - Widget _buildStaticMethods() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Static Methods', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 12), - _buildMethodTile( - _staticMethodName(PlatformChromeSafariBrowserMethod.isAvailable), - 'Check if Chrome Custom Tabs / Safari VC is available', - PlatformChromeSafariBrowserMethod.isAvailable, - _isAvailable, - ), - _buildMethodTile( - _staticMethodName( - PlatformChromeSafariBrowserMethod.getMaxToolbarItems, - ), - 'Get max toolbar items', - PlatformChromeSafariBrowserMethod.getMaxToolbarItems, - _getMaxToolbarItems, - ), - _buildMethodTile( - _staticMethodName( - PlatformChromeSafariBrowserMethod.getPackageName, - ), - 'Get Custom Tabs package name', - PlatformChromeSafariBrowserMethod.getPackageName, - _getPackageName, - ), - _buildMethodTile( - _staticMethodName( - PlatformChromeSafariBrowserMethod.clearWebsiteData, - ), - 'Clear website data', - PlatformChromeSafariBrowserMethod.clearWebsiteData, - _clearWebsiteData, - ), - _buildMethodTile( - _staticMethodName( - PlatformChromeSafariBrowserMethod.prewarmConnections, - ), - 'Prewarm connections', - PlatformChromeSafariBrowserMethod.prewarmConnections, - _prewarmConnections, - ), - ], - ), - ), - ); - } - - Widget _buildMethodTile( - String methodName, - String description, - PlatformChromeSafariBrowserMethod method, - VoidCallback? onPressed, - ) { - final supportedPlatforms = SupportCheckHelper.supportedPlatformsForMethod( - method: method, - checker: ChromeSafariBrowser.isMethodSupported, - ); - - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: ListTile( - dense: true, - title: Text( - methodName, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - description, - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - const SizedBox(height: 6), - SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - const SizedBox(height: 6), - _buildMethodHistory(methodName), - ], - ), - trailing: ElevatedButton( - onPressed: !_isLoading ? onPressed : null, - child: const Text('Run'), - ), - ), - ); - } - - Widget _buildEventLog() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Event Log', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - TextButton( - onPressed: () => context.read().clear(), - child: const Text('Clear'), - ), - ], - ), - const SizedBox(height: 8), - Consumer( - builder: (context, provider, _) { - final events = provider.events.reversed.take(20).toList(); - if (events.isEmpty) { - return Container( - padding: const EdgeInsets.all(16), - child: const Center( - child: Text( - 'No events yet', - style: TextStyle(color: Colors.grey), - ), - ), - ); - } - return Container( - height: 200, - decoration: BoxDecoration( - color: Colors.grey.shade100, - borderRadius: BorderRadius.circular(8), - ), - child: ListView.builder( - itemCount: events.length, - itemBuilder: (context, index) { - final event = events[index]; - return ListTile( - dense: true, - title: Text( - event.message, - style: const TextStyle(fontSize: 12), - ), - subtitle: Text( - event.data?.toString() ?? '', - style: TextStyle( - fontSize: 10, - color: Colors.grey.shade600, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - leading: Text( - '${event.timestamp.hour}:${event.timestamp.minute.toString().padLeft(2, '0')}:${event.timestamp.second.toString().padLeft(2, '0')}', - style: TextStyle( - fontSize: 10, - color: Colors.grey.shade500, - ), - ), - ); - }, - ), - ); - }, - ), - ], - ), - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/screens/browsers/headless_webview_screen.dart b/flutter_inappwebview/example/lib/screens/browsers/headless_webview_screen.dart deleted file mode 100644 index 1ab2c6e679..0000000000 --- a/flutter_inappwebview/example/lib/screens/browsers/headless_webview_screen.dart +++ /dev/null @@ -1,1046 +0,0 @@ -import 'dart:typed_data'; - -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/widgets/common/app_drawer.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; -import 'package:flutter_inappwebview_example/widgets/common/support_badge.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_result_history.dart'; -import 'package:flutter_inappwebview_example/widgets/common/responsive_row.dart'; -import 'package:flutter_inappwebview_example/utils/responsive_utils.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/models/event_log_entry.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; -import 'package:flutter_inappwebview_example/widgets/common/profile_selector_card.dart'; - -/// Screen for testing HeadlessInAppWebView functionality -class HeadlessWebViewScreen extends StatefulWidget { - const HeadlessWebViewScreen({super.key}); - - @override - State createState() => _HeadlessWebViewScreenState(); -} - -class _HeadlessWebViewScreenState extends State { - final TextEditingController _urlController = TextEditingController( - text: 'https://flutter.dev', - ); - final TextEditingController _widthController = TextEditingController( - text: '1024', - ); - final TextEditingController _heightController = TextEditingController( - text: '768', - ); - - HeadlessInAppWebView? _headlessWebView; - InAppWebViewController? _webViewController; - bool _isLoading = false; - bool _isRunning = false; - Size? _currentSize; - Uint8List? _screenshotData; - String? _currentUrl; - String? _currentTitle; - bool _isInitialized = false; - int _lastEnvironmentRevision = -1; - - final Map> _methodHistory = {}; - final Map _selectedHistoryIndex = {}; - static const int _maxHistoryEntries = 3; - - @override - void dispose() { - _urlController.dispose(); - _widthController.dispose(); - _heightController.dispose(); - _headlessWebView?.dispose(); - super.dispose(); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - final settingsManager = context.watch(); - - if (!_isInitialized) { - _isInitialized = true; - _lastEnvironmentRevision = settingsManager.environmentRevision; - return; - } - - if (_lastEnvironmentRevision != settingsManager.environmentRevision) { - _lastEnvironmentRevision = settingsManager.environmentRevision; - WidgetsBinding.instance.addPostFrameCallback((_) { - _resetForEnvironmentChange(); - }); - } - } - - void _logEvent(EventType type, String message, {Map? data}) { - context.read().addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: type, - message: message, - data: data, - ), - ); - } - - bool _createHeadlessWebView({ - required String url, - required double width, - required double height, - bool javaScriptEnabled = true, - required SettingsManager settingsManager, - }) { - if (url.isEmpty) { - _recordMethodResult( - PlatformHeadlessInAppWebViewMethod.run.name, - 'Please enter a URL', - isError: true, - ); - return false; - } - try { - final baseSettings = settingsManager.buildSettings(); - final mergedSettings = - InAppWebViewSettings.fromMap({ - ...baseSettings.toMap(), - 'javaScriptEnabled': javaScriptEnabled, - }) ?? - InAppWebViewSettings(); - _headlessWebView = HeadlessInAppWebView( - initialSize: Size(width, height), - initialUrlRequest: URLRequest(url: WebUri(url)), - webViewEnvironment: settingsManager.webViewEnvironment, - initialSettings: mergedSettings, - onWebViewCreated: (controller) { - _webViewController = controller; - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onWebViewCreated.name, - data: {'viewId': controller.getViewId()}, - ); - }, - onLoadStart: (controller, url) { - _logEvent( - EventType.navigation, - PlatformWebViewCreationParamsProperty.onLoadStart.name, - data: {'url': url?.toString()}, - ); - setState(() => _currentUrl = url?.toString()); - }, - onLoadStop: (controller, url) async { - _logEvent( - EventType.navigation, - PlatformWebViewCreationParamsProperty.onLoadStop.name, - data: {'url': url?.toString()}, - ); - final title = await controller.getTitle(); - setState(() { - _currentUrl = url?.toString(); - _currentTitle = title; - }); - }, - onReceivedError: (controller, request, error) { - _logEvent( - EventType.error, - PlatformWebViewCreationParamsProperty.onReceivedError.name, - data: { - 'url': request.url.toString(), - 'errorType': error.type.name(), - 'description': error.description, - }, - ); - }, - onProgressChanged: (controller, progress) { - _logEvent( - EventType.performance, - PlatformWebViewCreationParamsProperty.onProgressChanged.name, - data: {'progress': progress}, - ); - }, - onConsoleMessage: (controller, consoleMessage) { - _logEvent( - EventType.console, - PlatformWebViewCreationParamsProperty.onConsoleMessage.name, - data: { - 'message': consoleMessage.message, - 'level': consoleMessage.messageLevel.name(), - }, - ); - }, - onTitleChanged: (controller, title) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onTitleChanged.name, - data: {'title': title}, - ); - setState(() => _currentTitle = title); - }, - ); - } catch (e) { - _recordMethodResult( - PlatformHeadlessInAppWebViewMethod.run.name, - 'Error creating $HeadlessInAppWebView: $e', - isError: true, - ); - return false; - } - return true; - } - - Future _run() async { - final settingsManager = context.read(); - - // Use the values from the inline form instead of showing a dialog - final url = _urlController.text.trim(); - final width = double.tryParse(_widthController.text) ?? 1024; - final height = double.tryParse(_heightController.text) ?? 768; - - if (url.isEmpty) { - _recordMethodResult( - PlatformHeadlessInAppWebViewMethod.run.name, - 'Please enter a URL', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final created = _createHeadlessWebView( - url: url, - width: width, - height: height, - javaScriptEnabled: true, - settingsManager: settingsManager, - ); - if (!created) return; - await _headlessWebView?.run(); - setState(() => _isRunning = _headlessWebView?.isRunning() ?? false); - _recordMethodResult( - PlatformHeadlessInAppWebViewMethod.run.name, - '$HeadlessInAppWebView started', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformHeadlessInAppWebViewMethod.run.name, - 'Error starting $HeadlessInAppWebView: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - void _checkIsRunning() { - final running = _headlessWebView?.isRunning() ?? false; - setState(() => _isRunning = running); - _recordMethodResult( - PlatformHeadlessInAppWebViewMethod.isRunning.name, - '$HeadlessInAppWebView is running: $running', - isError: false, - ); - } - - Future _setSize() async { - final params = await showParameterDialog( - context: context, - title: 'Set Size', - parameters: { - 'width': double.tryParse(_widthController.text) ?? 1024, - 'height': double.tryParse(_heightController.text) ?? 768, - }, - requiredPaths: ['width', 'height'], - ); - - if (params == null) return; - final width = (params['width'] as num?)?.toDouble(); - final height = (params['height'] as num?)?.toDouble(); - if (width == null || height == null) { - _recordMethodResult( - PlatformHeadlessInAppWebViewMethod.setSize.name, - 'Please enter valid width and height', - isError: true, - ); - return; - } - _widthController.text = width.toString(); - _heightController.text = height.toString(); - - setState(() => _isLoading = true); - try { - await _headlessWebView?.setSize(Size(width, height)); - _recordMethodResult( - PlatformHeadlessInAppWebViewMethod.setSize.name, - 'Size set to ${width}x$height', - isError: false, - ); - await _getSize(); - } catch (e) { - _recordMethodResult( - PlatformHeadlessInAppWebViewMethod.setSize.name, - 'Error setting size: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getSize() async { - setState(() => _isLoading = true); - try { - final size = await _headlessWebView?.getSize(); - setState(() => _currentSize = size); - _recordMethodResult( - PlatformHeadlessInAppWebViewMethod.getSize.name, - 'Current size: ${size?.width}x${size?.height}', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformHeadlessInAppWebViewMethod.getSize.name, - 'Error getting size: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _dispose() async { - setState(() => _isLoading = true); - try { - await _headlessWebView?.dispose(); - setState(() { - _isRunning = false; - _currentSize = null; - _screenshotData = null; - _currentUrl = null; - _currentTitle = null; - }); - _headlessWebView = null; - _webViewController = null; - _recordMethodResult( - PlatformHeadlessInAppWebViewMethod.dispose.name, - '$HeadlessInAppWebView disposed', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformHeadlessInAppWebViewMethod.dispose.name, - 'Error disposing: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _takeScreenshot() async { - if (_webViewController == null) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.takeScreenshot.name, - 'WebView not initialized', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final screenshot = await _webViewController?.takeScreenshot(); - setState(() => _screenshotData = screenshot); - if (screenshot != null) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.takeScreenshot.name, - 'Screenshot taken (${screenshot.length} bytes)', - isError: false, - ); - } else { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.takeScreenshot.name, - 'Failed to take screenshot', - isError: true, - ); - } - } catch (e) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.takeScreenshot.name, - 'Error taking screenshot: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _loadUrl() async { - final params = await showParameterDialog( - context: context, - title: 'Load URL', - parameters: {'url': _urlController.text.trim()}, - requiredPaths: ['url'], - ); - - if (params == null) return; - final url = params['url']?.toString() ?? ''; - if (url.isEmpty) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.loadUrl.name, - 'Please enter a URL', - isError: true, - ); - return; - } - _urlController.text = url; - - if (_webViewController == null) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.loadUrl.name, - 'WebView not initialized. Run first.', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - await _webViewController?.loadUrl( - urlRequest: URLRequest(url: WebUri(url)), - ); - _recordMethodResult( - PlatformInAppWebViewControllerMethod.loadUrl.name, - 'Loading URL: $url', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.loadUrl.name, - 'Error loading URL: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _evaluateJavaScript() async { - if (_webViewController == null) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.evaluateJavascript.name, - 'WebView not initialized', - isError: true, - ); - return; - } - - final params = await showParameterDialog( - context: context, - title: 'Evaluate JavaScript', - parameters: {'source': 'document.title'}, - requiredPaths: ['source'], - ); - - if (params == null) return; - final source = params['source']?.toString() ?? ''; - if (source.isEmpty) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.evaluateJavascript.name, - 'Please enter JavaScript source', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final result = await _webViewController?.evaluateJavascript( - source: source, - ); - _recordMethodResult( - PlatformInAppWebViewControllerMethod.evaluateJavascript.name, - 'JavaScript result: $result', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.evaluateJavascript.name, - 'Error evaluating JavaScript: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - void _recordMethodResult( - String methodName, - String message, { - required bool isError, - dynamic value, - }) { - setState(() { - final entries = List.from( - _methodHistory[methodName] ?? const [], - ); - entries.insert( - 0, - MethodResultEntry( - message: message, - isError: isError, - timestamp: DateTime.now(), - value: value, - ), - ); - if (entries.length > _maxHistoryEntries) { - entries.removeRange(_maxHistoryEntries, entries.length); - } - _methodHistory[methodName] = entries; - _selectedHistoryIndex[methodName] = 0; - }); - } - - Future _resetForEnvironmentChange() async { - if (_headlessWebView != null) { - await _headlessWebView?.dispose(); - } - setState(() { - _headlessWebView = null; - _webViewController = null; - _isRunning = false; - _currentSize = null; - _screenshotData = null; - _currentUrl = null; - _currentTitle = null; - }); - } - - Widget _buildMethodHistory(String methodName, {String? title}) { - final entries = _methodHistory[methodName] ?? const []; - if (entries.isEmpty) { - return const SizedBox.shrink(); - } - return MethodResultHistory( - entries: entries, - selectedIndex: _selectedHistoryIndex[methodName], - title: title ?? methodName, - onSelected: (index) { - setState(() => _selectedHistoryIndex[methodName] = index); - }, - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text('$HeadlessInAppWebView'), - actions: [ - if (_isLoading) - const Padding( - padding: EdgeInsets.all(16), - child: SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - strokeWidth: 2, - color: Colors.white, - ), - ), - ), - IconButton( - icon: const Icon(Icons.clear_all), - tooltip: 'Clear Events', - onPressed: () { - context.read().clear(); - }, - ), - ], - ), - drawer: AppDrawer(), - body: ListView( - key: const Key('headless_webview_main_list'), - padding: const EdgeInsets.all(16), - children: [ - ProfileSelectorCard( - onEditSettingsProfile: () => - Navigator.pushNamed(context, '/settings'), - ), - const SizedBox(height: 16), - _buildStatusCard(), - const SizedBox(height: 16), - _buildInputSection(), - const SizedBox(height: 16), - _buildMainMethods(), - const SizedBox(height: 16), - _buildSizeMethods(), - const SizedBox(height: 16), - _buildWebViewActions(), - const SizedBox(height: 16), - _buildPreviewSection(), - const SizedBox(height: 16), - _buildEventLog(), - ], - ), - ); - } - - Widget _buildStatusCard() { - return Card( - color: _isRunning ? Colors.green.shade50 : Colors.grey.shade100, - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon( - _isRunning ? Icons.play_circle : Icons.pause_circle, - color: _isRunning ? Colors.green : Colors.grey, - size: 32, - ), - const SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - _isRunning ? 'Running' : 'Stopped', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: _isRunning ? Colors.green : Colors.grey, - ), - ), - Text( - 'ID: ${_headlessWebView?.id ?? "N/A"}', - style: TextStyle( - fontSize: 12, - color: Colors.grey.shade600, - ), - ), - ], - ), - ), - ], - ), - if (_isRunning) ...[ - const Divider(), - if (_currentUrl != null) - Text( - 'URL: $_currentUrl', - style: const TextStyle(fontSize: 12), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - if (_currentTitle != null) - Text( - 'Title: $_currentTitle', - style: const TextStyle(fontSize: 12), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - if (_currentSize != null) - Text( - 'Size: ${_currentSize!.width.toInt()}x${_currentSize!.height.toInt()}', - style: const TextStyle(fontSize: 12), - ), - ], - ], - ), - ), - ); - } - - Widget _buildInputSection() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Configuration', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 12), - TextField( - controller: _urlController, - decoration: const InputDecoration( - labelText: 'URL', - hintText: 'https://flutter.dev', - border: OutlineInputBorder(), - isDense: true, - ), - ), - const SizedBox(height: 12), - LayoutBuilder( - builder: (context, constraints) { - final isMobile = ResponsiveBreakpoints.isMobileWidth( - constraints.maxWidth, - ); - const spacing = 12.0; - final fieldWidth = isMobile - ? constraints.maxWidth - : (constraints.maxWidth - spacing) / 2; - - return ResponsiveRow( - key: const Key('headless_webview_size_layout'), - spacing: spacing, - runSpacing: spacing, - children: [ - SizedBox( - width: fieldWidth, - child: TextField( - key: const Key('headless_webview_width_field'), - controller: _widthController, - decoration: const InputDecoration( - labelText: 'Width', - border: OutlineInputBorder(), - isDense: true, - ), - keyboardType: TextInputType.number, - ), - ), - SizedBox( - width: fieldWidth, - child: TextField( - key: const Key('headless_webview_height_field'), - controller: _heightController, - decoration: const InputDecoration( - labelText: 'Height', - border: OutlineInputBorder(), - isDense: true, - ), - keyboardType: TextInputType.number, - ), - ), - ], - ); - }, - ), - ], - ), - ), - ); - } - - Widget _buildMainMethods() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Main Methods', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 12), - _buildMethodTile( - PlatformHeadlessInAppWebViewMethod.run.name, - 'Start the headless WebView', - PlatformHeadlessInAppWebViewMethod.run, - !_isRunning ? _run : null, - ), - _buildMethodTile( - PlatformHeadlessInAppWebViewMethod.isRunning.name, - 'Check if the headless WebView is running', - PlatformHeadlessInAppWebViewMethod.isRunning, - _checkIsRunning, - ), - _buildMethodTile( - PlatformHeadlessInAppWebViewMethod.dispose.name, - 'Stop and dispose the headless WebView', - PlatformHeadlessInAppWebViewMethod.dispose, - _isRunning ? _dispose : null, - ), - ], - ), - ), - ); - } - - Widget _buildSizeMethods() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Size Methods', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 12), - _buildMethodTile( - PlatformHeadlessInAppWebViewMethod.setSize.name, - 'Set the WebView size', - PlatformHeadlessInAppWebViewMethod.setSize, - _isRunning ? _setSize : null, - ), - _buildMethodTile( - PlatformHeadlessInAppWebViewMethod.getSize.name, - 'Get the current WebView size', - PlatformHeadlessInAppWebViewMethod.getSize, - _isRunning ? _getSize : null, - ), - ], - ), - ), - ); - } - - Widget _buildWebViewActions() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'WebView Actions', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 8), - Text( - 'These use the internal WebViewController', - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - const SizedBox(height: 12), - Wrap( - spacing: 8, - runSpacing: 8, - children: [ - ElevatedButton.icon( - onPressed: _isRunning ? _loadUrl : null, - icon: const Icon(Icons.link, size: 18), - label: const Text('Load URL'), - ), - ElevatedButton.icon( - onPressed: _isRunning ? _takeScreenshot : null, - icon: const Icon(Icons.camera_alt, size: 18), - label: const Text('Screenshot'), - ), - ElevatedButton.icon( - onPressed: _isRunning ? _evaluateJavaScript : null, - icon: const Icon(Icons.code, size: 18), - label: const Text('Eval JS'), - ), - ], - ), - const SizedBox(height: 8), - _buildMethodHistory( - PlatformInAppWebViewControllerMethod.loadUrl.name, - ), - _buildMethodHistory( - PlatformInAppWebViewControllerMethod.takeScreenshot.name, - ), - _buildMethodHistory( - PlatformInAppWebViewControllerMethod.evaluateJavascript.name, - ), - ], - ), - ), - ); - } - - Widget _buildPreviewSection() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Screenshot Preview', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - if (_screenshotData != null) - TextButton( - onPressed: () => setState(() => _screenshotData = null), - child: const Text('Clear'), - ), - ], - ), - const SizedBox(height: 12), - Container( - height: 200, - width: double.infinity, - decoration: BoxDecoration( - color: Colors.grey.shade200, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Colors.grey.shade300), - ), - child: _screenshotData != null - ? ClipRRect( - borderRadius: BorderRadius.circular(8), - child: Image.memory( - _screenshotData!, - fit: BoxFit.contain, - ), - ) - : Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.image_not_supported, - size: 48, - color: Colors.grey.shade400, - ), - const SizedBox(height: 8), - Text( - 'No screenshot available', - style: TextStyle(color: Colors.grey.shade600), - ), - const SizedBox(height: 4), - Text( - 'Run the headless WebView and take a screenshot', - style: TextStyle( - fontSize: 12, - color: Colors.grey.shade500, - ), - ), - ], - ), - ), - ), - ], - ), - ), - ); - } - - Widget _buildMethodTile( - String methodName, - String description, - PlatformHeadlessInAppWebViewMethod method, - VoidCallback? onPressed, - ) { - final supportedPlatforms = SupportCheckHelper.supportedPlatformsForMethod( - method: method, - checker: HeadlessInAppWebView.isMethodSupported, - ); - - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: ListTile( - dense: true, - title: Text( - methodName, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - description, - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - const SizedBox(height: 6), - SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - const SizedBox(height: 6), - _buildMethodHistory(methodName), - ], - ), - trailing: ElevatedButton( - onPressed: !_isLoading ? onPressed : null, - child: const Text('Run'), - ), - ), - ); - } - - Widget _buildEventLog() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Event Log', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - TextButton( - onPressed: () => context.read().clear(), - child: const Text('Clear'), - ), - ], - ), - const SizedBox(height: 8), - Consumer( - builder: (context, provider, _) { - final events = provider.events.reversed.take(20).toList(); - if (events.isEmpty) { - return Container( - padding: const EdgeInsets.all(16), - child: const Center( - child: Text( - 'No events yet', - style: TextStyle(color: Colors.grey), - ), - ), - ); - } - return Container( - height: 200, - decoration: BoxDecoration( - color: Colors.grey.shade100, - borderRadius: BorderRadius.circular(8), - ), - child: ListView.builder( - itemCount: events.length, - itemBuilder: (context, index) { - final event = events[index]; - return ListTile( - dense: true, - title: Text( - event.message, - style: const TextStyle(fontSize: 12), - ), - subtitle: Text( - event.data?.toString() ?? '', - style: TextStyle( - fontSize: 10, - color: Colors.grey.shade600, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - leading: Text( - '${event.timestamp.hour}:${event.timestamp.minute.toString().padLeft(2, '0')}:${event.timestamp.second.toString().padLeft(2, '0')}', - style: TextStyle( - fontSize: 10, - color: Colors.grey.shade500, - ), - ), - ); - }, - ), - ); - }, - ), - ], - ), - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/screens/browsers/inapp_browser_screen.dart b/flutter_inappwebview/example/lib/screens/browsers/inapp_browser_screen.dart deleted file mode 100644 index 74f6ba41a9..0000000000 --- a/flutter_inappwebview/example/lib/screens/browsers/inapp_browser_screen.dart +++ /dev/null @@ -1,989 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/widgets/common/app_drawer.dart'; -import 'package:flutter_inappwebview_example/widgets/common/appbar_loading_indicator.dart'; -import 'package:flutter_inappwebview_example/widgets/common/event_log_card.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_card.dart'; -import 'package:flutter_inappwebview_example/widgets/common/status_card.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; -import 'package:flutter_inappwebview_example/utils/responsive_utils.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_result_history.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/models/event_log_entry.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; -import 'package:flutter_inappwebview_example/widgets/common/profile_selector_card.dart'; - -/// Custom InAppBrowser implementation for testing -class TestInAppBrowser extends InAppBrowser { - final void Function(String event, Map? data)? onEvent; - - TestInAppBrowser({this.onEvent, WebViewEnvironment? webViewEnvironment}) - : super(webViewEnvironment: webViewEnvironment); - - @override - void onBrowserCreated() { - onEvent?.call(PlatformInAppBrowserEventsMethod.onBrowserCreated.name, { - 'id': id, - }); - } - - @override - void onLoadStart(WebUri? url) { - onEvent?.call(PlatformInAppBrowserEventsMethod.onLoadStart.name, { - 'url': url?.toString(), - }); - } - - @override - void onLoadStop(WebUri? url) { - onEvent?.call(PlatformInAppBrowserEventsMethod.onLoadStop.name, { - 'url': url?.toString(), - }); - } - - @override - void onReceivedError(WebResourceRequest request, WebResourceError error) { - onEvent?.call(PlatformInAppBrowserEventsMethod.onReceivedError.name, { - 'url': request.url.toString(), - 'errorType': error.type.name(), - 'description': error.description, - }); - } - - @override - void onProgressChanged(int progress) { - onEvent?.call(PlatformInAppBrowserEventsMethod.onProgressChanged.name, { - 'progress': progress, - }); - } - - @override - void onExit() { - onEvent?.call(PlatformInAppBrowserEventsMethod.onExit.name, null); - } - - @override - void onMainWindowWillClose() { - onEvent?.call( - PlatformInAppBrowserEventsMethod.onMainWindowWillClose.name, - null, - ); - } - - @override - void onConsoleMessage(ConsoleMessage consoleMessage) { - onEvent?.call(PlatformInAppBrowserEventsMethod.onConsoleMessage.name, { - 'message': consoleMessage.message, - 'level': consoleMessage.messageLevel.name, - }); - } -} - -/// Screen for testing InAppBrowser functionality -class InAppBrowserScreen extends StatefulWidget { - const InAppBrowserScreen({super.key}); - - @override - State createState() => _InAppBrowserScreenState(); -} - -class _InAppBrowserScreenState extends State { - final TextEditingController _menuItemIdController = TextEditingController(); - final TextEditingController _menuItemTitleController = TextEditingController( - text: 'Custom Menu Item', - ); - - TestInAppBrowser? _browser; - bool _isLoading = false; - bool _browserOpened = false; - final List _menuItems = []; - bool _isInitialized = false; - int _lastEnvironmentRevision = -1; - - final Map> _methodHistory = {}; - final Map _selectedHistoryIndex = {}; - static const int _maxHistoryEntries = 3; - - String get _initStatusKey => PlatformInAppBrowserMethod.openUrlRequest.name; - - void _initBrowser(WebViewEnvironment? webViewEnvironment) { - try { - _browser = TestInAppBrowser( - webViewEnvironment: webViewEnvironment, - onEvent: (event, data) { - _logEvent(EventType.ui, event, data: data); - if (event == PlatformInAppBrowserEventsMethod.onExit.name) { - setState(() => _browserOpened = false); - } - }, - ); - } catch (e) { - _showInitError('Unable to create browser: $e'); - } - } - - String _staticMethodName(PlatformInAppBrowserMethod method) { - return '${method.name} (static)'; - } - - @override - void initState() { - super.initState(); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - final settingsManager = context.watch(); - - if (!_isInitialized) { - _isInitialized = true; - _lastEnvironmentRevision = settingsManager.environmentRevision; - _initBrowser(settingsManager.webViewEnvironment); - return; - } - - if (_lastEnvironmentRevision != settingsManager.environmentRevision) { - _lastEnvironmentRevision = settingsManager.environmentRevision; - _handleEnvironmentChange(settingsManager.webViewEnvironment); - } - } - - @override - void dispose() { - _menuItemIdController.dispose(); - _menuItemTitleController.dispose(); - _browser?.dispose(); - super.dispose(); - } - - void _logEvent(EventType type, String message, {Map? data}) { - context.read().addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: type, - message: message, - data: data, - ), - ); - } - - Future _openUrlRequest() async { - final settingsManager = context.read(); - final params = await showParameterDialog( - context: context, - title: PlatformInAppBrowserMethod.openUrlRequest.name, - parameters: { - 'url': 'https://flutter.dev', - 'toolbarTopBackgroundColor': Colors.blue, - 'presentationStyle': 'FULL_SCREEN', - 'javaScriptEnabled': true, - }, - requiredPaths: ['url'], - ); - - if (params == null) return; - final url = params['url']?.toString() ?? ''; - if (url.isEmpty) { - _recordMethodResult( - PlatformInAppBrowserMethod.openUrlRequest.name, - 'Please enter a URL', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final baseSettings = settingsManager.buildSettings(); - final webViewSettings = - InAppWebViewSettings.fromMap({ - ...baseSettings.toMap(), - 'javaScriptEnabled': - params['javaScriptEnabled'] as bool? ?? - baseSettings.javaScriptEnabled ?? - true, - }) ?? - InAppWebViewSettings(); - await _browser?.openUrlRequest( - urlRequest: URLRequest(url: WebUri(url)), - settings: InAppBrowserClassSettings( - browserSettings: InAppBrowserSettings( - toolbarTopBackgroundColor: - params['toolbarTopBackgroundColor'] as Color?, - presentationStyle: _parseModalPresentationStyle( - params['presentationStyle']?.toString(), - ), - ), - webViewSettings: webViewSettings, - ), - ); - setState(() => _browserOpened = true); - _recordMethodResult( - PlatformInAppBrowserMethod.openUrlRequest.name, - 'Browser opened with URL', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformInAppBrowserMethod.openUrlRequest.name, - 'Error opening browser: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _openFile() async { - final settingsManager = context.read(); - final params = await showParameterDialog( - context: context, - title: PlatformInAppBrowserMethod.openFile.name, - parameters: { - 'assetFilePath': 'assets/index.html', - 'toolbarTopBackgroundColor': Colors.green, - }, - requiredPaths: ['assetFilePath'], - ); - - if (params == null) return; - final assetFilePath = params['assetFilePath']?.toString() ?? ''; - if (assetFilePath.isEmpty) { - _recordMethodResult( - PlatformInAppBrowserMethod.openFile.name, - 'Please enter an asset file path', - isError: true, - ); - return; - } - setState(() => _isLoading = true); - try { - await _browser?.openFile( - assetFilePath: assetFilePath, - settings: InAppBrowserClassSettings( - browserSettings: InAppBrowserSettings( - toolbarTopBackgroundColor: - params['toolbarTopBackgroundColor'] as Color?, - ), - webViewSettings: settingsManager.buildSettings(), - ), - ); - setState(() => _browserOpened = true); - _recordMethodResult( - PlatformInAppBrowserMethod.openFile.name, - 'Browser opened with file', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformInAppBrowserMethod.openFile.name, - 'Error opening file: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _openData() async { - final settingsManager = context.read(); - final params = await showParameterDialog( - context: context, - title: PlatformInAppBrowserMethod.openData.name, - parameters: { - 'data': - '

Hello ${InAppBrowser}!

This is HTML data.

', - 'mimeType': 'text/html', - 'encoding': 'utf8', - 'toolbarTopBackgroundColor': Colors.purple, - }, - requiredPaths: ['data'], - ); - - if (params == null) return; - final data = params['data']?.toString() ?? ''; - if (data.isEmpty) { - _recordMethodResult( - PlatformInAppBrowserMethod.openData.name, - 'Please enter HTML data', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - await _browser?.openData( - data: data, - mimeType: params['mimeType']?.toString() ?? 'text/html', - encoding: params['encoding']?.toString() ?? 'utf8', - settings: InAppBrowserClassSettings( - browserSettings: InAppBrowserSettings( - toolbarTopBackgroundColor: - params['toolbarTopBackgroundColor'] as Color?, - ), - webViewSettings: settingsManager.buildSettings(), - ), - ); - setState(() => _browserOpened = true); - _recordMethodResult( - PlatformInAppBrowserMethod.openData.name, - 'Browser opened with data', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformInAppBrowserMethod.openData.name, - 'Error opening data: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _openWithSystemBrowser() async { - final params = await showParameterDialog( - context: context, - title: PlatformInAppBrowserMethod.openWithSystemBrowser.name, - parameters: {'url': 'https://flutter.dev'}, - requiredPaths: ['url'], - ); - - if (params == null) return; - final url = params['url']?.toString() ?? ''; - if (url.isEmpty) { - _recordMethodResult( - _staticMethodName(PlatformInAppBrowserMethod.openWithSystemBrowser), - 'Please enter a URL', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - await InAppBrowser.openWithSystemBrowser(url: WebUri(url)); - _recordMethodResult( - _staticMethodName(PlatformInAppBrowserMethod.openWithSystemBrowser), - 'Opened in system browser', - isError: false, - ); - } catch (e) { - _recordMethodResult( - _staticMethodName(PlatformInAppBrowserMethod.openWithSystemBrowser), - 'Error opening system browser: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - void _addMenuItem() { - final id = _menuItemIdController.text.trim(); - final title = _menuItemTitleController.text.trim(); - - if (id.isEmpty || title.isEmpty) { - _recordMethodResult( - PlatformInAppBrowserMethod.addMenuItem.name, - 'Please enter menu item ID and title', - isError: true, - ); - return; - } - - final menuItem = InAppBrowserMenuItem( - id: id.hashCode, - title: title, - onClick: () { - _logEvent(EventType.ui, 'Menu item clicked', data: {'id': id}); - _recordMethodResult( - PlatformInAppBrowserMethod.addMenuItem.name, - 'Menu item "$title" clicked', - isError: false, - ); - }, - ); - - _browser?.addMenuItem(menuItem); - setState(() { - _menuItems.add(menuItem); - }); - _menuItemIdController.clear(); - _recordMethodResult( - PlatformInAppBrowserMethod.addMenuItem.name, - 'Menu item added', - isError: false, - ); - } - - void _removeMenuItem(InAppBrowserMenuItem menuItem) { - final removed = _browser?.removeMenuItem(menuItem) ?? false; - if (removed) { - setState(() { - _menuItems.remove(menuItem); - }); - _recordMethodResult( - PlatformInAppBrowserMethod.removeMenuItem.name, - 'Menu item removed', - isError: false, - ); - } else { - _recordMethodResult( - PlatformInAppBrowserMethod.removeMenuItem.name, - 'Failed to remove menu item', - isError: true, - ); - } - } - - Future _show() async { - setState(() => _isLoading = true); - try { - await _browser?.show(); - _recordMethodResult( - PlatformInAppBrowserMethod.show.name, - 'Browser shown', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformInAppBrowserMethod.show.name, - 'Error showing browser: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _hide() async { - setState(() => _isLoading = true); - try { - await _browser?.hide(); - _recordMethodResult( - PlatformInAppBrowserMethod.hide.name, - 'Browser hidden', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformInAppBrowserMethod.hide.name, - 'Error hiding browser: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _close() async { - setState(() => _isLoading = true); - try { - await _browser?.close(); - setState(() => _browserOpened = false); - _recordMethodResult( - PlatformInAppBrowserMethod.close.name, - 'Browser closed', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformInAppBrowserMethod.close.name, - 'Error closing browser: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _isHidden() async { - setState(() => _isLoading = true); - try { - final hidden = await _browser?.isHidden(); - _recordMethodResult( - PlatformInAppBrowserMethod.isHidden.name, - 'Browser is hidden: $hidden', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformInAppBrowserMethod.isHidden.name, - 'Error checking hidden state: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getSettings() async { - setState(() => _isLoading = true); - try { - final settings = await _browser?.getSettings(); - _showSettingsDialog(settings); - _recordMethodResult( - PlatformInAppBrowserMethod.getSettings.name, - 'Settings dialog opened', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformInAppBrowserMethod.getSettings.name, - 'Error getting settings: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _setSettings() async { - final params = await showParameterDialog( - context: context, - title: PlatformInAppBrowserMethod.setSettings.name, - parameters: { - 'toolbarTopBackgroundColor': Colors.orange, - 'hideToolbarTop': false, - }, - ); - - if (params == null) return; - setState(() => _isLoading = true); - try { - await _browser?.setSettings( - settings: InAppBrowserClassSettings( - browserSettings: InAppBrowserSettings( - toolbarTopBackgroundColor: - params['toolbarTopBackgroundColor'] as Color?, - hideToolbarTop: params['hideToolbarTop'] as bool?, - ), - ), - ); - _recordMethodResult( - PlatformInAppBrowserMethod.setSettings.name, - 'Settings updated', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformInAppBrowserMethod.setSettings.name, - 'Error setting settings: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - void _checkIsOpened() { - final opened = _browser?.isOpened() ?? false; - _recordMethodResult( - PlatformInAppBrowserMethod.isOpened.name, - 'Browser is opened: $opened', - isError: false, - ); - } - - void _showSettingsDialog(InAppBrowserClassSettings? settings) { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Browser Settings'), - content: SingleChildScrollView( - child: Text(settings?.toMap().toString() ?? 'No settings'), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Close'), - ), - ], - ), - ); - } - - void _recordMethodResult( - String methodName, - String message, { - required bool isError, - dynamic value, - }) { - setState(() { - final entries = List.from( - _methodHistory[methodName] ?? const [], - ); - entries.insert( - 0, - MethodResultEntry( - message: message, - isError: isError, - timestamp: DateTime.now(), - value: value, - ), - ); - if (entries.length > _maxHistoryEntries) { - entries.removeRange(_maxHistoryEntries, entries.length); - } - _methodHistory[methodName] = entries; - _selectedHistoryIndex[methodName] = 0; - }); - } - - Widget _buildMethodHistory(String methodName, {String? title}) { - final entries = _methodHistory[methodName] ?? const []; - if (entries.isEmpty) { - return const SizedBox.shrink(); - } - return MethodResultHistory( - entries: entries, - selectedIndex: _selectedHistoryIndex[methodName], - title: title ?? methodName, - onSelected: (index) { - setState(() => _selectedHistoryIndex[methodName] = index); - }, - ); - } - - void _showInitError(String message) { - _recordMethodResult(_initStatusKey, message, isError: true); - } - - void _handleEnvironmentChange(WebViewEnvironment? environment) { - if (_browserOpened) { - _browser?.close(); - } - _browser?.dispose(); - _initBrowser(environment); - setState(() => _browserOpened = false); - } - - Widget _buildInitStatusSection() { - final entries = _methodHistory[_initStatusKey] ?? const []; - if (entries.isEmpty) { - return const SizedBox.shrink(); - } - return Column( - children: [ - _buildMethodHistory(_initStatusKey, title: 'Initialization'), - const SizedBox(height: 16), - ], - ); - } - - ModalPresentationStyle _parseModalPresentationStyle(String? value) { - if (value == null || value.isEmpty) { - return ModalPresentationStyle.FULL_SCREEN; - } - return ModalPresentationStyle.values.firstWhere( - (style) => style.name().toLowerCase() == value.toLowerCase(), - orElse: () => ModalPresentationStyle.FULL_SCREEN, - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text('$InAppBrowser'), - actions: [ - AppBarLoadingIndicator(isLoading: _isLoading), - IconButton( - icon: const Icon(Icons.clear_all), - tooltip: 'Clear Events', - onPressed: () { - context.read().clear(); - }, - ), - ], - ), - drawer: AppDrawer(), - body: ListView( - key: const Key('inapp_browser_main_list'), - padding: const EdgeInsets.all(16), - children: [ - ProfileSelectorCard( - onEditSettingsProfile: () => - Navigator.pushNamed(context, '/settings'), - ), - const SizedBox(height: 16), - _buildStatusCard(), - const SizedBox(height: 16), - _buildInitStatusSection(), - _buildOpenMethods(), - const SizedBox(height: 16), - _buildMenuItemsSection(), - const SizedBox(height: 16), - _buildControlMethods(), - const SizedBox(height: 16), - _buildSettingsMethods(), - const SizedBox(height: 16), - const EventLogCard(maxEvents: 20, height: 200), - ], - ), - ); - } - - Widget _buildStatusCard() { - return StatusCard( - isActive: _browserOpened, - activeTitle: 'Browser Open', - inactiveTitle: 'Browser Closed', - activeIcon: Icons.web, - inactiveIcon: Icons.web_asset_off, - subtitle: 'ID: ${_browser?.id ?? "N/A"}', - ); - } - - Widget _buildOpenMethods() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Open Methods', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 12), - _buildMethodTile( - PlatformInAppBrowserMethod.openUrlRequest.name, - 'Open browser with URL request', - PlatformInAppBrowserMethod.openUrlRequest, - _openUrlRequest, - ), - _buildMethodTile( - PlatformInAppBrowserMethod.openFile.name, - 'Open browser with local file', - PlatformInAppBrowserMethod.openFile, - _openFile, - ), - _buildMethodTile( - PlatformInAppBrowserMethod.openData.name, - 'Open browser with HTML data', - PlatformInAppBrowserMethod.openData, - _openData, - ), - _buildMethodTile( - _staticMethodName( - PlatformInAppBrowserMethod.openWithSystemBrowser, - ), - 'Open URL in system browser', - PlatformInAppBrowserMethod.openWithSystemBrowser, - _openWithSystemBrowser, - ), - ], - ), - ), - ); - } - - Widget _buildMenuItemsSection() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Menu Items', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 12), - LayoutBuilder( - builder: (context, constraints) { - final isMobile = ResponsiveBreakpoints.isMobileWidth( - constraints.maxWidth, - ); - const spacing = 8.0; - const buttonWidth = 96.0; - final availableWidth = constraints.maxWidth; - final remainingWidth = isMobile - ? availableWidth - : (availableWidth - buttonWidth - spacing * 2); - final idWidth = isMobile - ? availableWidth - : remainingWidth * 0.35; - final titleWidth = isMobile - ? availableWidth - : remainingWidth * 0.65; - - return Wrap( - key: const Key('inapp_browser_menu_items_layout'), - spacing: spacing, - runSpacing: spacing, - children: [ - SizedBox( - width: idWidth, - child: TextField( - key: const Key('inapp_browser_menu_id_field'), - controller: _menuItemIdController, - decoration: const InputDecoration( - labelText: 'ID', - border: OutlineInputBorder(), - isDense: true, - ), - ), - ), - SizedBox( - width: titleWidth, - child: TextField( - key: const Key('inapp_browser_menu_title_field'), - controller: _menuItemTitleController, - decoration: const InputDecoration( - labelText: 'Title', - border: OutlineInputBorder(), - isDense: true, - ), - ), - ), - SizedBox( - width: isMobile ? availableWidth : buttonWidth, - child: ElevatedButton( - key: const Key('inapp_browser_menu_add_button'), - onPressed: _addMenuItem, - child: const Text('Add'), - ), - ), - ], - ); - }, - ), - const SizedBox(height: 8), - _buildMethodHistory(PlatformInAppBrowserMethod.addMenuItem.name), - _buildMethodHistory(PlatformInAppBrowserMethod.removeMenuItem.name), - const SizedBox(height: 12), - if (_menuItems.isNotEmpty) ...[ - const Divider(), - ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: _menuItems.length, - itemBuilder: (context, index) { - final item = _menuItems[index]; - return ListTile( - dense: true, - title: Text(item.title), - subtitle: Text('ID: ${item.id}'), - trailing: IconButton( - icon: const Icon(Icons.delete, size: 20), - onPressed: () => _removeMenuItem(item), - ), - ); - }, - ), - ], - ], - ), - ), - ); - } - - Widget _buildControlMethods() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Control Methods', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 12), - _buildMethodTile( - PlatformInAppBrowserMethod.show.name, - 'Show the browser', - PlatformInAppBrowserMethod.show, - _browserOpened ? _show : null, - ), - _buildMethodTile( - PlatformInAppBrowserMethod.hide.name, - 'Hide the browser', - PlatformInAppBrowserMethod.hide, - _browserOpened ? _hide : null, - ), - _buildMethodTile( - PlatformInAppBrowserMethod.close.name, - 'Close the browser', - PlatformInAppBrowserMethod.close, - _browserOpened ? _close : null, - ), - _buildMethodTile( - PlatformInAppBrowserMethod.isHidden.name, - 'Check if browser is hidden', - PlatformInAppBrowserMethod.isHidden, - _browserOpened ? _isHidden : null, - ), - _buildMethodTile( - PlatformInAppBrowserMethod.isOpened.name, - 'Check if browser is opened', - PlatformInAppBrowserMethod.isOpened, - _checkIsOpened, - ), - ], - ), - ), - ); - } - - Widget _buildSettingsMethods() { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Settings Methods', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 12), - _buildMethodTile( - PlatformInAppBrowserMethod.getSettings.name, - 'Get current browser settings', - PlatformInAppBrowserMethod.getSettings, - _browserOpened ? _getSettings : null, - ), - _buildMethodTile( - PlatformInAppBrowserMethod.setSettings.name, - 'Update browser settings', - PlatformInAppBrowserMethod.setSettings, - _browserOpened ? _setSettings : null, - ), - ], - ), - ), - ); - } - - Widget _buildMethodTile( - String methodName, - String description, - PlatformInAppBrowserMethod method, - VoidCallback? onPressed, - ) { - final supportedPlatforms = SupportCheckHelper.supportedPlatformsForMethod( - method: method, - checker: InAppBrowser.isMethodSupported, - ); - - return MethodTile( - methodName: methodName, - description: description, - supportedPlatforms: supportedPlatforms, - onRun: !_isLoading ? onPressed : null, - historyEntries: _methodHistory[methodName], - selectedHistoryIndex: _selectedHistoryIndex[methodName], - onHistorySelected: (index) { - setState(() => _selectedHistoryIndex[methodName] = index); - }, - ); - } -} diff --git a/flutter_inappwebview/example/lib/screens/category_screen.dart b/flutter_inappwebview/example/lib/screens/category_screen.dart deleted file mode 100644 index 6408b3ac17..0000000000 --- a/flutter_inappwebview/example/lib/screens/category_screen.dart +++ /dev/null @@ -1,193 +0,0 @@ -import 'package:flutter/material.dart'; -import '../utils/constants.dart'; -import '../utils/support_checker.dart'; -import '../models/test_case.dart'; -import '../utils/test_registry.dart'; -import '../widgets/common/test_card.dart'; -import '../widgets/common/platform_filter.dart'; -import '../widgets/common/empty_state.dart'; - -/// Screen displaying all tests for a specific category. -class CategoryScreen extends StatefulWidget { - final TestCategory category; - - const CategoryScreen({super.key, required this.category}); - - @override - State createState() => _CategoryScreenState(); -} - -class _CategoryScreenState extends State { - List _selectedPlatforms = []; - - @override - Widget build(BuildContext context) { - final allTests = TestRegistry.getTestsByCategory(widget.category); - final filteredTests = _filterTests(allTests); - - return Scaffold( - appBar: AppBar( - title: Text('${_getCategoryName()} Tests'), - actions: [ - IconButton( - icon: const Icon(Icons.filter_list), - onPressed: _showFilterDialog, - tooltip: 'Filter by platform', - ), - ], - ), - body: Column( - children: [ - if (_selectedPlatforms.isNotEmpty) - Container( - padding: const EdgeInsets.all(8.0), - color: Theme.of(context).primaryColor.withOpacity(0.1), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Filtered: ${_selectedPlatforms.map((p) => p.displayName).join(", ")}', - style: TextStyle( - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(width: 8), - TextButton( - onPressed: () { - setState(() { - _selectedPlatforms = []; - }); - }, - child: const Text('Clear'), - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - children: [ - Icon(_getCategoryIcon(), color: Theme.of(context).primaryColor), - const SizedBox(width: 8), - Text( - '${filteredTests.length} test${filteredTests.length != 1 ? 's' : ''}', - style: Theme.of(context).textTheme.titleMedium, - ), - ], - ), - ), - Expanded( - child: filteredTests.isEmpty - ? _buildEmptyState() - : ListView.builder( - padding: const EdgeInsets.all(16.0), - itemCount: filteredTests.length, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.only(bottom: 12.0), - child: TestCard( - testCase: filteredTests[index], - onRun: () { - // TODO: Execute test in Phase 3 - }, - ), - ); - }, - ), - ), - ], - ), - ); - } - - List _filterTests(List tests) { - if (_selectedPlatforms.isEmpty) { - return tests; - } - - return tests.where((test) { - return _selectedPlatforms.any( - (platform) => test.supportedPlatforms.contains(platform.name), - ); - }).toList(); - } - - void _showFilterDialog() { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Filter by Platform'), - content: SingleChildScrollView( - child: PlatformFilter( - selectedPlatforms: _selectedPlatforms, - onChanged: (newSelection) { - setState(() { - _selectedPlatforms = newSelection; - }); - }, - ), - ), - actions: [ - TextButton( - onPressed: () { - setState(() { - _selectedPlatforms = []; - }); - Navigator.pop(context); - }, - child: const Text('Close'), - ), - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), - ), - ], - ), - ); - } - - Widget _buildEmptyState() { - return EmptyState( - icon: Icons.search_off, - title: 'No tests available', - description: _selectedPlatforms.isNotEmpty - ? 'No tests match the selected platforms' - : 'No tests registered for this category', - ); - } - - String _getCategoryName() { - switch (widget.category) { - case TestCategory.navigation: - return 'Navigation'; - case TestCategory.javascript: - return 'JavaScript'; - case TestCategory.content: - return 'Content'; - case TestCategory.storage: - return 'Storage & Cookies'; - case TestCategory.advanced: - return 'Advanced Features'; - case TestCategory.browsers: - return 'Browsers'; - } - } - - IconData _getCategoryIcon() { - switch (widget.category) { - case TestCategory.navigation: - return Icons.navigation; - case TestCategory.javascript: - return Icons.code; - case TestCategory.content: - return Icons.article; - case TestCategory.storage: - return Icons.storage; - case TestCategory.advanced: - return Icons.settings; - case TestCategory.browsers: - return Icons.web; - } - } -} diff --git a/flutter_inappwebview/example/lib/screens/home_screen.dart b/flutter_inappwebview/example/lib/screens/home_screen.dart deleted file mode 100644 index f70cb6d026..0000000000 --- a/flutter_inappwebview/example/lib/screens/home_screen.dart +++ /dev/null @@ -1,186 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import '../widgets/common/app_drawer.dart'; -import '../utils/constants.dart'; -import '../utils/test_registry.dart'; -import '../utils/platform_utils.dart'; -import 'category_screen.dart'; -import 'platform_info_screen.dart'; - -/// Main dashboard screen showing all test categories. -class HomeScreen extends StatelessWidget { - const HomeScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text('${InAppWebView} Test Suite'), - actions: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - Icon(PlatformUtils.getPlatformIcon(), size: 20), - const SizedBox(width: 8), - Text( - PlatformUtils.getPlatformName(), - style: const TextStyle(fontSize: 14), - ), - ], - ), - ), - ], - ), - drawer: AppDrawer(), - body: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Test Categories', - style: Theme.of( - context, - ).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.bold), - ), - const SizedBox(height: 8), - Text( - 'Select a category to run tests', - style: Theme.of( - context, - ).textTheme.bodyMedium?.copyWith(color: Colors.grey[600]), - ), - const SizedBox(height: 24), - Expanded( - child: SingleChildScrollView( - child: GridView.count( - crossAxisCount: 2, - mainAxisSpacing: 16, - crossAxisSpacing: 16, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - children: [ - _buildCategoryCard( - context, - category: TestCategory.navigation, - title: 'Navigation', - icon: Icons.navigation, - color: Colors.blue, - ), - _buildCategoryCard( - context, - category: TestCategory.javascript, - title: 'JavaScript', - icon: Icons.code, - color: Colors.amber, - ), - _buildCategoryCard( - context, - category: TestCategory.content, - title: 'Content', - icon: Icons.article, - color: Colors.green, - ), - _buildCategoryCard( - context, - category: TestCategory.storage, - title: 'Storage & Cookies', - icon: Icons.storage, - color: Colors.purple, - ), - _buildCategoryCard( - context, - category: TestCategory.advanced, - title: 'Advanced Features', - icon: Icons.settings, - color: Colors.orange, - ), - _buildCategoryCard( - context, - category: TestCategory.browsers, - title: 'Browsers', - icon: Icons.web, - color: Colors.teal, - ), - ], - ), - ), - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => const PlatformInfoScreen()), - ); - }, - tooltip: 'Platform Info', - child: const Icon(Icons.info_outline), - ), - ); - } - - Widget _buildCategoryCard( - BuildContext context, { - required TestCategory category, - required String title, - required IconData icon, - required Color color, - }) { - final testCount = TestRegistry.getTestsByCategory(category).length; - - return Card( - elevation: 4, - child: InkWell( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => CategoryScreen(category: category), - ), - ); - }, - borderRadius: BorderRadius.circular(4), - child: Container( - padding: const EdgeInsets.all(16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(icon, size: 48, color: color), - const SizedBox(height: 12), - Text( - title, - textAlign: TextAlign.center, - style: Theme.of( - context, - ).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), - ), - const SizedBox(height: 8), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 4, - ), - decoration: BoxDecoration( - color: color.withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - ), - child: Text( - '$testCount test${testCount != 1 ? 's' : ''}', - style: TextStyle( - fontSize: 12, - color: color, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - ), - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/screens/platform_info_screen.dart b/flutter_inappwebview/example/lib/screens/platform_info_screen.dart deleted file mode 100644 index 7e0e9077ee..0000000000 --- a/flutter_inappwebview/example/lib/screens/platform_info_screen.dart +++ /dev/null @@ -1,239 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import '../utils/platform_utils.dart'; -import '../widgets/common/section_card.dart'; - -/// Screen displaying detailed platform information and capabilities. -class PlatformInfoScreen extends StatelessWidget { - const PlatformInfoScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text('Platform Information')), - body: ListView( - padding: const EdgeInsets.all(16.0), - children: [ - InfoSection( - title: 'Platform Details', - icon: PlatformUtils.getPlatformIcon(), - children: [ - _buildInfoTile( - 'Platform', - PlatformUtils.getPlatformName(), - Icons.devices, - ), - _buildInfoTile( - 'Flutter Version', - PlatformUtils.getFlutterVersion(), - Icons.flutter_dash, - ), - _buildInfoTile( - 'Dart Version', - PlatformUtils.getDartVersion(), - Icons.code, - ), - _buildInfoTile( - 'Platform Type', - _getPlatformType(), - Icons.category, - ), - ], - ), - const SizedBox(height: 24), - InfoSection( - title: 'Core WebView Features', - icon: Icons.web, - children: [_buildFeaturesList(context, _getCoreWebViewFeatures())], - ), - const SizedBox(height: 24), - InfoSection( - title: 'Browser Features', - icon: Icons.open_in_browser, - children: [_buildFeaturesList(context, _getBrowserFeatures())], - ), - const SizedBox(height: 24), - InfoSection( - title: 'Storage & Data', - icon: Icons.storage, - children: [_buildFeaturesList(context, _getStorageFeatures())], - ), - const SizedBox(height: 24), - InfoSection( - title: 'Controllers', - icon: Icons.tune, - children: [_buildFeaturesList(context, _getControllerFeatures())], - ), - const SizedBox(height: 24), - InfoSection( - title: 'Messaging & Communication', - icon: Icons.message, - children: [_buildFeaturesList(context, _getMessagingFeatures())], - ), - const SizedBox(height: 24), - InfoSection( - title: 'Advanced Features', - icon: Icons.settings_applications, - children: [_buildFeaturesList(context, _getAdvancedFeatures())], - ), - ], - ), - ); - } - - Widget _buildInfoTile(String label, String value, IconData icon) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Row( - children: [ - Icon(icon, size: 20, color: Colors.grey[600]), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - label, - style: const TextStyle( - fontSize: 12, - color: Colors.grey, - fontWeight: FontWeight.w500, - ), - ), - const SizedBox(height: 4), - Text( - value, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildFeaturesList(BuildContext context, Map features) { - return Column( - children: features.entries.map((entry) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 4.0), - child: Row( - children: [ - Icon( - entry.value ? Icons.check_circle : Icons.cancel, - color: entry.value ? Colors.green : Colors.red, - size: 20, - ), - const SizedBox(width: 12), - Expanded( - child: Text(entry.key, style: const TextStyle(fontSize: 14)), - ), - ], - ), - ); - }).toList(), - ); - } - - String _getPlatformType() { - if (PlatformUtils.isWebPlatform()) { - return 'Web'; - } else if (PlatformUtils.isMobilePlatform()) { - return 'Mobile'; - } else if (PlatformUtils.isDesktopPlatform()) { - return 'Desktop'; - } - return 'Unknown'; - } - - /// Core WebView features - Map _getCoreWebViewFeatures() { - try { - return { - '${InAppWebView} (Widget)': InAppWebView.isClassSupported(), - '${InAppWebViewController}': InAppWebViewController.isClassSupported(), - '${HeadlessInAppWebView}': HeadlessInAppWebView.isClassSupported(), - }; - } catch (e) { - return {}; - } - } - - /// Browser features - Map _getBrowserFeatures() { - try { - return { - '${InAppBrowser}': InAppBrowser.isClassSupported(), - '${ChromeSafariBrowser}': ChromeSafariBrowser.isClassSupported(), - '${WebAuthenticationSession}': - WebAuthenticationSession.isClassSupported(), - }; - } catch (e) { - return {}; - } - } - - /// Storage and data features - Map _getStorageFeatures() { - try { - return { - '${CookieManager}': CookieManager.isClassSupported(), - '${WebStorage}': WebStorage.isClassSupported(), - '${LocalStorage}': LocalStorage.isClassSupported(), - '${SessionStorage}': SessionStorage.isClassSupported(), - '${WebStorageManager}': WebStorageManager.isClassSupported(), - '${HttpAuthCredentialDatabase}': - HttpAuthCredentialDatabase.isClassSupported(), - }; - } catch (e) { - return {}; - } - } - - /// Controller features - Map _getControllerFeatures() { - try { - return { - '${PullToRefreshController}': - PullToRefreshController.isClassSupported(), - '${FindInteractionController}': - FindInteractionController.isClassSupported(), - '${PrintJobController}': PrintJobController.isClassSupported(), - '${ServiceWorkerController}': - ServiceWorkerController.isClassSupported(), - '${ProxyController}': ProxyController.isClassSupported(), - '${TracingController}': TracingController.isClassSupported(), - }; - } catch (e) { - return {}; - } - } - - /// Messaging and communication features - Map _getMessagingFeatures() { - try { - return { - '${WebMessageChannel}': WebMessageChannel.isClassSupported(), - '${WebMessageListener}': WebMessageListener.isClassSupported(), - }; - } catch (e) { - return {}; - } - } - - /// Advanced features - Map _getAdvancedFeatures() { - try { - return { - '${WebViewEnvironment}': WebViewEnvironment.isClassSupported(), - '${ProcessGlobalConfig}': ProcessGlobalConfig.isClassSupported(), - }; - } catch (e) { - return {}; - } - } -} diff --git a/flutter_inappwebview/example/lib/screens/settings_editor_screen.dart b/flutter_inappwebview/example/lib/screens/settings_editor_screen.dart deleted file mode 100644 index 7a6776454c..0000000000 --- a/flutter_inappwebview/example/lib/screens/settings_editor_screen.dart +++ /dev/null @@ -1,893 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; -import 'package:flutter_inappwebview_example/models/setting_definition.dart'; -import 'package:flutter_inappwebview_example/models/settings_profile.dart'; -import 'package:flutter_inappwebview_example/utils/platform_utils.dart'; -import 'package:flutter_inappwebview_example/utils/responsive_utils.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; -import 'package:flutter_inappwebview_example/widgets/common/support_badge.dart'; -import 'package:flutter_inappwebview_example/widgets/common/app_drawer.dart'; -import 'package:flutter_inappwebview_example/widgets/settings/responsive_setting_tile.dart'; - -/// Comprehensive settings editor for InAppWebViewSettings -class SettingsEditorScreen extends StatefulWidget { - const SettingsEditorScreen({super.key}); - - @override - State createState() => _SettingsEditorScreenState(); -} - -class _SettingsEditorScreenState extends State { - final TextEditingController _profileNameController = TextEditingController(); - final TextEditingController _searchController = TextEditingController(); - String _searchQuery = ''; - Set _expandedCategories = {}; - - @override - void initState() { - super.initState(); - // Initialize the settings manager if not already done - WidgetsBinding.instance.addPostFrameCallback((_) { - final settingsManager = context.read(); - if (settingsManager.isLoading) { - settingsManager.init(); - } - }); - } - - @override - void dispose() { - _profileNameController.dispose(); - _searchController.dispose(); - super.dispose(); - } - - SupportedPlatform? get _currentPlatform => PlatformUtils.getCurrentPlatform(); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Settings Editor'), - actions: [ - IconButton( - icon: const Icon(Icons.save), - tooltip: 'Save Profile', - onPressed: _showSaveProfileDialog, - ), - IconButton( - icon: const Icon(Icons.folder_open), - tooltip: 'Load Profile', - onPressed: _showLoadProfileDialog, - ), - PopupMenuButton( - icon: const Icon(Icons.more_vert), - onSelected: _handleMenuAction, - itemBuilder: (context) => [ - const PopupMenuItem( - value: 'reset', - child: ListTile( - leading: Icon(Icons.restore), - title: Text('Reset to Defaults'), - contentPadding: EdgeInsets.zero, - ), - ), - const PopupMenuItem( - value: 'export', - child: ListTile( - leading: Icon(Icons.download), - title: Text('Export JSON'), - contentPadding: EdgeInsets.zero, - ), - ), - const PopupMenuItem( - value: 'import', - child: ListTile( - leading: Icon(Icons.upload), - title: Text('Import JSON'), - contentPadding: EdgeInsets.zero, - ), - ), - const PopupMenuDivider(), - const PopupMenuItem( - value: 'expand_all', - child: ListTile( - leading: Icon(Icons.unfold_more), - title: Text('Expand All'), - contentPadding: EdgeInsets.zero, - ), - ), - const PopupMenuItem( - value: 'collapse_all', - child: ListTile( - leading: Icon(Icons.unfold_less), - title: Text('Collapse All'), - contentPadding: EdgeInsets.zero, - ), - ), - ], - ), - ], - ), - drawer: AppDrawer(), - body: Consumer( - builder: (context, settingsManager, child) { - if (settingsManager.isLoading) { - return const Center(child: CircularProgressIndicator()); - } - - final definitions = SettingsManager.getSettingDefinitions(); - - return Column( - children: [ - _buildHeader(settingsManager), - _buildSearchBar(), - Expanded( - child: ListView( - padding: const EdgeInsets.all(16), - children: definitions.entries.map((entry) { - return _buildCategorySection( - entry.key, - entry.value, - settingsManager, - ); - }).toList(), - ), - ), - _buildBottomBar(settingsManager), - ], - ); - }, - ), - ); - } - - Widget _buildHeader(SettingsManager settingsManager) { - final profile = settingsManager.currentProfile; - final modifiedCount = settingsManager.modifiedSettings.length; - - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.blue.shade50, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: Row( - children: [ - Icon(Icons.settings, color: Colors.blue.shade700), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - profile != null - ? 'Profile: ${profile.name}' - : 'New Configuration', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - Text( - modifiedCount > 0 - ? '$modifiedCount setting${modifiedCount == 1 ? '' : 's'} modified' - : 'Using default settings', - style: TextStyle( - fontSize: 12, - color: modifiedCount > 0 - ? Colors.orange.shade700 - : Colors.grey.shade600, - ), - ), - ], - ), - ), - Chip( - label: Text( - _currentPlatform?.displayName.toUpperCase() ?? 'UNKNOWN', - ), - backgroundColor: Colors.blue.shade100, - labelStyle: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Colors.blue.shade800, - ), - ), - ], - ), - ); - } - - Widget _buildSearchBar() { - return Padding( - padding: const EdgeInsets.all(16), - child: TextField( - controller: _searchController, - decoration: InputDecoration( - hintText: 'Search settings...', - prefixIcon: const Icon(Icons.search), - suffixIcon: _searchQuery.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear), - onPressed: () { - _searchController.clear(); - setState(() => _searchQuery = ''); - }, - ) - : null, - border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 12, - ), - ), - onChanged: (value) { - setState(() => _searchQuery = value.toLowerCase()); - }, - ), - ); - } - - Widget _buildCategorySection( - String category, - List settings, - SettingsManager settingsManager, - ) { - // Filter settings based on search query - final filteredSettings = settings.where((setting) { - if (_searchQuery.isEmpty) return true; - return setting.name.toLowerCase().contains(_searchQuery) || - setting.description.toLowerCase().contains(_searchQuery) || - setting.key.toLowerCase().contains(_searchQuery); - }).toList(); - - if (filteredSettings.isEmpty) return const SizedBox.shrink(); - - final isExpanded = - _expandedCategories.contains(category) || _searchQuery.isNotEmpty; - final header = Row( - children: [ - Text( - category, - style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), - ), - const SizedBox(width: 8), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), - decoration: BoxDecoration( - color: Colors.grey.shade200, - borderRadius: BorderRadius.circular(12), - ), - child: Text( - '${filteredSettings.length}', - style: TextStyle(fontSize: 12, color: Colors.grey.shade700), - ), - ), - ], - ); - final subtitle = Text( - '${filteredSettings.length} setting${filteredSettings.length == 1 ? '' : 's'}', - style: TextStyle(color: Colors.grey.shade600, fontSize: 12), - ); - - return Card( - margin: const EdgeInsets.only(bottom: 8), - child: ExpansionTile( - key: ValueKey('$category-$isExpanded'), - initiallyExpanded: isExpanded, - onExpansionChanged: (expanded) { - setState(() { - if (expanded) { - _expandedCategories.add(category); - } else { - _expandedCategories.remove(category); - } - }); - }, - title: header, - subtitle: subtitle, - children: filteredSettings.map((setting) { - return _buildSettingTile(setting, settingsManager); - }).toList(), - ), - ); - } - - Widget _buildSettingTile( - SettingDefinition setting, - SettingsManager settingsManager, - ) { - final isModified = settingsManager.isSettingModified(setting.key); - final currentValue = settingsManager.getSetting(setting.key); - final hasPlatformLimitations = setting.hasPlatformLimitations; - - return Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - decoration: BoxDecoration( - color: isModified ? Colors.orange.shade50 : null, - border: Border(bottom: BorderSide(color: Colors.grey.shade200)), - ), - child: ResponsiveSettingTile( - title: Row( - children: [ - Flexible( - child: Text( - setting.name, - style: const TextStyle( - fontWeight: FontWeight.w600, - color: Colors.black87, - ), - ), - ), - if (isModified) ...[ - const SizedBox(width: 8), - Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: Colors.orange.shade200, - borderRadius: BorderRadius.circular(4), - ), - child: const Text( - 'Modified', - style: TextStyle(fontSize: 10, fontWeight: FontWeight.bold), - ), - ), - ], - ], - ), - description: Text( - setting.description, - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - badges: hasPlatformLimitations - ? SupportBadgesRow( - supportedPlatforms: setting.supportedPlatforms, - compact: true, - ) - : null, - trailing: isModified - ? IconButton( - icon: const Icon(Icons.restore, size: 20), - tooltip: 'Reset to default', - onPressed: () => settingsManager.resetSetting(setting.key), - ) - : null, - control: _buildSettingControl(setting, currentValue, settingsManager), - inlineControl: setting.type == SettingType.boolean, - ), - ); - } - - Widget _buildSettingControl( - SettingDefinition setting, - dynamic currentValue, - SettingsManager settingsManager, - ) { - switch (setting.type) { - case SettingType.boolean: - return Switch( - value: currentValue ?? setting.defaultValue ?? false, - onChanged: (value) => - settingsManager.updateSetting(setting.key, value), - ); - - case SettingType.string: - return TextField( - controller: TextEditingController( - text: currentValue?.toString() ?? '', - ), - decoration: const InputDecoration( - isDense: true, - contentPadding: EdgeInsets.symmetric(horizontal: 8, vertical: 8), - border: OutlineInputBorder(), - ), - style: const TextStyle(fontSize: 14), - onChanged: (value) => - settingsManager.updateSetting(setting.key, value), - ); - - case SettingType.integer: - return TextField( - controller: TextEditingController( - text: currentValue?.toString() ?? '', - ), - keyboardType: TextInputType.number, - inputFormatters: [FilteringTextInputFormatter.digitsOnly], - decoration: const InputDecoration( - isDense: true, - contentPadding: EdgeInsets.symmetric(horizontal: 8, vertical: 8), - border: OutlineInputBorder(), - ), - style: const TextStyle(fontSize: 14), - onChanged: (value) { - final intValue = int.tryParse(value); - if (intValue != null) { - settingsManager.updateSetting(setting.key, intValue); - } - }, - ); - - case SettingType.double: - return TextField( - controller: TextEditingController( - text: currentValue?.toString() ?? '', - ), - keyboardType: const TextInputType.numberWithOptions(decimal: true), - decoration: const InputDecoration( - isDense: true, - contentPadding: EdgeInsets.symmetric(horizontal: 8, vertical: 8), - border: OutlineInputBorder(), - ), - style: const TextStyle(fontSize: 14), - onChanged: (value) { - final doubleValue = double.tryParse(value); - if (doubleValue != null) { - settingsManager.updateSetting(setting.key, doubleValue); - } - }, - ); - - case SettingType.enumeration: - if (setting.enumValues == null || setting.enumValues!.isEmpty) { - return const SizedBox.shrink(); - } - final selectedValue = _resolveEnumSelection(setting, currentValue); - return DropdownButton( - value: selectedValue, - isExpanded: true, - items: [ - const DropdownMenuItem( - value: null, - child: Text('Not Set', style: TextStyle(fontSize: 14)), - ), - ...setting.enumValues!.map((enumValue) { - return DropdownMenuItem( - value: enumValue, - child: Text( - SettingDefinition.enumDisplayName(enumValue), - style: const TextStyle(fontSize: 14), - ), - ); - }), - ], - onChanged: (value) => settingsManager.updateSetting( - setting.key, - SettingDefinition.enumValueToNative(value), - ), - ); - } - } - - dynamic _resolveEnumSelection( - SettingDefinition setting, - dynamic currentValue, - ) { - if (currentValue == null) return null; - final enumValues = setting.enumValues; - if (enumValues == null || enumValues.isEmpty) return null; - - if (enumValues.contains(currentValue)) { - return currentValue; - } - - for (final enumValue in enumValues) { - final nativeValue = SettingDefinition.enumValueToNative(enumValue); - if (nativeValue == currentValue) { - return enumValue; - } - } - - return null; - } - - Widget _buildBottomBar(SettingsManager settingsManager) { - final isMobile = context.isMobile; - final resetButton = OutlinedButton.icon( - icon: const Icon(Icons.restore), - label: const Text('Reset All'), - onPressed: () => _showResetConfirmDialog(settingsManager), - ); - final applyButton = ElevatedButton.icon( - icon: const Icon(Icons.check), - label: const Text('Apply to WebView'), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.blue, - foregroundColor: Colors.white, - ), - onPressed: () { - final settings = settingsManager.buildSettings(); - Navigator.pop(context, settings); - }, - ); - - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: Colors.grey.shade300)), - boxShadow: [ - BoxShadow( - color: Colors.grey.shade200, - blurRadius: 4, - offset: const Offset(0, -2), - ), - ], - ), - child: isMobile - ? Wrap( - key: const ValueKey('settings_bottom_bar_actions'), - spacing: 12, - runSpacing: 8, - children: [resetButton, applyButton], - ) - : Row( - key: const ValueKey('settings_bottom_bar_actions'), - children: [resetButton, const Spacer(), applyButton], - ), - ); - } - - void _handleMenuAction(String action) { - final settingsManager = context.read(); - - switch (action) { - case 'reset': - _showResetConfirmDialog(settingsManager); - break; - case 'export': - _exportSettings(settingsManager); - break; - case 'import': - _showImportDialog(settingsManager); - break; - case 'expand_all': - setState(() { - _expandedCategories = SettingsManager.getSettingDefinitions().keys - .toSet(); - }); - break; - case 'collapse_all': - setState(() { - _expandedCategories.clear(); - }); - break; - } - } - - void _showSaveProfileDialog() { - final settingsManager = context.read(); - final currentProfile = settingsManager.currentProfile; - _profileNameController.text = currentProfile?.name ?? ''; - - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Save Profile'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextField( - controller: _profileNameController, - decoration: const InputDecoration( - labelText: 'Profile Name', - hintText: 'Enter a name for this profile', - border: OutlineInputBorder(), - ), - autofocus: true, - ), - const SizedBox(height: 16), - Text( - 'This will save ${settingsManager.modifiedSettings.length} modified settings.', - style: TextStyle(color: Colors.grey.shade600, fontSize: 12), - ), - ], - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: () async { - final name = _profileNameController.text.trim(); - if (name.isNotEmpty) { - await settingsManager.saveCurrentSettings(name); - if (mounted) { - Navigator.pop(context); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Profile "$name" saved')), - ); - } - } - }, - child: const Text('Save'), - ), - ], - ), - ); - } - - void _showLoadProfileDialog() { - final settingsManager = context.read(); - - if (settingsManager.profiles.isEmpty) { - ScaffoldMessenger.of( - context, - ).showSnackBar(const SnackBar(content: Text('No saved profiles found'))); - return; - } - - showDialog( - context: context, - builder: (dialogContext) => StatefulBuilder( - builder: (context, setDialogState) { - final profiles = settingsManager.profiles; - - if (profiles.isEmpty) { - // Close dialog if all profiles were deleted - WidgetsBinding.instance.addPostFrameCallback((_) { - Navigator.pop(dialogContext); - }); - return const SizedBox.shrink(); - } - - return AlertDialog( - title: const Text('Load Profile'), - content: SizedBox( - width: double.maxFinite, - child: ListView.builder( - shrinkWrap: true, - itemCount: profiles.length, - itemBuilder: (context, index) { - final profile = profiles[index]; - final isCurrentProfile = - profile.id == settingsManager.currentProfileId; - - return ListTile( - title: Text(profile.name), - subtitle: Text( - '${profile.settings.length} settings • Created ${_formatDate(profile.createdAt)}', - style: const TextStyle(fontSize: 12), - ), - leading: Icon( - isCurrentProfile ? Icons.check_circle : Icons.folder, - color: isCurrentProfile ? Colors.green : null, - ), - trailing: IconButton( - icon: const Icon(Icons.delete, color: Colors.red), - onPressed: () => _confirmDeleteProfile( - profile, - onDeleted: () => setDialogState(() {}), - ), - ), - onTap: () async { - await settingsManager.loadProfile(profile.id); - if (mounted) { - Navigator.pop(dialogContext); - ScaffoldMessenger.of(this.context).showSnackBar( - SnackBar( - content: Text('Loaded profile "${profile.name}"'), - ), - ); - } - }, - ); - }, - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(dialogContext), - child: const Text('Close'), - ), - ], - ); - }, - ), - ); - } - - void _confirmDeleteProfile( - SettingsProfile profile, { - VoidCallback? onDeleted, - }) { - showDialog( - context: context, - builder: (dialogContext) => AlertDialog( - title: const Text('Delete Profile'), - content: Text('Are you sure you want to delete "${profile.name}"?'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(dialogContext), - child: const Text('Cancel'), - ), - ElevatedButton( - style: ElevatedButton.styleFrom(backgroundColor: Colors.red), - onPressed: () async { - await context.read().deleteProfile(profile.id); - if (mounted) { - Navigator.pop(dialogContext); - onDeleted?.call(); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Deleted profile "${profile.name}"')), - ); - } - }, - child: const Text('Delete'), - ), - ], - ), - ); - } - - void _showResetConfirmDialog(SettingsManager settingsManager) { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Reset Settings'), - content: const Text( - 'Are you sure you want to reset all settings to their default values?', - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), - ), - ElevatedButton( - style: ElevatedButton.styleFrom(backgroundColor: Colors.red), - onPressed: () async { - await settingsManager.resetToDefaults(); - if (context.mounted) { - Navigator.pop(context); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Settings reset to defaults')), - ); - } - }, - child: const Text('Reset'), - ), - ], - ), - ); - } - - void _exportSettings(SettingsManager settingsManager) { - final json = settingsManager.exportSettingsAsJson(); - - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Export Settings'), - content: SizedBox( - width: double.maxFinite, - height: 300, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Text( - 'Copy the JSON below:', - style: TextStyle(fontSize: 12), - ), - const SizedBox(height: 8), - Expanded( - child: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.grey.shade100, - borderRadius: BorderRadius.circular(4), - border: Border.all(color: Colors.grey.shade300), - ), - child: SingleChildScrollView( - child: SelectableText( - json, - style: const TextStyle( - fontFamily: 'monospace', - fontSize: 12, - ), - ), - ), - ), - ), - ], - ), - ), - actions: [ - TextButton( - onPressed: () { - Clipboard.setData(ClipboardData(text: json)); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Copied to clipboard')), - ); - }, - child: const Text('Copy'), - ), - ElevatedButton( - onPressed: () => Navigator.pop(context), - child: const Text('Close'), - ), - ], - ), - ); - } - - void _showImportDialog(SettingsManager settingsManager) { - final importController = TextEditingController(); - - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Import Settings'), - content: SizedBox( - width: double.maxFinite, - height: 300, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Text( - 'Paste JSON settings:', - style: TextStyle(fontSize: 12), - ), - const SizedBox(height: 8), - Expanded( - child: TextField( - controller: importController, - maxLines: null, - expands: true, - decoration: const InputDecoration( - hintText: '{"settings": {...}}', - border: OutlineInputBorder(), - ), - style: const TextStyle(fontFamily: 'monospace', fontSize: 12), - ), - ), - ], - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: () async { - final success = await settingsManager.importSettingsFromJson( - importController.text, - ); - if (mounted) { - Navigator.pop(context); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - success - ? 'Settings imported successfully' - : 'Failed to import settings - invalid JSON', - ), - ), - ); - } - }, - child: const Text('Import'), - ), - ], - ), - ); - } - - String _formatDate(DateTime date) { - final now = DateTime.now(); - final diff = now.difference(date); - - if (diff.inDays == 0) { - return 'today'; - } else if (diff.inDays == 1) { - return 'yesterday'; - } else if (diff.inDays < 7) { - return '${diff.inDays} days ago'; - } else { - return '${date.day}/${date.month}/${date.year}'; - } - } -} diff --git a/flutter_inappwebview/example/lib/screens/storage/cookie_manager_screen.dart b/flutter_inappwebview/example/lib/screens/storage/cookie_manager_screen.dart deleted file mode 100644 index 02274022b9..0000000000 --- a/flutter_inappwebview/example/lib/screens/storage/cookie_manager_screen.dart +++ /dev/null @@ -1,1129 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/widgets/common/app_drawer.dart'; -import 'package:flutter_inappwebview_example/widgets/common/appbar_loading_indicator.dart'; -import 'package:flutter_inappwebview_example/widgets/common/empty_state.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_card.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_result_history.dart'; -import 'package:flutter_inappwebview_example/utils/responsive_utils.dart'; -import 'package:flutter_inappwebview_example/widgets/common/responsive_row.dart'; - -/// Screen for testing CookieManager functionality -class CookieManagerScreen extends StatefulWidget { - const CookieManagerScreen({super.key}); - - @override - State createState() => _CookieManagerScreenState(); -} - -class _CookieManagerScreenState extends State { - final CookieManager _cookieManager = CookieManager.instance(); - final TextEditingController _urlController = TextEditingController( - text: 'https://example.com', - ); - final TextEditingController _searchController = TextEditingController(); - - List _cookies = []; - bool _isLoading = false; - - // Sorting state - String _sortColumn = 'name'; - bool _sortAscending = true; - - // Search state - String _searchQuery = ''; - - final Map> _methodHistory = {}; - final Map _selectedHistoryIndex = {}; - static const int _maxHistoryEntries = 3; - - Future _getCookies() async { - final url = _urlController.text.trim(); - if (url.isEmpty) { - _recordMethodResult( - PlatformCookieManagerMethod.getCookies.name, - 'Please enter a URL', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final cookies = await _cookieManager.getCookies(url: WebUri(url)); - setState(() => _cookies = cookies); - _recordMethodResult( - PlatformCookieManagerMethod.getCookies.name, - 'Found ${cookies.length} cookies', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformCookieManagerMethod.getCookies.name, - 'Error getting cookies: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getAllCookies() async { - setState(() => _isLoading = true); - try { - final cookies = await _cookieManager.getAllCookies(); - setState(() => _cookies = cookies); - _recordMethodResult( - PlatformCookieManagerMethod.getAllCookies.name, - 'Found ${cookies.length} cookies', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformCookieManagerMethod.getAllCookies.name, - 'Error getting all cookies: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getCookie({required String url, required String name}) async { - setState(() => _isLoading = true); - try { - final cookie = await _cookieManager.getCookie( - url: WebUri(url), - name: name, - ); - if (cookie != null) { - _showCookieDetailsDialog(cookie); - _recordMethodResult( - PlatformCookieManagerMethod.getCookie.name, - 'Cookie found for "$name"', - isError: false, - ); - } else { - _recordMethodResult( - PlatformCookieManagerMethod.getCookie.name, - 'Cookie not found', - isError: true, - ); - } - } catch (e) { - _recordMethodResult( - PlatformCookieManagerMethod.getCookie.name, - 'Error getting cookie: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _setCookie() async { - final params = await showParameterDialog( - context: context, - title: PlatformCookieManagerMethod.setCookie.name, - parameters: { - 'url': _urlController.text.trim(), - 'name': '', - 'value': '', - 'path': '/', - 'domain': '', - 'expiresDate': const ParameterValueHint( - null, - ParameterValueType.date, - ), - 'maxAge': 3600, - 'isSecure': false, - 'isHttpOnly': false, - 'sameSite': '', - }, - requiredPaths: ['url', 'name', 'value'], - ); - - if (params == null) return; - - final url = params['url']?.toString() ?? ''; - if (url.isEmpty) { - _recordMethodResult( - PlatformCookieManagerMethod.setCookie.name, - 'Please enter a URL', - isError: true, - ); - return; - } - - final sameSiteValue = params['sameSite']?.toString(); - HTTPCookieSameSitePolicy? sameSite; - if (sameSiteValue != null && sameSiteValue.trim().isNotEmpty) { - sameSite = HTTPCookieSameSitePolicy.values.firstWhere( - (policy) => policy.name().toLowerCase() == sameSiteValue.toLowerCase(), - orElse: () => HTTPCookieSameSitePolicy.LAX, - ); - } - - setState(() => _isLoading = true); - try { - final path = params['path']?.toString(); - final result = await _cookieManager.setCookie( - url: WebUri(url), - name: params['name']?.toString() ?? '', - value: params['value']?.toString() ?? '', - path: path?.isNotEmpty == true ? path! : '/', - domain: params['domain']?.toString().isNotEmpty == true - ? params['domain']?.toString() - : null, - expiresDate: - (params['expiresDate'] as DateTime?)?.millisecondsSinceEpoch, - maxAge: (params['maxAge'] as num?)?.toInt(), - isSecure: params['isSecure'] as bool? ?? false, - isHttpOnly: params['isHttpOnly'] as bool? ?? false, - sameSite: sameSite, - ); - if (result) { - _recordMethodResult( - PlatformCookieManagerMethod.setCookie.name, - 'Cookie set successfully', - isError: false, - ); - await _getCookies(); - } else { - _recordMethodResult( - PlatformCookieManagerMethod.setCookie.name, - 'Failed to set cookie', - isError: true, - ); - } - } catch (e) { - _recordMethodResult( - PlatformCookieManagerMethod.setCookie.name, - 'Error setting cookie: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _deleteCookie(Cookie cookie, {String? urlOverride}) async { - final url = urlOverride ?? _urlController.text.trim(); - if (url.isEmpty) { - _recordMethodResult( - PlatformCookieManagerMethod.deleteCookie.name, - 'Please enter a URL', - isError: true, - ); - return; - } - setState(() => _isLoading = true); - try { - final result = await _cookieManager.deleteCookie( - url: WebUri(url), - name: cookie.name, - path: cookie.path ?? '/', - domain: cookie.domain, - ); - if (result) { - _recordMethodResult( - PlatformCookieManagerMethod.deleteCookie.name, - 'Cookie "${cookie.name}" deleted', - isError: false, - ); - // Remove the cookie from local list - setState(() { - _cookies.removeWhere( - (c) => - c.name == cookie.name && - c.domain == cookie.domain && - c.path == cookie.path, - ); - }); - } else { - _recordMethodResult( - PlatformCookieManagerMethod.deleteCookie.name, - 'Failed to delete cookie', - isError: true, - ); - } - } catch (e) { - _recordMethodResult( - PlatformCookieManagerMethod.deleteCookie.name, - 'Error deleting cookie: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _confirmAndDeleteCookie(Cookie cookie) async { - final confirmed = - await showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text(PlatformCookieManagerMethod.deleteCookie.name), - content: Text( - 'Are you sure you want to delete the cookie "${cookie.name}"?', - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context, false), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: () => Navigator.pop(context, true), - style: ElevatedButton.styleFrom(backgroundColor: Colors.red), - child: const Text('Delete'), - ), - ], - ), - ) ?? - false; - - if (!confirmed) return; - - // Determine URL to use for deletion - // If we have a URL in the field, use that. Otherwise, try to construct one from the domain - String url = _urlController.text.trim(); - if (url.isEmpty && cookie.domain != null) { - // Construct a URL from the cookie domain - final domain = cookie.domain!.startsWith('.') - ? cookie.domain!.substring(1) - : cookie.domain!; - url = 'https://$domain${cookie.path ?? '/'}'; - } - - if (url.isEmpty) { - _recordMethodResult( - PlatformCookieManagerMethod.deleteCookie.name, - 'Cannot delete cookie: No URL provided and cookie has no domain', - isError: true, - ); - return; - } - - await _deleteCookie(cookie, urlOverride: url); - } - - Future _deleteCookieByParams({ - required String url, - required String name, - String? path, - String? domain, - }) async { - setState(() => _isLoading = true); - try { - final result = await _cookieManager.deleteCookie( - url: WebUri(url), - name: name, - path: path ?? '/', - domain: domain, - ); - if (result) { - _recordMethodResult( - PlatformCookieManagerMethod.deleteCookie.name, - 'Cookie deleted', - isError: false, - ); - await _getCookies(); - } else { - _recordMethodResult( - PlatformCookieManagerMethod.deleteCookie.name, - 'Failed to delete cookie', - isError: true, - ); - } - } catch (e) { - _recordMethodResult( - PlatformCookieManagerMethod.deleteCookie.name, - 'Error deleting cookie: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _promptGetCookie() async { - final params = await showParameterDialog( - context: context, - title: PlatformCookieManagerMethod.getCookie.name, - parameters: {'url': _urlController.text.trim(), 'name': ''}, - requiredPaths: ['url', 'name'], - ); - - if (params == null) return; - final url = params['url']?.toString() ?? ''; - final name = params['name']?.toString() ?? ''; - if (url.isEmpty || name.isEmpty) { - _recordMethodResult( - PlatformCookieManagerMethod.getCookie.name, - 'URL and name are required', - isError: true, - ); - return; - } - _urlController.text = url; - await _getCookie(url: url, name: name); - } - - Future _promptDeleteCookie() async { - final params = await showParameterDialog( - context: context, - title: PlatformCookieManagerMethod.deleteCookie.name, - parameters: { - 'url': _urlController.text.trim(), - 'name': '', - 'path': '/', - 'domain': '', - }, - requiredPaths: ['url', 'name'], - ); - - if (params == null) return; - final url = params['url']?.toString() ?? ''; - final name = params['name']?.toString() ?? ''; - if (url.isEmpty || name.isEmpty) { - _recordMethodResult( - PlatformCookieManagerMethod.deleteCookie.name, - 'URL and name are required', - isError: true, - ); - return; - } - _urlController.text = url; - await _deleteCookieByParams( - url: url, - name: name, - path: params['path']?.toString().isNotEmpty == true - ? params['path']?.toString() - : '/', - domain: params['domain']?.toString().isNotEmpty == true - ? params['domain']?.toString() - : null, - ); - } - - Future _deleteCookies() async { - final url = _urlController.text.trim(); - if (url.isEmpty) { - _recordMethodResult( - PlatformCookieManagerMethod.deleteCookies.name, - 'Please enter a URL', - isError: true, - ); - return; - } - - final confirmed = await _showConfirmDialog( - PlatformCookieManagerMethod.deleteCookies.name, - 'Are you sure you want to delete all cookies for this URL?', - ); - if (!confirmed) return; - - setState(() => _isLoading = true); - try { - final result = await _cookieManager.deleteCookies(url: WebUri(url)); - if (result) { - _recordMethodResult( - PlatformCookieManagerMethod.deleteCookies.name, - 'Cookies deleted for URL', - isError: false, - ); - setState(() => _cookies = []); - } else { - _recordMethodResult( - PlatformCookieManagerMethod.deleteCookies.name, - 'Failed to delete cookies', - isError: true, - ); - } - } catch (e) { - _recordMethodResult( - PlatformCookieManagerMethod.deleteCookies.name, - 'Error deleting cookies: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _deleteAllCookies() async { - final confirmed = await _showConfirmDialog( - PlatformCookieManagerMethod.deleteAllCookies.name, - 'Are you sure you want to delete ALL cookies?', - ); - if (!confirmed) return; - - setState(() => _isLoading = true); - try { - final result = await _cookieManager.deleteAllCookies(); - if (result) { - _recordMethodResult( - PlatformCookieManagerMethod.deleteAllCookies.name, - 'All cookies deleted', - isError: false, - ); - setState(() => _cookies = []); - } else { - _recordMethodResult( - PlatformCookieManagerMethod.deleteAllCookies.name, - 'Failed to delete all cookies', - isError: true, - ); - } - } catch (e) { - _recordMethodResult( - PlatformCookieManagerMethod.deleteAllCookies.name, - 'Error deleting all cookies: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _removeSessionCookies() async { - setState(() => _isLoading = true); - try { - final result = await _cookieManager.removeSessionCookies(); - _recordMethodResult( - PlatformCookieManagerMethod.removeSessionCookies.name, - result ? 'Session cookies removed' : 'No session cookies to remove', - isError: !result, - ); - } catch (e) { - _recordMethodResult( - PlatformCookieManagerMethod.removeSessionCookies.name, - 'Error removing session cookies: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _flush() async { - setState(() => _isLoading = true); - try { - await _cookieManager.flush(); - _recordMethodResult( - PlatformCookieManagerMethod.flush.name, - 'Cookies flushed to persistent storage', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformCookieManagerMethod.flush.name, - 'Error flushing cookies: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - void _recordMethodResult( - String methodName, - String message, { - required bool isError, - dynamic value, - }) { - setState(() { - final entries = List.from( - _methodHistory[methodName] ?? const [], - ); - entries.insert( - 0, - MethodResultEntry( - message: message, - isError: isError, - timestamp: DateTime.now(), - value: value, - ), - ); - if (entries.length > _maxHistoryEntries) { - entries.removeRange(_maxHistoryEntries, entries.length); - } - _methodHistory[methodName] = entries; - _selectedHistoryIndex[methodName] = 0; - }); - } - - Future _showConfirmDialog(String title, String content) async { - return await showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text(title), - content: Text(content), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context, false), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: () => Navigator.pop(context, true), - style: ElevatedButton.styleFrom(backgroundColor: Colors.red), - child: const Text('Delete'), - ), - ], - ), - ) ?? - false; - } - - void _showCookieDetailsDialog(Cookie cookie) { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text(cookie.name), - content: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - _buildDetailRow('Value', cookie.value?.toString() ?? 'null'), - _buildDetailRow('Domain', cookie.domain ?? 'null'), - _buildDetailRow('Path', cookie.path ?? 'null'), - _buildDetailRow( - 'Expires', - cookie.expiresDate != null - ? DateTime.fromMillisecondsSinceEpoch( - cookie.expiresDate!, - ).toString() - : 'null', - ), - _buildDetailRow('Secure', cookie.isSecure?.toString() ?? 'null'), - _buildDetailRow( - 'HttpOnly', - cookie.isHttpOnly?.toString() ?? 'null', - ), - _buildDetailRow( - 'Session Only', - cookie.isSessionOnly?.toString() ?? 'null', - ), - _buildDetailRow( - 'SameSite', - cookie.sameSite?.toString() ?? 'null', - ), - ], - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Close'), - ), - ], - ), - ); - } - - Widget _buildDetailRow(String label, String value) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: 100, - child: Text( - '$label:', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ), - Expanded(child: Text(value)), - ], - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Cookie Manager'), - actions: [AppBarLoadingIndicator(isLoading: _isLoading)], - ), - drawer: AppDrawer(), - body: Column( - children: [ - _buildUrlInput(), - Expanded( - child: ListView( - padding: const EdgeInsets.all(16), - children: [ - _buildMethodSection( - PlatformCookieManagerMethod.setCookie, - 'Set a cookie for the given URL', - _setCookie, - ), - _buildMethodSection( - PlatformCookieManagerMethod.getCookies, - 'Get all cookies for the given URL', - _getCookies, - ), - _buildMethodSection( - PlatformCookieManagerMethod.getCookie, - 'Get a specific cookie by name (requires cookie list)', - _promptGetCookie, - ), - _buildMethodSection( - PlatformCookieManagerMethod.deleteCookie, - 'Delete a specific cookie (select from list)', - _promptDeleteCookie, - ), - _buildMethodSection( - PlatformCookieManagerMethod.deleteCookies, - 'Delete all cookies for the URL', - _deleteCookies, - ), - _buildMethodSection( - PlatformCookieManagerMethod.deleteAllCookies, - 'Delete all cookies', - _deleteAllCookies, - ), - _buildMethodSection( - PlatformCookieManagerMethod.getAllCookies, - 'Get all cookies', - _getAllCookies, - ), - _buildMethodSection( - PlatformCookieManagerMethod.removeSessionCookies, - 'Remove session cookies', - _removeSessionCookies, - ), - _buildMethodSection( - PlatformCookieManagerMethod.flush, - 'Flush cookies to persistent storage', - _flush, - ), - const SizedBox(height: 16), - _buildCookiesList(), - ], - ), - ), - ], - ), - ); - } - - Widget _buildUrlInput() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.blue.shade50, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: LayoutBuilder( - builder: (context, constraints) { - final isMobile = ResponsiveBreakpoints.isMobileWidth( - constraints.maxWidth, - ); - final urlField = TextField( - controller: _urlController, - decoration: const InputDecoration( - labelText: 'URL', - hintText: 'https://example.com', - border: OutlineInputBorder(), - isDense: true, - ), - ); - return ResponsiveRow( - rowKey: const Key('cookie_manager_url_row'), - columnKey: const Key('cookie_manager_url_column'), - spacing: 8, - runSpacing: 8, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isMobile ? urlField : Expanded(child: urlField), - SizedBox( - width: isMobile ? double.infinity : null, - child: ElevatedButton( - onPressed: _isLoading ? null : _getCookies, - child: Text(PlatformCookieManagerMethod.getCookies.name), - ), - ), - ], - ); - }, - ), - ); - } - - Widget _buildMethodSection( - PlatformCookieManagerMethod method, - String description, - VoidCallback? onPressed, - ) { - final methodName = method.name; - final supportedPlatforms = SupportCheckHelper.supportedPlatformsForMethod( - method: method, - checker: CookieManager.isMethodSupported, - ); - - return MethodTile( - methodName: methodName, - description: description, - supportedPlatforms: supportedPlatforms, - onRun: !_isLoading ? onPressed : null, - historyEntries: _methodHistory[methodName], - selectedHistoryIndex: _selectedHistoryIndex[methodName], - onHistorySelected: (index) { - setState(() => _selectedHistoryIndex[methodName] = index); - }, - ); - } - - Widget _buildCookiesList() { - if (_cookies.isEmpty) { - return EmptyStateCard( - icon: Icons.cookie_outlined, - title: 'No cookies found', - description: - 'Enter a URL and click "${PlatformCookieManagerMethod.getCookies.name}" to fetch cookies', - ); - } - - final filteredCookies = _filteredAndSortedCookies; - - return Card( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Text( - 'Cookies (${filteredCookies.length}${filteredCookies.length != _cookies.length ? ' of ${_cookies.length}' : ''})', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - const Spacer(), - IconButton( - icon: const Icon(Icons.refresh), - onPressed: _isLoading ? null : _getCookies, - tooltip: 'Refresh', - ), - ], - ), - const SizedBox(height: 12), - // Search field - TextField( - controller: _searchController, - decoration: InputDecoration( - hintText: 'Search cookies...', - prefixIcon: const Icon(Icons.search, size: 20), - suffixIcon: _searchQuery.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear, size: 20), - onPressed: () { - setState(() { - _searchController.clear(); - _searchQuery = ''; - }); - }, - ) - : null, - border: const OutlineInputBorder(), - isDense: true, - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 10, - ), - ), - onChanged: (value) { - setState(() => _searchQuery = value); - }, - ), - ], - ), - ), - const Divider(height: 1), - if (filteredCookies.isEmpty) - Padding( - padding: const EdgeInsets.all(32), - child: Center( - child: Text( - 'No cookies match your search', - style: TextStyle(color: Colors.grey.shade600), - ), - ), - ) - else - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: DataTable( - sortColumnIndex: _getSortColumnIndex(), - sortAscending: _sortAscending, - headingRowHeight: 48, - dataRowMinHeight: 40, - dataRowMaxHeight: 56, - columnSpacing: 16, - horizontalMargin: 16, - columns: [ - DataColumn( - label: const Text( - 'Name', - style: TextStyle(fontWeight: FontWeight.bold), - ), - onSort: (_, __) => _onSort('name'), - ), - DataColumn( - label: const Text( - 'Value', - style: TextStyle(fontWeight: FontWeight.bold), - ), - onSort: (_, __) => _onSort('value'), - ), - DataColumn( - label: const Text( - 'Domain', - style: TextStyle(fontWeight: FontWeight.bold), - ), - onSort: (_, __) => _onSort('domain'), - ), - DataColumn( - label: const Text( - 'Path', - style: TextStyle(fontWeight: FontWeight.bold), - ), - onSort: (_, __) => _onSort('path'), - ), - DataColumn( - label: const Text( - 'Expires', - style: TextStyle(fontWeight: FontWeight.bold), - ), - onSort: (_, __) => _onSort('expires'), - ), - DataColumn( - label: const Text( - 'Secure', - style: TextStyle(fontWeight: FontWeight.bold), - ), - onSort: (_, __) => _onSort('secure'), - ), - const DataColumn( - label: Text( - 'Actions', - style: TextStyle(fontWeight: FontWeight.bold), - ), - ), - ], - rows: filteredCookies - .map( - (cookie) => DataRow( - cells: [ - DataCell( - SizedBox( - width: 120, - child: Text( - cookie.name, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontWeight: FontWeight.w500, - ), - ), - ), - ), - DataCell( - SizedBox( - width: 150, - child: Text( - cookie.value?.toString() ?? 'null', - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 12, - color: cookie.value != null - ? Colors.black87 - : Colors.grey, - ), - ), - ), - ), - DataCell( - SizedBox( - width: 100, - child: Text( - cookie.domain ?? '-', - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontSize: 12), - ), - ), - ), - DataCell( - SizedBox( - width: 60, - child: Text( - cookie.path ?? '/', - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontSize: 12), - ), - ), - ), - DataCell( - SizedBox( - width: 140, - child: Text( - cookie.expiresDate != null - ? DateTime.fromMillisecondsSinceEpoch( - cookie.expiresDate!, - ).toLocal().toString().split('.')[0] - : 'Session', - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontSize: 11), - ), - ), - ), - DataCell( - Icon( - cookie.isSecure == true - ? Icons.lock - : Icons.lock_open, - size: 18, - color: cookie.isSecure == true - ? Colors.green - : Colors.grey, - ), - ), - DataCell( - Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon( - Icons.visibility_outlined, - size: 18, - ), - onPressed: () => - _showCookieDetailsDialog(cookie), - tooltip: 'View Details', - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - ), - const SizedBox(width: 8), - IconButton( - icon: const Icon( - Icons.delete_outline, - size: 18, - color: Colors.red, - ), - onPressed: () => - _confirmAndDeleteCookie(cookie), - tooltip: 'Delete', - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - ), - ], - ), - ), - ], - ), - ) - .toList(), - ), - ), - ], - ), - ); - } - - int? _getSortColumnIndex() { - switch (_sortColumn) { - case 'name': - return 0; - case 'value': - return 1; - case 'domain': - return 2; - case 'path': - return 3; - case 'expires': - return 4; - case 'secure': - return 5; - default: - return null; - } - } - - /// Get filtered and sorted cookies - List get _filteredAndSortedCookies { - var result = List.from(_cookies); - - // Apply search filter - if (_searchQuery.isNotEmpty) { - final query = _searchQuery.toLowerCase(); - result = result.where((cookie) { - return cookie.name.toLowerCase().contains(query) || - (cookie.value?.toString().toLowerCase().contains(query) ?? false) || - (cookie.domain?.toLowerCase().contains(query) ?? false) || - (cookie.path?.toLowerCase().contains(query) ?? false); - }).toList(); - } - - // Apply sorting - result.sort((a, b) { - int comparison; - switch (_sortColumn) { - case 'name': - comparison = a.name.compareTo(b.name); - break; - case 'value': - comparison = (a.value?.toString() ?? '').compareTo( - b.value?.toString() ?? '', - ); - break; - case 'domain': - comparison = (a.domain ?? '').compareTo(b.domain ?? ''); - break; - case 'path': - comparison = (a.path ?? '').compareTo(b.path ?? ''); - break; - case 'expires': - comparison = (a.expiresDate ?? 0).compareTo(b.expiresDate ?? 0); - break; - case 'secure': - comparison = (a.isSecure == true ? 1 : 0).compareTo( - b.isSecure == true ? 1 : 0, - ); - break; - default: - comparison = 0; - } - return _sortAscending ? comparison : -comparison; - }); - - return result; - } - - void _onSort(String column) { - setState(() { - if (_sortColumn == column) { - _sortAscending = !_sortAscending; - } else { - _sortColumn = column; - _sortAscending = true; - } - }); - } - - @override - void dispose() { - _urlController.dispose(); - _searchController.dispose(); - super.dispose(); - } -} diff --git a/flutter_inappwebview/example/lib/screens/storage/http_auth_screen.dart b/flutter_inappwebview/example/lib/screens/storage/http_auth_screen.dart deleted file mode 100644 index 8beaca95cf..0000000000 --- a/flutter_inappwebview/example/lib/screens/storage/http_auth_screen.dart +++ /dev/null @@ -1,662 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/widgets/common/app_drawer.dart'; -import 'package:flutter_inappwebview_example/widgets/common/appbar_loading_indicator.dart'; -import 'package:flutter_inappwebview_example/widgets/common/empty_state.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_card.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_result_history.dart'; - -/// Screen for testing HttpAuthCredentialDatabase functionality -class HttpAuthScreen extends StatefulWidget { - const HttpAuthScreen({super.key}); - - @override - State createState() => _HttpAuthScreenState(); -} - -class _HttpAuthScreenState extends State { - final HttpAuthCredentialDatabase _db = HttpAuthCredentialDatabase.instance(); - List _allCredentials = []; - bool _isLoading = false; - - final Map> _methodHistory = {}; - final Map _selectedHistoryIndex = {}; - static const int _maxHistoryEntries = 3; - - @override - void initState() { - super.initState(); - _getAllAuthCredentials(); - } - - Future _getAllAuthCredentials() async { - setState(() => _isLoading = true); - try { - final credentials = await _db.getAllAuthCredentials(); - setState(() => _allCredentials = credentials); - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.getAllAuthCredentials.name, - 'Found ${credentials.length} protection spaces', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.getAllAuthCredentials.name, - 'Error getting credentials: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getHttpAuthCredentials( - URLProtectionSpace protectionSpace, - ) async { - setState(() => _isLoading = true); - try { - final credentials = await _db.getHttpAuthCredentials( - protectionSpace: protectionSpace, - ); - _showCredentialsDialog(protectionSpace, credentials); - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.getHttpAuthCredentials.name, - 'Found ${credentials.length} credential(s)', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.getHttpAuthCredentials.name, - 'Error getting credentials: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _setHttpAuthCredential() async { - final params = await showParameterDialog( - context: context, - title: 'Add Credential', - parameters: { - 'protectionSpace': { - 'host': '', - 'protocol': 'https', - 'port': 443, - 'realm': '', - }, - 'credential': {'username': '', 'password': ''}, - }, - requiredPaths: [ - 'protectionSpace.host', - 'credential.username', - 'credential.password', - ], - ); - - if (params == null) return; - await _applyCredentialFromParams(params); - } - - Future _removeHttpAuthCredential( - URLProtectionSpace protectionSpace, - URLCredential credential, - ) async { - final confirmed = await _showConfirmDialog( - 'Remove Credential', - 'Are you sure you want to remove the credential for "${credential.username}"?', - ); - if (!confirmed) return; - - setState(() => _isLoading = true); - try { - await _db.removeHttpAuthCredential( - protectionSpace: protectionSpace, - credential: credential, - ); - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.removeHttpAuthCredential.name, - 'Credential removed', - isError: false, - ); - await _getAllAuthCredentials(); - } catch (e) { - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.removeHttpAuthCredential.name, - 'Error removing credential: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _promptGetHttpAuthCredentials() async { - final params = await showParameterDialog( - context: context, - title: 'Get Credentials', - parameters: { - 'protectionSpace': { - 'host': '', - 'protocol': 'https', - 'port': 443, - 'realm': '', - }, - }, - requiredPaths: ['protectionSpace.host'], - ); - - if (params == null) return; - final space = _protectionSpaceFromParams(params['protectionSpace']); - if (space == null) { - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.getHttpAuthCredentials.name, - 'Protection space host is required', - isError: true, - ); - return; - } - await _getHttpAuthCredentials(space); - } - - Future _promptRemoveHttpAuthCredential() async { - final params = await showParameterDialog( - context: context, - title: 'Remove Credential', - parameters: { - 'protectionSpace': { - 'host': '', - 'protocol': 'https', - 'port': 443, - 'realm': '', - }, - 'credential': {'username': '', 'password': ''}, - }, - requiredPaths: [ - 'protectionSpace.host', - 'credential.username', - 'credential.password', - ], - ); - - if (params == null) return; - final space = _protectionSpaceFromParams(params['protectionSpace']); - if (space == null) { - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.removeHttpAuthCredential.name, - 'Protection space host is required', - isError: true, - ); - return; - } - final credential = _credentialFromParams(params['credential']); - if (credential == null) { - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.removeHttpAuthCredential.name, - 'Credential username and password are required', - isError: true, - ); - return; - } - await _removeHttpAuthCredential(space, credential); - } - - Future _promptRemoveHttpAuthCredentials() async { - final params = await showParameterDialog( - context: context, - title: 'Remove Credentials', - parameters: { - 'protectionSpace': { - 'host': '', - 'protocol': 'https', - 'port': 443, - 'realm': '', - }, - }, - requiredPaths: ['protectionSpace.host'], - ); - - if (params == null) return; - final space = _protectionSpaceFromParams(params['protectionSpace']); - if (space == null) { - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.removeHttpAuthCredentials.name, - 'Protection space host is required', - isError: true, - ); - return; - } - await _removeHttpAuthCredentials(space); - } - - Future _removeHttpAuthCredentials( - URLProtectionSpace protectionSpace, - ) async { - final confirmed = await _showConfirmDialog( - 'Remove All Credentials for Protection Space', - 'Are you sure you want to remove all credentials for ${protectionSpace.host}?', - ); - if (!confirmed) return; - - setState(() => _isLoading = true); - try { - await _db.removeHttpAuthCredentials(protectionSpace: protectionSpace); - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.removeHttpAuthCredentials.name, - 'Credentials removed for protection space', - isError: false, - ); - await _getAllAuthCredentials(); - } catch (e) { - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.removeHttpAuthCredentials.name, - 'Error removing credentials: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _clearAllAuthCredentials() async { - final confirmed = await _showConfirmDialog( - 'Clear All Credentials', - 'Are you sure you want to clear ALL HTTP auth credentials?', - ); - if (!confirmed) return; - - setState(() => _isLoading = true); - try { - await _db.clearAllAuthCredentials(); - setState(() => _allCredentials = []); - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.clearAllAuthCredentials.name, - 'All credentials cleared', - isError: false, - ); - } catch (e) { - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.clearAllAuthCredentials.name, - 'Error clearing credentials: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - void _recordMethodResult( - String methodName, - String message, { - required bool isError, - dynamic value, - }) { - setState(() { - final entries = List.from( - _methodHistory[methodName] ?? const [], - ); - entries.insert( - 0, - MethodResultEntry( - message: message, - isError: isError, - timestamp: DateTime.now(), - value: value, - ), - ); - if (entries.length > _maxHistoryEntries) { - entries.removeRange(_maxHistoryEntries, entries.length); - } - _methodHistory[methodName] = entries; - _selectedHistoryIndex[methodName] = 0; - }); - } - - URLProtectionSpace? _protectionSpaceFromParams(dynamic raw) { - if (raw is! Map) return null; - final host = raw['host']?.toString() ?? ''; - if (host.isEmpty) return null; - final protocol = raw['protocol']?.toString(); - final realm = raw['realm']?.toString(); - final port = (raw['port'] as num?)?.toInt(); - return URLProtectionSpace( - host: host, - protocol: protocol?.isNotEmpty == true ? protocol : null, - port: port, - realm: realm?.isNotEmpty == true ? realm : null, - ); - } - - URLCredential? _credentialFromParams(dynamic raw) { - if (raw is! Map) return null; - final username = raw['username']?.toString() ?? ''; - final password = raw['password']?.toString() ?? ''; - if (username.isEmpty || password.isEmpty) return null; - return URLCredential(username: username, password: password); - } - - Future _applyCredentialFromParams(Map params) async { - final space = _protectionSpaceFromParams(params['protectionSpace']); - final credential = _credentialFromParams(params['credential']); - if (space == null || credential == null) { - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.setHttpAuthCredential.name, - 'Protection space, username, and password are required', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - await _db.setHttpAuthCredential( - protectionSpace: space, - credential: credential, - ); - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.setHttpAuthCredential.name, - 'Credential saved', - isError: false, - ); - await _getAllAuthCredentials(); - } catch (e) { - _recordMethodResult( - PlatformHttpAuthCredentialDatabaseMethod.setHttpAuthCredential.name, - 'Error saving credential: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _showConfirmDialog(String title, String content) async { - return await showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text(title), - content: Text(content), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context, false), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: () => Navigator.pop(context, true), - style: ElevatedButton.styleFrom(backgroundColor: Colors.red), - child: const Text('Delete'), - ), - ], - ), - ) ?? - false; - } - - void _showCredentialsDialog( - URLProtectionSpace protectionSpace, - List credentials, - ) { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Credentials for ${protectionSpace.host}'), - content: SizedBox( - width: double.maxFinite, - child: credentials.isEmpty - ? const Padding( - padding: EdgeInsets.all(16), - child: Text('No credentials found'), - ) - : ListView.builder( - shrinkWrap: true, - itemCount: credentials.length, - itemBuilder: (context, index) { - final cred = credentials[index]; - return ListTile( - title: Text(cred.username ?? 'null'), - subtitle: Text( - 'Password: ${'*' * (cred.password?.length ?? 0)}', - ), - trailing: IconButton( - icon: const Icon(Icons.delete_outline), - color: Colors.red, - onPressed: () { - Navigator.pop(context); - _removeHttpAuthCredential(protectionSpace, cred); - }, - ), - ); - }, - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Close'), - ), - ], - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('HTTP Auth Credentials'), - actions: [AppBarLoadingIndicator(isLoading: _isLoading)], - ), - drawer: AppDrawer(), - body: ListView( - padding: const EdgeInsets.all(16), - children: [ - _buildMethodSection( - PlatformHttpAuthCredentialDatabaseMethod.getAllAuthCredentials, - 'Get all saved credentials', - _getAllAuthCredentials, - ), - _buildMethodSection( - PlatformHttpAuthCredentialDatabaseMethod.getHttpAuthCredentials, - 'Get credentials for a protection space (select from list)', - _promptGetHttpAuthCredentials, - ), - _buildMethodSection( - PlatformHttpAuthCredentialDatabaseMethod.setHttpAuthCredential, - 'Save a new credential', - _setHttpAuthCredential, - ), - _buildMethodSection( - PlatformHttpAuthCredentialDatabaseMethod.removeHttpAuthCredential, - 'Remove a specific credential (select from list)', - _promptRemoveHttpAuthCredential, - ), - _buildMethodSection( - PlatformHttpAuthCredentialDatabaseMethod.removeHttpAuthCredentials, - 'Remove all credentials for a protection space', - _promptRemoveHttpAuthCredentials, - ), - _buildMethodSection( - PlatformHttpAuthCredentialDatabaseMethod.clearAllAuthCredentials, - 'Clear all credentials', - _clearAllAuthCredentials, - ), - const SizedBox(height: 16), - _buildCredentialsList(), - ], - ), - ); - } - - Widget _buildMethodSection( - PlatformHttpAuthCredentialDatabaseMethod method, - String description, - VoidCallback? onPressed, - ) { - final methodName = method.name; - final supportedPlatforms = SupportCheckHelper.supportedPlatformsForMethod( - method: method, - checker: HttpAuthCredentialDatabase.isMethodSupported, - ); - - return MethodTile( - methodName: methodName, - description: description, - supportedPlatforms: supportedPlatforms, - onRun: !_isLoading ? onPressed : null, - historyEntries: _methodHistory[methodName], - selectedHistoryIndex: _selectedHistoryIndex[methodName], - onHistorySelected: (index) { - setState(() => _selectedHistoryIndex[methodName] = index); - }, - ); - } - - Widget _buildCredentialsList() { - if (_allCredentials.isEmpty) { - return EmptyStateCard( - icon: Icons.lock_outline, - title: 'No credentials found', - description: - 'Click "${PlatformHttpAuthCredentialDatabaseMethod.setHttpAuthCredential.name}" to add HTTP auth credentials', - ); - } - - return Card( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Row( - children: [ - Text( - 'Protection Spaces (${_allCredentials.length})', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - const Spacer(), - IconButton( - icon: const Icon(Icons.refresh), - onPressed: _isLoading ? null : _getAllAuthCredentials, - tooltip: 'Refresh', - ), - ], - ), - ), - const Divider(height: 1), - ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: _allCredentials.length, - separatorBuilder: (_, __) => const Divider(height: 1), - itemBuilder: (context, index) { - final item = _allCredentials[index]; - final protectionSpace = item.protectionSpace; - final credentials = item.credentials ?? []; - - return ExpansionTile( - title: Text( - protectionSpace?.host ?? 'Unknown Host', - style: const TextStyle(fontWeight: FontWeight.w500), - ), - subtitle: Text( - _buildProtectionSpaceDescription(protectionSpace), - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), - decoration: BoxDecoration( - color: Colors.blue.shade100, - borderRadius: BorderRadius.circular(12), - ), - child: Text( - '${credentials.length}', - style: TextStyle( - fontSize: 12, - color: Colors.blue.shade800, - fontWeight: FontWeight.bold, - ), - ), - ), - IconButton( - icon: const Icon(Icons.visibility, size: 20), - onPressed: protectionSpace != null - ? () => _getHttpAuthCredentials(protectionSpace) - : null, - tooltip: 'View Credentials', - ), - IconButton( - icon: const Icon(Icons.delete_outline, size: 20), - onPressed: protectionSpace != null - ? () => _removeHttpAuthCredentials(protectionSpace) - : null, - tooltip: 'Remove All for Protection Space', - color: Colors.red, - ), - ], - ), - children: [ - if (credentials.isEmpty) - Padding( - padding: const EdgeInsets.all(16), - child: Text( - 'No credentials for this protection space', - style: TextStyle( - color: Colors.grey.shade600, - fontStyle: FontStyle.italic, - ), - ), - ) - else - ...credentials.map((credential) { - return ListTile( - leading: const Icon(Icons.person_outline), - title: Text(credential.username ?? 'Unknown'), - subtitle: Text( - 'Password: ${'*' * (credential.password?.length ?? 0)}', - style: const TextStyle(fontSize: 12), - ), - trailing: IconButton( - icon: const Icon(Icons.delete_outline, size: 20), - color: Colors.red, - onPressed: protectionSpace != null - ? () => _removeHttpAuthCredential( - protectionSpace, - credential, - ) - : null, - tooltip: 'Remove Credential', - ), - ); - }), - ], - ); - }, - ), - ], - ), - ); - } - - String _buildProtectionSpaceDescription(URLProtectionSpace? space) { - if (space == null) return 'Unknown'; - - final parts = []; - if (space.protocol != null) parts.add(space.protocol!); - if (space.port != null) parts.add('Port: ${space.port}'); - if (space.realm != null) parts.add('Realm: ${space.realm}'); - - return parts.isEmpty ? 'No additional details' : parts.join(' • '); - } -} diff --git a/flutter_inappwebview/example/lib/screens/storage/web_storage_screen.dart b/flutter_inappwebview/example/lib/screens/storage/web_storage_screen.dart deleted file mode 100644 index a0e7559a87..0000000000 --- a/flutter_inappwebview/example/lib/screens/storage/web_storage_screen.dart +++ /dev/null @@ -1,1402 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/widgets/common/app_drawer.dart'; -import 'package:flutter_inappwebview_example/widgets/common/appbar_loading_indicator.dart'; -import 'package:flutter_inappwebview_example/widgets/common/empty_state.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_card.dart'; -import 'package:flutter_inappwebview_example/widgets/common/resize_handle.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_result_history.dart'; - -/// Screen for testing WebStorage (localStorage and sessionStorage) functionality -class WebStorageScreen extends StatefulWidget { - const WebStorageScreen({super.key}); - - @override - State createState() => _WebStorageScreenState(); -} - -class _WebStorageScreenState extends State - with SingleTickerProviderStateMixin { - late TabController _tabController; - InAppWebViewController? _webViewController; - bool _isLoading = false; - bool _webViewReady = false; - double _webViewHeight = 140; - static const double _minWebViewHeight = 100; - static const double _minContentHeight = 260; - static const double _dividerHeight = 6; - - // LocalStorage state - List _localStorageItems = []; - int? _localStorageLength; - - // SessionStorage state - List _sessionStorageItems = []; - int? _sessionStorageLength; - - // WebStorageManager state - final WebStorageManager _webStorageManager = WebStorageManager.instance(); - List _webStorageOrigins = []; - List _dataRecords = []; - - final TextEditingController _urlController = TextEditingController( - text: 'https://example.com', - ); - - final Map> _methodHistory = {}; - final Map _selectedHistoryIndex = {}; - static const int _maxHistoryEntries = 3; - - @override - void initState() { - super.initState(); - _tabController = TabController(length: 3, vsync: this); - _tabController.addListener(() { - if (!_tabController.indexIsChanging) { - setState(() {}); - } - }); - } - - @override - void dispose() { - _tabController.dispose(); - _urlController.dispose(); - super.dispose(); - } - - WebStorage? get _webStorage => _webViewController?.webStorage; - LocalStorage? get _localStorage => _webStorage?.localStorage; - SessionStorage? get _sessionStorage => _webStorage?.sessionStorage; - - bool get _isLocalStorageTab => _tabController.index == 0; - - String get _activeStorageTypeName => - _isLocalStorageTab ? '$LocalStorage' : '$SessionStorage'; - - String _storageMethodKey(String methodName) { - return '$_activeStorageTypeName.$methodName'; - } - - String _managerMethodKey(PlatformWebStorageManagerMethod method) { - return '$WebStorageManager.${method.name}'; - } - - Set _getStorageMethodPlatforms( - String methodName, { - required bool isLocal, - }) { - if (isLocal) { - final method = PlatformLocalStorageMethod.values.firstWhere( - (m) => m.name == methodName, - ); - return SupportCheckHelper.supportedPlatformsForMethod( - method: method, - checker: LocalStorage.isMethodSupported, - ); - } - - final method = PlatformSessionStorageMethod.values.firstWhere( - (m) => m.name == methodName, - ); - return SupportCheckHelper.supportedPlatformsForMethod( - method: method, - checker: SessionStorage.isMethodSupported, - ); - } - - Future _loadUrl() async { - final url = _urlController.text.trim(); - if (url.isEmpty) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.loadUrl.name, - 'Please enter a URL', - isError: true, - ); - return; - } - - try { - await _webViewController?.loadUrl( - urlRequest: URLRequest(url: WebUri(url)), - ); - } catch (e) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.loadUrl.name, - 'Error loading URL: $e', - isError: true, - ); - } - } - - Future _getLength() async { - if (!_webViewReady) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.length.name), - 'WebView not ready. Load a page first.', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final storage = _isLocalStorageTab ? _localStorage : _sessionStorage; - final length = await storage?.length(); - - setState(() { - if (_isLocalStorageTab) { - _localStorageLength = length; - } else { - _sessionStorageLength = length; - } - }); - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.length.name), - 'Storage length: $length', - isError: false, - ); - } catch (e) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.length.name), - 'Error getting length: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getItems() async { - if (!_webViewReady) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.getItems.name), - 'WebView not ready. Load a page first.', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final storage = _isLocalStorageTab ? _localStorage : _sessionStorage; - final items = await storage?.getItems() ?? []; - - setState(() { - if (_isLocalStorageTab) { - _localStorageItems = items; - _localStorageLength = items.length; - } else { - _sessionStorageItems = items; - _sessionStorageLength = items.length; - } - }); - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.getItems.name), - 'Found ${items.length} items', - isError: false, - ); - } catch (e) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.getItems.name), - 'Error getting items: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getItem(String key) async { - if (!_webViewReady) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.getItem.name), - 'WebView not ready. Load a page first.', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final storage = _isLocalStorageTab ? _localStorage : _sessionStorage; - final value = await storage?.getItem(key: key); - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.getItem.name), - 'Value for "$key": ${value ?? "null"}', - isError: false, - ); - } catch (e) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.getItem.name), - 'Error getting item: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _setItem() async { - if (!_webViewReady) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.setItem.name), - 'WebView not ready. Load a page first.', - isError: true, - ); - return; - } - - await _promptSetItem(); - } - - Future _removeItem(String key) async { - if (!_webViewReady) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.removeItem.name), - 'WebView not ready. Load a page first.', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final storage = _isLocalStorageTab ? _localStorage : _sessionStorage; - await storage?.removeItem(key: key); - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.removeItem.name), - 'Item "$key" removed', - isError: false, - ); - await _getItems(); - } catch (e) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.removeItem.name), - 'Error removing item: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _promptRemoveItem() async { - final params = await showParameterDialog( - context: context, - title: 'Remove Item', - parameters: {'key': ''}, - requiredPaths: ['key'], - ); - - if (params == null) return; - final key = params['key']?.toString() ?? ''; - if (key.isEmpty) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.removeItem.name), - 'Please enter a key', - isError: true, - ); - return; - } - _removeItem(key); - } - - Future _clear() async { - if (!_webViewReady) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.clear.name), - 'WebView not ready. Load a page first.', - isError: true, - ); - return; - } - - final confirmed = await _showConfirmDialog( - 'Clear Storage', - 'Are you sure you want to clear all $_activeStorageTypeName items?', - ); - if (!confirmed) return; - - setState(() => _isLoading = true); - try { - final storage = _isLocalStorageTab ? _localStorage : _sessionStorage; - await storage?.clear(); - setState(() { - if (_isLocalStorageTab) { - _localStorageItems = []; - _localStorageLength = 0; - } else { - _sessionStorageItems = []; - _sessionStorageLength = 0; - } - }); - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.clear.name), - 'Storage cleared', - isError: false, - ); - } catch (e) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.clear.name), - 'Error clearing storage: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _key(int index) async { - if (!_webViewReady) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.key.name), - 'WebView not ready. Load a page first.', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final storage = _isLocalStorageTab ? _localStorage : _sessionStorage; - final keyName = await storage?.key(index: index); - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.key.name), - 'Key at index $index: ${keyName ?? "null"}', - isError: false, - ); - } catch (e) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.key.name), - 'Error getting key: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - void _recordMethodResult( - String methodName, - String message, { - required bool isError, - dynamic value, - }) { - setState(() { - final entries = List.from( - _methodHistory[methodName] ?? const [], - ); - entries.insert( - 0, - MethodResultEntry( - message: message, - isError: isError, - timestamp: DateTime.now(), - value: value, - ), - ); - if (entries.length > _maxHistoryEntries) { - entries.removeRange(_maxHistoryEntries, entries.length); - } - _methodHistory[methodName] = entries; - _selectedHistoryIndex[methodName] = 0; - }); - } - - Future _showConfirmDialog(String title, String content) async { - return await showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text(title), - content: Text(content), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context, false), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: () => Navigator.pop(context, true), - style: ElevatedButton.styleFrom(backgroundColor: Colors.red), - child: const Text('Clear'), - ), - ], - ), - ) ?? - false; - } - - Future _promptSetItem() async { - final params = await showParameterDialog( - context: context, - title: 'Set Item ($_activeStorageTypeName)', - parameters: {'key': '', 'value': ''}, - requiredPaths: ['key', 'value'], - ); - - if (params == null) return; - final key = params['key']?.toString() ?? ''; - final value = params['value']?.toString() ?? ''; - if (key.isEmpty || value.isEmpty) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.setItem.name), - 'Key and Value are required', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final storage = _isLocalStorageTab ? _localStorage : _sessionStorage; - await storage?.setItem(key: key, value: value); - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.setItem.name), - 'Item set successfully', - isError: false, - ); - await _getItems(); - } catch (e) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.setItem.name), - 'Error setting item: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _promptKeyIndex() async { - final params = await showParameterDialog( - context: context, - title: 'Get Key at Index', - parameters: {'index': 0}, - requiredPaths: ['index'], - ); - - if (params == null) return; - final index = (params['index'] as num?)?.toInt(); - if (index == null || index < 0) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.key.name), - 'Please enter a valid index', - isError: true, - ); - return; - } - _key(index); - } - - Future _promptGetItem() async { - final params = await showParameterDialog( - context: context, - title: 'Get Item by Key', - parameters: {'key': ''}, - requiredPaths: ['key'], - ); - - if (params == null) return; - final key = params['key']?.toString() ?? ''; - if (key.isEmpty) { - _recordMethodResult( - _storageMethodKey(PlatformLocalStorageMethod.getItem.name), - 'Please enter a key', - isError: true, - ); - return; - } - _getItem(key); - } - - Widget _buildMethodHistory(String methodName, {String? title}) { - final entries = _methodHistory[methodName] ?? const []; - if (entries.isEmpty) { - return const SizedBox.shrink(); - } - return MethodResultHistory( - entries: entries, - selectedIndex: _selectedHistoryIndex[methodName], - title: title ?? methodName, - onSelected: (index) { - setState(() => _selectedHistoryIndex[methodName] = index); - }, - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Web Storage'), - actions: [AppBarLoadingIndicator(isLoading: _isLoading)], - bottom: TabBar( - controller: _tabController, - tabs: [ - const Tab(text: 'Manager'), - Tab(text: '$LocalStorage'), - Tab(text: '$SessionStorage'), - ], - indicatorColor: Colors.white, - ), - ), - drawer: AppDrawer(), - body: LayoutBuilder( - builder: (context, constraints) { - final maxWebViewHeight = - constraints.maxHeight - _minContentHeight - _dividerHeight; - final effectiveMax = maxWebViewHeight < _minWebViewHeight - ? _minWebViewHeight - : maxWebViewHeight; - final webViewHeight = _webViewHeight - .clamp(_minWebViewHeight, effectiveMax) - .toDouble(); - - return Column( - children: [ - SizedBox(height: webViewHeight, child: _buildWebViewSection()), - ResizeHandle( - height: _dividerHeight, - onDrag: (delta) { - setState(() { - _webViewHeight = (_webViewHeight + delta) - .clamp(_minWebViewHeight, effectiveMax) - .toDouble(); - }); - }, - ), - Expanded( - child: TabBarView( - controller: _tabController, - children: [ - _buildWebStorageManagerView(), - _buildStorageView( - items: _localStorageItems, - length: _localStorageLength, - isLocal: true, - ), - _buildStorageView( - items: _sessionStorageItems, - length: _sessionStorageLength, - isLocal: false, - ), - ], - ), - ), - ], - ); - }, - ), - ); - } - - Widget _buildWebViewSection() { - return Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.grey.shade100, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - child: TextField( - controller: _urlController, - decoration: const InputDecoration( - labelText: 'URL', - hintText: 'https://example.com', - border: OutlineInputBorder(), - isDense: true, - ), - ), - ), - const SizedBox(width: 8), - ElevatedButton(onPressed: _loadUrl, child: const Text('Load')), - ], - ), - const SizedBox(height: 8), - _buildMethodHistory( - PlatformInAppWebViewControllerMethod.loadUrl.name, - ), - const SizedBox(height: 8), - Expanded( - child: Stack( - children: [ - InAppWebView( - initialUrlRequest: URLRequest( - url: WebUri(_urlController.text), - ), - initialSettings: InAppWebViewSettings( - javaScriptEnabled: true, - ), - onWebViewCreated: (controller) { - _webViewController = controller; - }, - onLoadStop: (controller, url) { - setState(() => _webViewReady = true); - }, - onLoadError: (controller, url, code, message) { - _recordMethodResult( - PlatformInAppWebViewControllerMethod.loadUrl.name, - 'Load error: $message', - isError: true, - ); - }, - ), - Container( - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.7), - borderRadius: BorderRadius.circular(4), - ), - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), - margin: const EdgeInsets.all(4), - child: Text( - _webViewReady ? 'WebView Ready ✓' : 'Loading WebView...', - style: TextStyle( - color: _webViewReady ? Colors.green : Colors.white, - fontSize: 12, - ), - ), - ), - ], - ), - ), - if (!_webViewReady) - Container( - margin: const EdgeInsets.only(top: 8), - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.orange.shade100, - borderRadius: BorderRadius.circular(4), - ), - child: Row( - children: [ - const Icon( - Icons.info_outline, - size: 16, - color: Colors.orange, - ), - const SizedBox(width: 8), - Expanded( - child: Text( - '$WebStorage requires a loaded WebView. Load a page to enable storage methods.', - style: const TextStyle(fontSize: 12), - ), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildStorageView({ - required List items, - required int? length, - required bool isLocal, - }) { - return ListView( - padding: const EdgeInsets.all(16), - children: [ - _buildMethodSection( - PlatformLocalStorageMethod.length.name, - 'Get number of items in storage', - _getStorageMethodPlatforms( - PlatformLocalStorageMethod.length.name, - isLocal: isLocal, - ), - _getLength, - ), - _buildMethodSection( - PlatformLocalStorageMethod.setItem.name, - 'Set a key-value pair', - _getStorageMethodPlatforms( - PlatformLocalStorageMethod.setItem.name, - isLocal: isLocal, - ), - _setItem, - ), - _buildMethodSection( - PlatformLocalStorageMethod.getItem.name, - 'Get value by key', - _getStorageMethodPlatforms( - PlatformLocalStorageMethod.getItem.name, - isLocal: isLocal, - ), - _promptGetItem, - ), - _buildMethodSection( - PlatformLocalStorageMethod.removeItem.name, - 'Remove item by key (select from list)', - _getStorageMethodPlatforms( - PlatformLocalStorageMethod.removeItem.name, - isLocal: isLocal, - ), - _promptRemoveItem, - ), - _buildMethodSection( - PlatformLocalStorageMethod.getItems.name, - 'Get all items', - _getStorageMethodPlatforms( - PlatformLocalStorageMethod.getItems.name, - isLocal: isLocal, - ), - _getItems, - ), - _buildMethodSection( - PlatformLocalStorageMethod.clear.name, - 'Clear all items', - _getStorageMethodPlatforms( - PlatformLocalStorageMethod.clear.name, - isLocal: isLocal, - ), - _clear, - ), - _buildMethodSection( - PlatformLocalStorageMethod.key.name, - 'Get key at index', - _getStorageMethodPlatforms( - PlatformLocalStorageMethod.key.name, - isLocal: isLocal, - ), - _promptKeyIndex, - ), - const SizedBox(height: 16), - _buildItemsList(items, length), - ], - ); - } - - Widget _buildMethodSection( - String methodName, - String description, - Set supportedPlatforms, - VoidCallback? onPressed, - ) { - final historyKey = _storageMethodKey(methodName); - return MethodTile( - methodName: methodName, - description: description, - supportedPlatforms: supportedPlatforms, - onRun: !_isLoading && _webViewReady ? onPressed : null, - historyEntries: _methodHistory[historyKey], - selectedHistoryIndex: _selectedHistoryIndex[historyKey], - onHistorySelected: (index) { - setState(() => _selectedHistoryIndex[historyKey] = index); - }, - ); - } - - Widget _buildItemsList(List items, int? length) { - final storageName = _activeStorageTypeName; - - if (items.isEmpty) { - return EmptyStateCard( - icon: Icons.storage_outlined, - title: 'No $storageName items found', - description: _webViewReady - ? 'Click "${_isLocalStorageTab ? PlatformLocalStorageMethod.getItems.name : PlatformSessionStorageMethod.getItems.name}" to fetch storage contents' - : 'Load a page first, then fetch items', - ); - } - - return Card( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Row( - children: [ - Text( - '$storageName (${length ?? items.length} items)', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - const Spacer(), - IconButton( - icon: const Icon(Icons.refresh), - onPressed: _isLoading || !_webViewReady ? null : _getItems, - tooltip: 'Refresh', - ), - ], - ), - ), - const Divider(height: 1), - ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: items.length, - separatorBuilder: (_, __) => const Divider(height: 1), - itemBuilder: (context, index) { - final item = items[index]; - return ListTile( - title: Text( - item.key ?? 'null', - style: const TextStyle(fontWeight: FontWeight.w500), - ), - subtitle: Text( - item.value?.toString() ?? 'null', - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon(Icons.content_copy, size: 20), - onPressed: () { - _getItem(item.key ?? ''); - }, - tooltip: 'Get Item Value', - ), - IconButton( - icon: const Icon(Icons.delete_outline, size: 20), - onPressed: () { - _removeItem(item.key ?? ''); - }, - tooltip: 'Remove Item', - color: Colors.red, - ), - ], - ), - ); - }, - ), - ], - ), - ); - } - // ============ WebStorageManager Methods ============ - - Set _getManagerMethodPlatforms(String methodName) { - final method = PlatformWebStorageManagerMethod.values.firstWhere( - (m) => m.name == methodName, - orElse: () => PlatformWebStorageManagerMethod.deleteAllData, - ); - return SupportCheckHelper.supportedPlatformsForMethod( - method: method, - checker: WebStorageManager.isMethodSupported, - ); - } - - Future _getOrigins() async { - setState(() => _isLoading = true); - try { - final origins = await _webStorageManager.getOrigins(); - setState(() => _webStorageOrigins = origins); - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.getOrigins), - 'Found ${origins.length} origins', - isError: false, - value: origins.map((o) => o.toMap()).toList(), - ); - } catch (e) { - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.getOrigins), - 'Error getting origins: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _deleteAllData() async { - final confirmed = await _showConfirmDialog( - 'Delete All Data', - 'Are you sure you want to delete all web storage data?', - ); - if (!confirmed) return; - - setState(() => _isLoading = true); - try { - await _webStorageManager.deleteAllData(); - setState(() => _webStorageOrigins = []); - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.deleteAllData), - 'All web storage data deleted', - isError: false, - ); - } catch (e) { - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.deleteAllData), - 'Error deleting all data: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _deleteOrigin(String origin) async { - setState(() => _isLoading = true); - try { - await _webStorageManager.deleteOrigin(origin: origin); - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.deleteOrigin), - 'Deleted origin: $origin', - isError: false, - ); - await _getOrigins(); - } catch (e) { - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.deleteOrigin), - 'Error deleting origin: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _promptDeleteOrigin() async { - final params = await showParameterDialog( - context: context, - title: 'Delete Origin', - parameters: {'origin': ''}, - requiredPaths: ['origin'], - ); - - if (params == null) return; - final origin = params['origin']?.toString() ?? ''; - if (origin.isEmpty) { - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.deleteOrigin), - 'Please enter an origin', - isError: true, - ); - return; - } - await _deleteOrigin(origin); - } - - Future _getQuotaForOrigin() async { - final params = await showParameterDialog( - context: context, - title: 'Get Quota for Origin', - parameters: {'origin': ''}, - requiredPaths: ['origin'], - ); - - if (params == null) return; - final origin = params['origin']?.toString() ?? ''; - if (origin.isEmpty) { - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.getQuotaForOrigin), - 'Please enter an origin', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final quota = await _webStorageManager.getQuotaForOrigin(origin: origin); - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.getQuotaForOrigin), - 'Quota for "$origin": $quota bytes', - isError: false, - value: quota, - ); - } catch (e) { - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.getQuotaForOrigin), - 'Error getting quota: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _getUsageForOrigin() async { - final params = await showParameterDialog( - context: context, - title: 'Get Usage for Origin', - parameters: {'origin': ''}, - requiredPaths: ['origin'], - ); - - if (params == null) return; - final origin = params['origin']?.toString() ?? ''; - if (origin.isEmpty) { - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.getUsageForOrigin), - 'Please enter an origin', - isError: true, - ); - return; - } - - setState(() => _isLoading = true); - try { - final usage = await _webStorageManager.getUsageForOrigin(origin: origin); - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.getUsageForOrigin), - 'Usage for "$origin": $usage bytes', - isError: false, - value: usage, - ); - } catch (e) { - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.getUsageForOrigin), - 'Error getting usage: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _fetchDataRecords() async { - setState(() => _isLoading = true); - try { - final records = await _webStorageManager.fetchDataRecords( - dataTypes: WebsiteDataType.ALL, - ); - setState(() => _dataRecords = records); - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.fetchDataRecords), - 'Found ${records.length} data records', - isError: false, - value: records.map((r) => r.toMap()).toList(), - ); - } catch (e) { - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.fetchDataRecords), - 'Error fetching data records: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _removeDataModifiedSince() async { - final params = await showParameterDialog( - context: context, - title: 'Remove Data Modified Since', - description: 'Enter how many days ago to start removal (0 = all data)', - parameters: {'daysAgo': 0}, - ); - - if (params == null) return; - final daysAgo = (params['daysAgo'] as num?)?.toInt() ?? 0; - final date = DateTime.now().subtract(Duration(days: daysAgo)); - - final confirmed = await _showConfirmDialog( - 'Remove Data', - 'Are you sure you want to remove all data modified since ${date.toIso8601String()}?', - ); - if (!confirmed) return; - - setState(() => _isLoading = true); - try { - await _webStorageManager.removeDataModifiedSince( - dataTypes: WebsiteDataType.ALL, - date: date, - ); - setState(() => _dataRecords = []); - _recordMethodResult( - _managerMethodKey( - PlatformWebStorageManagerMethod.removeDataModifiedSince, - ), - 'Data removed since ${date.toIso8601String()}', - isError: false, - ); - } catch (e) { - _recordMethodResult( - _managerMethodKey( - PlatformWebStorageManagerMethod.removeDataModifiedSince, - ), - 'Error removing data: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Future _removeDataForRecord(WebsiteDataRecord record) async { - setState(() => _isLoading = true); - try { - await _webStorageManager.removeDataFor( - dataTypes: record.dataTypes ?? WebsiteDataType.ALL, - dataRecords: [record], - ); - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.removeDataFor), - 'Removed data for ${record.displayName}', - isError: false, - ); - await _fetchDataRecords(); - } catch (e) { - _recordMethodResult( - _managerMethodKey(PlatformWebStorageManagerMethod.removeDataFor), - 'Error removing data: $e', - isError: true, - ); - } finally { - setState(() => _isLoading = false); - } - } - - Widget _buildWebStorageManagerView() { - return ListView( - padding: const EdgeInsets.all(16), - children: [ - // Platform info card - Card( - color: Colors.blue.shade50, - child: Padding( - padding: const EdgeInsets.all(12), - child: Row( - children: [ - Icon(Icons.info_outline, color: Colors.blue.shade700), - const SizedBox(width: 12), - Expanded( - child: Text( - '$WebStorageManager provides platform-level storage management. ' - 'Methods have different platform availability - check the support badges.', - style: TextStyle(fontSize: 12, color: Colors.blue.shade700), - ), - ), - ], - ), - ), - ), - const SizedBox(height: 16), - _buildManagerMethodSection( - PlatformWebStorageManagerMethod.getOrigins.name, - 'Get origins using Application Cache or Web SQL Database', - _getManagerMethodPlatforms( - PlatformWebStorageManagerMethod.getOrigins.name, - ), - _getOrigins, - ), - _buildManagerMethodSection( - PlatformWebStorageManagerMethod.deleteAllData.name, - 'Clear all storage (App Cache, Web SQL, HTML5 Storage)', - _getManagerMethodPlatforms( - PlatformWebStorageManagerMethod.deleteAllData.name, - ), - _deleteAllData, - ), - _buildManagerMethodSection( - PlatformWebStorageManagerMethod.deleteOrigin.name, - 'Clear storage for a specific origin', - _getManagerMethodPlatforms( - PlatformWebStorageManagerMethod.deleteOrigin.name, - ), - _promptDeleteOrigin, - ), - _buildManagerMethodSection( - PlatformWebStorageManagerMethod.getQuotaForOrigin.name, - 'Get storage quota for an origin (bytes)', - _getManagerMethodPlatforms( - PlatformWebStorageManagerMethod.getQuotaForOrigin.name, - ), - _getQuotaForOrigin, - ), - _buildManagerMethodSection( - PlatformWebStorageManagerMethod.getUsageForOrigin.name, - 'Get storage usage for an origin (bytes)', - _getManagerMethodPlatforms( - PlatformWebStorageManagerMethod.getUsageForOrigin.name, - ), - _getUsageForOrigin, - ), - _buildManagerMethodSection( - PlatformWebStorageManagerMethod.fetchDataRecords.name, - 'Fetch website data records', - _getManagerMethodPlatforms( - PlatformWebStorageManagerMethod.fetchDataRecords.name, - ), - _fetchDataRecords, - ), - _buildManagerMethodSection( - PlatformWebStorageManagerMethod.removeDataModifiedSince.name, - 'Remove data modified since a date', - _getManagerMethodPlatforms( - PlatformWebStorageManagerMethod.removeDataModifiedSince.name, - ), - _removeDataModifiedSince, - ), - const SizedBox(height: 16), - _buildOriginsList(), - const SizedBox(height: 16), - _buildDataRecordsList(), - ], - ); - } - - Widget _buildManagerMethodSection( - String methodName, - String description, - Set supportedPlatforms, - VoidCallback? onPressed, - ) { - final historyKey = '$WebStorageManager.$methodName'; - return MethodTile( - methodName: methodName, - description: description, - supportedPlatforms: supportedPlatforms, - onRun: !_isLoading ? onPressed : null, - historyEntries: _methodHistory[historyKey], - selectedHistoryIndex: _selectedHistoryIndex[historyKey], - onHistorySelected: (index) { - setState(() => _selectedHistoryIndex[historyKey] = index); - }, - ); - } - - Widget _buildOriginsList() { - if (_webStorageOrigins.isEmpty) { - return EmptyStateCard( - icon: Icons.public_outlined, - title: 'No origins fetched', - description: - 'Click "${PlatformWebStorageManagerMethod.getOrigins.name}" to fetch storage origins', - iconSize: 48, - ); - } - - return Card( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Row( - children: [ - Text( - 'Origins (${_webStorageOrigins.length})', - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - const Spacer(), - IconButton( - icon: const Icon(Icons.refresh), - onPressed: _isLoading ? null : _getOrigins, - tooltip: 'Refresh', - ), - ], - ), - ), - const Divider(height: 1), - ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: _webStorageOrigins.length, - separatorBuilder: (_, __) => const Divider(height: 1), - itemBuilder: (context, index) { - final origin = _webStorageOrigins[index]; - return ListTile( - title: Text( - origin.origin ?? 'Unknown', - style: const TextStyle(fontWeight: FontWeight.w500), - ), - subtitle: Text( - 'Quota: ${origin.quota ?? 'N/A'} bytes, Usage: ${origin.usage ?? 'N/A'} bytes', - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - trailing: IconButton( - icon: const Icon(Icons.delete_outline, size: 20), - onPressed: () => _deleteOrigin(origin.origin ?? ''), - tooltip: 'Delete Origin', - color: Colors.red, - ), - ); - }, - ), - ], - ), - ); - } - - Widget _buildDataRecordsList() { - if (_dataRecords.isEmpty) { - return EmptyStateCard( - icon: Icons.folder_outlined, - title: 'No data records fetched', - description: - 'Click "${PlatformWebStorageManagerMethod.fetchDataRecords.name}" to fetch website data records', - iconSize: 48, - ); - } - - return Card( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Row( - children: [ - Text( - 'Data Records (${_dataRecords.length})', - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - const Spacer(), - IconButton( - icon: const Icon(Icons.refresh), - onPressed: _isLoading ? null : _fetchDataRecords, - tooltip: 'Refresh', - ), - ], - ), - ), - const Divider(height: 1), - ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: _dataRecords.length, - separatorBuilder: (_, __) => const Divider(height: 1), - itemBuilder: (context, index) { - final record = _dataRecords[index]; - final dataTypesStr = - record.dataTypes?.map((t) => t.toNativeValue()).join(', ') ?? - 'Unknown'; - return ListTile( - title: Text( - record.displayName ?? 'Unknown', - style: const TextStyle(fontWeight: FontWeight.w500), - ), - subtitle: Text( - 'Types: $dataTypesStr', - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - trailing: IconButton( - icon: const Icon(Icons.delete_outline, size: 20), - onPressed: () => _removeDataForRecord(record), - tooltip: 'Remove Data', - color: Colors.red, - ), - ); - }, - ), - ], - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/screens/support_matrix/platform_comparison_screen.dart b/flutter_inappwebview/example/lib/screens/support_matrix/platform_comparison_screen.dart deleted file mode 100644 index e13cec8483..0000000000 --- a/flutter_inappwebview/example/lib/screens/support_matrix/platform_comparison_screen.dart +++ /dev/null @@ -1,850 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import '../../utils/support_checker.dart'; -import '../../utils/responsive_utils.dart'; -import '../../widgets/common/support_badge.dart'; -import '../../widgets/common/app_drawer.dart'; - -/// Screen for comparing API support between two platforms. -class PlatformComparisonScreen extends StatefulWidget { - const PlatformComparisonScreen({super.key}); - - @override - State createState() => - _PlatformComparisonScreenState(); -} - -class _PlatformComparisonScreenState extends State { - SupportedPlatform _platform1 = SupportedPlatform.android; - SupportedPlatform _platform2 = SupportedPlatform.ios; - String _searchQuery = ''; - final TextEditingController _searchController = TextEditingController(); - - // View mode: 'all', 'common', 'platform1Only', 'platform2Only', 'differences' - String _viewMode = 'all'; - - late List _apiDefinitions; - - @override - void initState() { - super.initState(); - _apiDefinitions = SupportChecker.getAllApiDefinitions(); - } - - @override - void dispose() { - _searchController.dispose(); - super.dispose(); - } - - /// Get comparison statistics - _ComparisonStats _getStats() { - int commonMethods = 0; - int platform1OnlyMethods = 0; - int platform2OnlyMethods = 0; - int commonEvents = 0; - int platform1OnlyEvents = 0; - int platform2OnlyEvents = 0; - - for (final classDef in _apiDefinitions) { - for (final method in classDef.methods) { - final supported = SupportChecker.getSupportedPlatformsForMethod( - classDef.className, - method.name, - ); - final p1 = supported.contains(_platform1); - final p2 = supported.contains(_platform2); - if (p1 && p2) { - commonMethods++; - } else if (p1) { - platform1OnlyMethods++; - } else if (p2) { - platform2OnlyMethods++; - } - } - for (final event in classDef.events) { - final supported = SupportChecker.getSupportedPlatformsForEvent( - classDef.className, - event.name, - ); - final p1 = supported.contains(_platform1); - final p2 = supported.contains(_platform2); - if (p1 && p2) { - commonEvents++; - } else if (p1) { - platform1OnlyEvents++; - } else if (p2) { - platform2OnlyEvents++; - } - } - } - - return _ComparisonStats( - commonMethods: commonMethods, - platform1OnlyMethods: platform1OnlyMethods, - platform2OnlyMethods: platform2OnlyMethods, - commonEvents: commonEvents, - platform1OnlyEvents: platform1OnlyEvents, - platform2OnlyEvents: platform2OnlyEvents, - ); - } - - /// Filter APIs based on view mode and search - List<_ComparisonItem> _getFilteredItems() { - final items = <_ComparisonItem>[]; - - for (final classDef in _apiDefinitions) { - // Methods - for (final method in classDef.methods) { - final supported = SupportChecker.getSupportedPlatformsForMethod( - classDef.className, - method.name, - ); - final p1 = supported.contains(_platform1); - final p2 = supported.contains(_platform2); - - if (!_matchesViewMode(p1, p2)) continue; - if (!_matchesSearch(method.name, method.description)) continue; - - items.add( - _ComparisonItem( - className: classDef.className, - name: method.name, - description: method.description, - isMethod: true, - isStatic: method.isStatic, - category: method.category, - platform1Supported: p1, - platform2Supported: p2, - ), - ); - } - - // Events - for (final event in classDef.events) { - final supported = SupportChecker.getSupportedPlatformsForEvent( - classDef.className, - event.name, - ); - final p1 = supported.contains(_platform1); - final p2 = supported.contains(_platform2); - - if (!_matchesViewMode(p1, p2)) continue; - if (!_matchesSearch(event.name, event.description)) continue; - - items.add( - _ComparisonItem( - className: classDef.className, - name: event.name, - description: event.description, - isMethod: false, - category: event.category, - platform1Supported: p1, - platform2Supported: p2, - ), - ); - } - } - - return items; - } - - bool _matchesViewMode(bool p1, bool p2) { - switch (_viewMode) { - case 'common': - return p1 && p2; - case 'platform1Only': - return p1 && !p2; - case 'platform2Only': - return !p1 && p2; - case 'differences': - return p1 != p2; - default: - return true; - } - } - - bool _matchesSearch(String name, String description) { - if (_searchQuery.isEmpty) return true; - final query = _searchQuery.toLowerCase(); - return name.toLowerCase().contains(query) || - description.toLowerCase().contains(query); - } - - void _exportComparison() { - final stats = _getStats(); - final items = _getFilteredItems(); - - final buffer = StringBuffer(); - buffer.writeln( - '# Platform Comparison: ${_platform1.displayName} vs ${_platform2.displayName}\n', - ); - buffer.writeln('Generated: ${DateTime.now().toIso8601String()}\n'); - - buffer.writeln('## Summary\n'); - buffer.writeln( - '| Category | ${_platform1.displayName} | ${_platform2.displayName} | Common |', - ); - buffer.writeln('|----------|---------|---------|--------|'); - buffer.writeln( - '| Methods | ${stats.commonMethods + stats.platform1OnlyMethods} | ${stats.commonMethods + stats.platform2OnlyMethods} | ${stats.commonMethods} |', - ); - buffer.writeln( - '| Events | ${stats.commonEvents + stats.platform1OnlyEvents} | ${stats.commonEvents + stats.platform2OnlyEvents} | ${stats.commonEvents} |', - ); - buffer.writeln(); - - buffer.writeln( - '## Common APIs (${stats.commonMethods + stats.commonEvents})\n', - ); - buffer.writeln('| Class | API | Type |'); - buffer.writeln('|-------|-----|------|'); - for (final item in items.where( - (i) => i.platform1Supported && i.platform2Supported, - )) { - buffer.writeln( - '| ${item.className} | ${item.name} | ${item.isMethod ? "Method" : "Event"} |', - ); - } - buffer.writeln(); - - buffer.writeln( - '## ${_platform1.displayName} Only (${stats.platform1OnlyMethods + stats.platform1OnlyEvents})\n', - ); - buffer.writeln('| Class | API | Type |'); - buffer.writeln('|-------|-----|------|'); - for (final item in items.where( - (i) => i.platform1Supported && !i.platform2Supported, - )) { - buffer.writeln( - '| ${item.className} | ${item.name} | ${item.isMethod ? "Method" : "Event"} |', - ); - } - buffer.writeln(); - - buffer.writeln( - '## ${_platform2.displayName} Only (${stats.platform2OnlyMethods + stats.platform2OnlyEvents})\n', - ); - buffer.writeln('| Class | API | Type |'); - buffer.writeln('|-------|-----|------|'); - for (final item in items.where( - (i) => !i.platform1Supported && i.platform2Supported, - )) { - buffer.writeln( - '| ${item.className} | ${item.name} | ${item.isMethod ? "Method" : "Event"} |', - ); - } - - Clipboard.setData(ClipboardData(text: buffer.toString())); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Comparison exported to clipboard as Markdown'), - backgroundColor: Colors.green, - ), - ); - } - - @override - Widget build(BuildContext context) { - final stats = _getStats(); - final items = _getFilteredItems(); - - return Scaffold( - appBar: AppBar( - title: const Text('Platform Comparison'), - actions: [ - IconButton( - icon: const Icon(Icons.copy), - tooltip: 'Export as Markdown', - onPressed: _exportComparison, - ), - ], - ), - drawer: AppDrawer(), - body: Column( - children: [ - // Platform selectors - _buildPlatformSelectors(), - - // Statistics - _buildStatistics(stats), - - // View mode selector - _buildViewModeSelector(stats), - - // Search - _buildSearchBar(), - - // Results - Expanded( - child: items.isEmpty - ? Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.search_off, - size: 64, - color: Colors.grey.shade400, - ), - const SizedBox(height: 16), - Text( - 'No APIs match your criteria', - style: TextStyle(color: Colors.grey.shade600), - ), - ], - ), - ) - : _buildComparisonList(items), - ), - ], - ), - ); - } - - Widget _buildPlatformSelectors() { - return Container( - padding: const EdgeInsets.all(12), - color: Colors.blue.shade50, - child: LayoutBuilder( - builder: (context, constraints) { - final swapWidget = Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon(Icons.compare_arrows, color: Colors.blue), - const SizedBox(height: 4), - TextButton( - onPressed: () { - setState(() { - final temp = _platform1; - _platform1 = _platform2; - _platform2 = temp; - }); - }, - child: const Text('Swap', style: TextStyle(fontSize: 12)), - ), - ], - ); - - // Always use Row layout - expand to fill available space - return Row( - key: const Key('platform_comparison_selectors_row'), - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: _buildPlatformDropdown( - value: _platform1, - label: 'Platform 1', - onChanged: (p) => setState(() => _platform1 = p!), - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: swapWidget, - ), - Expanded( - child: _buildPlatformDropdown( - value: _platform2, - label: 'Platform 2', - onChanged: (p) => setState(() => _platform2 = p!), - ), - ), - ], - ); - }, - ), - ); - } - - Widget _buildPlatformDropdown({ - required SupportedPlatform value, - required String label, - required ValueChanged onChanged, - }) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - label, - style: TextStyle(fontSize: 12, color: Colors.grey.shade700), - ), - const SizedBox(height: 4), - Container( - padding: const EdgeInsets.symmetric(horizontal: 12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: value.color.withOpacity(0.5)), - ), - child: DropdownButtonHideUnderline( - child: DropdownButton( - value: value, - isExpanded: true, - items: SupportedPlatform.values.map((p) { - return DropdownMenuItem( - value: p, - child: Row( - children: [ - Icon(p.icon, size: 18, color: p.color), - const SizedBox(width: 8), - Text(p.displayName), - ], - ), - ); - }).toList(), - onChanged: onChanged, - ), - ), - ), - ], - ); - } - - Widget _buildStatistics(_ComparisonStats stats) { - final p1Total = - stats.commonMethods + - stats.platform1OnlyMethods + - stats.commonEvents + - stats.platform1OnlyEvents; - final p2Total = - stats.commonMethods + - stats.platform2OnlyMethods + - stats.commonEvents + - stats.platform2OnlyEvents; - final commonTotal = stats.commonMethods + stats.commonEvents; - - return Container( - padding: const EdgeInsets.all(12), - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: IntrinsicWidth( - child: Row( - key: const Key('platform_comparison_stats_row'), - children: [ - _buildStatCard( - _platform1.displayName, - p1Total.toString(), - _platform1.color, - _platform1.icon, - ), - const SizedBox(width: 12), - _buildStatCard( - 'Common', - commonTotal.toString(), - Colors.green, - Icons.handshake, - ), - const SizedBox(width: 12), - _buildStatCard( - _platform2.displayName, - p2Total.toString(), - _platform2.color, - _platform2.icon, - ), - ], - ), - ), - ), - ); - } - - Widget _buildStatCard( - String label, - String value, - Color color, - IconData icon, - ) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - decoration: BoxDecoration( - color: color.withOpacity(0.1), - borderRadius: BorderRadius.circular(8), - border: Border.all(color: color.withOpacity(0.3)), - ), - child: Column( - children: [ - Icon(icon, color: color, size: 20), - const SizedBox(height: 4), - Text( - value, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: color, - ), - ), - Text(label, style: TextStyle(fontSize: 11, color: color)), - ], - ), - ); - } - - Widget _buildViewModeSelector(_ComparisonStats stats) { - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - padding: const EdgeInsets.symmetric(horizontal: 12), - child: Row( - children: [ - _buildViewModeChip('all', 'All', null, Icons.list), - _buildViewModeChip( - 'common', - 'Common (${stats.commonMethods + stats.commonEvents})', - Colors.green, - Icons.handshake, - ), - _buildViewModeChip( - 'platform1Only', - '${_platform1.displayName} Only (${stats.platform1OnlyMethods + stats.platform1OnlyEvents})', - _platform1.color, - _platform1.icon, - ), - _buildViewModeChip( - 'platform2Only', - '${_platform2.displayName} Only (${stats.platform2OnlyMethods + stats.platform2OnlyEvents})', - _platform2.color, - _platform2.icon, - ), - _buildViewModeChip( - 'differences', - 'Differences', - Colors.orange, - Icons.difference, - ), - ], - ), - ); - } - - Widget _buildViewModeChip( - String mode, - String label, - Color? color, - IconData icon, - ) { - final isSelected = _viewMode == mode; - return Padding( - padding: const EdgeInsets.only(right: 8), - child: ChoiceChip( - selected: isSelected, - label: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - icon, - size: 14, - color: isSelected ? Colors.white : (color ?? Colors.grey), - ), - const SizedBox(width: 4), - Text( - label, - style: TextStyle( - fontSize: 11, - color: isSelected ? Colors.white : null, - ), - ), - ], - ), - selectedColor: color ?? Colors.blue, - onSelected: (_) => setState(() => _viewMode = mode), - ), - ); - } - - Widget _buildSearchBar() { - return Padding( - padding: const EdgeInsets.all(12), - child: TextField( - controller: _searchController, - decoration: InputDecoration( - hintText: 'Search APIs...', - prefixIcon: const Icon(Icons.search, size: 20), - suffixIcon: _searchQuery.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear, size: 20), - onPressed: () { - _searchController.clear(); - setState(() => _searchQuery = ''); - }, - ) - : null, - border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), - isDense: true, - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 10, - ), - ), - onChanged: (v) => setState(() => _searchQuery = v), - ), - ); - } - - Widget _buildComparisonList(List<_ComparisonItem> items) { - // Group by class - final grouped = >{}; - for (final item in items) { - grouped.putIfAbsent(item.className, () => []).add(item); - } - - return ListView.builder( - padding: const EdgeInsets.all(8), - itemCount: grouped.length, - itemBuilder: (context, index) { - final className = grouped.keys.elementAt(index); - final classItems = grouped[className]!; - - return Card( - margin: const EdgeInsets.only(bottom: 8), - child: ExpansionTile( - initiallyExpanded: grouped.length <= 3, - title: Row( - children: [ - const Icon(Icons.class_, size: 18, color: Colors.blue), - const SizedBox(width: 8), - Text( - className, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - const Spacer(), - Text( - '${classItems.length} APIs', - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - ], - ), - children: classItems - .map((item) => _buildComparisonRow(item)) - .toList(), - ), - ); - }, - ); - } - - Widget _buildComparisonRow(_ComparisonItem item) { - Color rowColor; - IconData statusIcon; - String statusText; - - if (item.platform1Supported && item.platform2Supported) { - rowColor = Colors.green.shade50; - statusIcon = Icons.check_circle; - statusText = 'Both'; - } else if (item.platform1Supported) { - rowColor = _platform1.color.withOpacity(0.1); - statusIcon = Icons.arrow_back; - statusText = '${_platform1.displayName} only'; - } else if (item.platform2Supported) { - rowColor = _platform2.color.withOpacity(0.1); - statusIcon = Icons.arrow_forward; - statusText = '${_platform2.displayName} only'; - } else { - rowColor = Colors.grey.shade100; - statusIcon = Icons.block; - statusText = 'Neither'; - } - - return LayoutBuilder( - builder: (context, constraints) { - final isMobile = ResponsiveBreakpoints.isMobileWidth( - constraints.maxWidth, - ); - - if (isMobile) { - return Container( - color: rowColor, - padding: const EdgeInsets.all(12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon( - item.isMethod ? Icons.functions : Icons.bolt, - size: 16, - color: item.isMethod ? Colors.blue : Colors.orange, - ), - const SizedBox(width: 8), - Expanded( - child: Text( - item.name, - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 13, - ), - ), - ), - ], - ), - if (item.description.isNotEmpty) ...[ - const SizedBox(height: 4), - Text( - item.description, - style: TextStyle(fontSize: 11, color: Colors.grey.shade600), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ], - const SizedBox(height: 8), - Wrap( - spacing: 8, - runSpacing: 8, - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - SupportBadge( - platform: _platform1, - isSupported: item.platform1Supported, - compact: true, - ), - Tooltip( - message: statusText, - child: Icon( - statusIcon, - size: 18, - color: - item.platform1Supported && item.platform2Supported - ? Colors.green - : item.platform1Supported - ? _platform1.color - : item.platform2Supported - ? _platform2.color - : Colors.grey, - ), - ), - SupportBadge( - platform: _platform2, - isSupported: item.platform2Supported, - compact: true, - ), - ], - ), - ], - ), - ); - } - - return Container( - color: rowColor, - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - child: Row( - children: [ - Expanded( - flex: 3, - child: Row( - children: [ - Icon( - item.isMethod ? Icons.functions : Icons.bolt, - size: 16, - color: item.isMethod ? Colors.blue : Colors.orange, - ), - const SizedBox(width: 8), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - item.name, - style: const TextStyle( - fontWeight: FontWeight.w500, - fontSize: 13, - ), - ), - if (item.description.isNotEmpty) - Text( - item.description, - style: TextStyle( - fontSize: 11, - color: Colors.grey.shade600, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ], - ), - ), - ], - ), - ), - Expanded( - child: Center( - child: SupportBadge( - platform: _platform1, - isSupported: item.platform1Supported, - compact: true, - ), - ), - ), - Expanded( - child: Center( - child: Tooltip( - message: statusText, - child: Icon( - statusIcon, - size: 18, - color: item.platform1Supported && item.platform2Supported - ? Colors.green - : item.platform1Supported - ? _platform1.color - : item.platform2Supported - ? _platform2.color - : Colors.grey, - ), - ), - ), - ), - Expanded( - child: Center( - child: SupportBadge( - platform: _platform2, - isSupported: item.platform2Supported, - compact: true, - ), - ), - ), - ], - ), - ); - }, - ); - } -} - -class _ComparisonStats { - final int commonMethods; - final int platform1OnlyMethods; - final int platform2OnlyMethods; - final int commonEvents; - final int platform1OnlyEvents; - final int platform2OnlyEvents; - - _ComparisonStats({ - required this.commonMethods, - required this.platform1OnlyMethods, - required this.platform2OnlyMethods, - required this.commonEvents, - required this.platform1OnlyEvents, - required this.platform2OnlyEvents, - }); -} - -class _ComparisonItem { - final String className; - final String name; - final String description; - final bool isMethod; - final bool isStatic; - final String? category; - final bool platform1Supported; - final bool platform2Supported; - - _ComparisonItem({ - required this.className, - required this.name, - required this.description, - required this.isMethod, - this.isStatic = false, - this.category, - required this.platform1Supported, - required this.platform2Supported, - }); -} diff --git a/flutter_inappwebview/example/lib/screens/support_matrix/support_matrix_screen.dart b/flutter_inappwebview/example/lib/screens/support_matrix/support_matrix_screen.dart deleted file mode 100644 index 703505fff7..0000000000 --- a/flutter_inappwebview/example/lib/screens/support_matrix/support_matrix_screen.dart +++ /dev/null @@ -1,747 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import '../../utils/support_checker.dart'; -import '../../utils/responsive_utils.dart'; -import '../../widgets/common/support_badge.dart'; -import '../../widgets/common/app_drawer.dart'; -import '../../widgets/common/responsive_row.dart'; - -/// Screen displaying a comprehensive support matrix showing all APIs with platform availability. -class SupportMatrixScreen extends StatefulWidget { - const SupportMatrixScreen({super.key}); - - @override - State createState() => _SupportMatrixScreenState(); -} - -class _SupportMatrixScreenState extends State - with SingleTickerProviderStateMixin { - late TabController _tabController; - late List _apiDefinitions; - late SupportSummary _summary; - - final TextEditingController _searchController = TextEditingController(); - String _searchQuery = ''; - Set _selectedPlatforms = {}; - bool _showOnlySupported = false; - bool _showMethods = true; - bool _showEvents = true; - - @override - void initState() { - super.initState(); - _apiDefinitions = SupportChecker.getAllApiDefinitions(); - _summary = SupportChecker.getSupportSummary(); - _tabController = TabController(length: _apiDefinitions.length, vsync: this); - } - - @override - void dispose() { - _tabController.dispose(); - _searchController.dispose(); - super.dispose(); - } - - List _getFilteredMethods(ApiClassDefinition classDef) { - if (!_showMethods) return []; - - return classDef.methods.where((method) { - final supportedPlatforms = SupportChecker.getSupportedPlatformsForMethod( - classDef.className, - method.name, - ); - - // Search filter - if (_searchQuery.isNotEmpty) { - final query = _searchQuery.toLowerCase(); - if (!method.name.toLowerCase().contains(query) && - !method.description.toLowerCase().contains(query)) { - return false; - } - } - - // Platform filter - if (_selectedPlatforms.isNotEmpty) { - if (!_selectedPlatforms.any((p) => supportedPlatforms.contains(p))) { - return false; - } - } - - // Show only supported filter - if (_showOnlySupported) { - if (supportedPlatforms.isEmpty) return false; - } - - return true; - }).toList(); - } - - List _getFilteredEvents(ApiClassDefinition classDef) { - if (!_showEvents) return []; - - return classDef.events.where((event) { - final supportedPlatforms = SupportChecker.getSupportedPlatformsForEvent( - classDef.className, - event.name, - ); - - // Search filter - if (_searchQuery.isNotEmpty) { - final query = _searchQuery.toLowerCase(); - if (!event.name.toLowerCase().contains(query) && - !event.description.toLowerCase().contains(query)) { - return false; - } - } - - // Platform filter - if (_selectedPlatforms.isNotEmpty) { - if (!_selectedPlatforms.any((p) => supportedPlatforms.contains(p))) { - return false; - } - } - - // Show only supported filter - if (_showOnlySupported) { - if (supportedPlatforms.isEmpty) return false; - } - - return true; - }).toList(); - } - - void _exportAsMarkdown() { - final buffer = StringBuffer(); - buffer.writeln('# flutter_inappwebview API Support Matrix\n'); - buffer.writeln('Generated: ${DateTime.now().toIso8601String()}\n'); - - // Summary - buffer.writeln('## Summary\n'); - buffer.writeln('| Platform | Methods | Events | Total |'); - buffer.writeln('|----------|---------|--------|-------|'); - for (final platform in SupportedPlatform.values) { - final methods = _summary.methodsPerPlatform[platform] ?? 0; - final events = _summary.eventsPerPlatform[platform] ?? 0; - buffer.writeln( - '| ${platform.displayName} | $methods | $events | ${methods + events} |', - ); - } - buffer.writeln(); - - // Per class - for (final classDef in _apiDefinitions) { - buffer.writeln('## ${classDef.className}\n'); - if (classDef.description.isNotEmpty) { - buffer.writeln('${classDef.description}\n'); - } - - if (classDef.methods.isNotEmpty) { - buffer.writeln('### Methods\n'); - buffer.writeln( - '| Method | Android | iOS | macOS | Web | Windows | Linux |', - ); - buffer.writeln( - '|--------|---------|-----|-------|-----|---------|-------|', - ); - for (final method in classDef.methods) { - final supportedPlatforms = - SupportChecker.getSupportedPlatformsForMethod( - classDef.className, - method.name, - ); - final row = [ - '`${method.name}`', - _platformMark(supportedPlatforms, SupportedPlatform.android), - _platformMark(supportedPlatforms, SupportedPlatform.ios), - _platformMark(supportedPlatforms, SupportedPlatform.macos), - _platformMark(supportedPlatforms, SupportedPlatform.web), - _platformMark(supportedPlatforms, SupportedPlatform.windows), - _platformMark(supportedPlatforms, SupportedPlatform.linux), - ]; - buffer.writeln('| ${row.join(' | ')} |'); - } - buffer.writeln(); - } - - if (classDef.events.isNotEmpty) { - buffer.writeln('### Events\n'); - buffer.writeln( - '| Event | Android | iOS | macOS | Web | Windows | Linux |', - ); - buffer.writeln( - '|-------|---------|-----|-------|-----|---------|-------|', - ); - for (final event in classDef.events) { - final supportedPlatforms = - SupportChecker.getSupportedPlatformsForEvent( - classDef.className, - event.name, - ); - final row = [ - '`${event.name}`', - _platformMark(supportedPlatforms, SupportedPlatform.android), - _platformMark(supportedPlatforms, SupportedPlatform.ios), - _platformMark(supportedPlatforms, SupportedPlatform.macos), - _platformMark(supportedPlatforms, SupportedPlatform.web), - _platformMark(supportedPlatforms, SupportedPlatform.windows), - _platformMark(supportedPlatforms, SupportedPlatform.linux), - ]; - buffer.writeln('| ${row.join(' | ')} |'); - } - buffer.writeln(); - } - } - - Clipboard.setData(ClipboardData(text: buffer.toString())); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Support matrix copied to clipboard as Markdown'), - backgroundColor: Colors.green, - ), - ); - } - - String _platformMark( - Set platforms, - SupportedPlatform platform, - ) { - return platforms.contains(platform) ? '✅' : '❌'; - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('API Support Matrix'), - actions: [ - IconButton( - icon: const Icon(Icons.copy), - tooltip: 'Export as Markdown', - onPressed: _exportAsMarkdown, - ), - IconButton( - icon: const Icon(Icons.compare_arrows), - tooltip: 'Platform Comparison', - onPressed: () { - Navigator.pushNamed(context, '/platform-comparison'); - }, - ), - ], - bottom: TabBar( - controller: _tabController, - isScrollable: true, - tabs: _apiDefinitions.map((def) { - return Tab( - text: def.className.length > 18 - ? '${def.className.substring(0, 15)}...' - : def.className, - ); - }).toList(), - ), - ), - drawer: AppDrawer(), - body: Column( - children: [ - _buildSummaryHeader(), - _buildSearchAndFilters(), - Expanded( - child: TabBarView( - controller: _tabController, - children: _apiDefinitions.map((classDef) { - return _buildClassTab(classDef); - }).toList(), - ), - ), - ], - ), - ); - } - - Widget _buildSummaryHeader() { - final isMobile = context.isMobile; - return Container( - padding: EdgeInsets.all(isMobile ? 8 : 12), - color: Colors.blue.shade50, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - key: const Key('support_matrix_summary_row'), - children: [ - const Icon(Icons.analytics, color: Colors.blue), - const SizedBox(width: 8), - Flexible( - child: Text( - 'Total APIs: ${_summary.totalApis}', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: isMobile ? 14 : 16, - ), - ), - ), - const SizedBox(width: 8), - Flexible( - child: Text( - '(${_summary.totalMethods} methods, ${_summary.totalEvents} events)', - style: TextStyle( - color: Colors.grey.shade700, - fontSize: isMobile ? 12 : 14, - ), - ), - ), - ], - ), - const SizedBox(height: 8), - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - children: SupportedPlatform.values.map((platform) { - final total = _summary.totalApisForPlatform(platform); - final percentage = (_summary.totalApis > 0) - ? (total / _summary.totalApis * 100).toStringAsFixed(0) - : '0'; - return Container( - margin: const EdgeInsets.only(right: 8), - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 6, - ), - decoration: BoxDecoration( - color: platform.color.withOpacity(0.1), - borderRadius: BorderRadius.circular(16), - border: Border.all(color: platform.color.withOpacity(0.3)), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(platform.icon, size: 16, color: platform.color), - const SizedBox(width: 4), - Text( - '$total ($percentage%)', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: platform.color, - ), - ), - ], - ), - ); - }).toList(), - ), - ), - ], - ), - ); - } - - Widget _buildSearchAndFilters() { - final isMobile = context.isMobile; - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - children: [ - // Search field - TextField( - controller: _searchController, - decoration: InputDecoration( - hintText: 'Search APIs...', - prefixIcon: const Icon(Icons.search), - suffixIcon: _searchQuery.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear), - onPressed: () { - _searchController.clear(); - setState(() => _searchQuery = ''); - }, - ) - : null, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - isDense: true, - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 12, - ), - ), - onChanged: (value) => setState(() => _searchQuery = value), - ), - const SizedBox(height: 8), - - // Platform filters - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - children: [ - const Text( - 'Filter by platform: ', - style: TextStyle(fontSize: 12), - ), - ...SupportedPlatform.values.map((platform) { - final isSelected = _selectedPlatforms.contains(platform); - return Padding( - padding: const EdgeInsets.only(right: 4), - child: FilterChip( - selected: isSelected, - label: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - platform.icon, - size: 14, - color: isSelected ? Colors.white : platform.color, - ), - const SizedBox(width: 4), - Text( - platform.displayName, - style: TextStyle( - fontSize: 11, - color: isSelected ? Colors.white : null, - ), - ), - ], - ), - selectedColor: platform.color, - checkmarkColor: Colors.white, - onSelected: (selected) { - setState(() { - if (selected) { - _selectedPlatforms.add(platform); - } else { - _selectedPlatforms.remove(platform); - } - }); - }, - ), - ); - }), - if (_selectedPlatforms.isNotEmpty) - TextButton( - onPressed: () => setState(() => _selectedPlatforms.clear()), - child: const Text('Clear', style: TextStyle(fontSize: 11)), - ), - ], - ), - ), - const SizedBox(height: 4), - - // Additional filters - always in a row - Wrap( - spacing: 8, - runSpacing: 8, - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - FilterChip( - selected: _showMethods, - label: Text( - 'Methods', - style: TextStyle(fontSize: isMobile ? 10 : 11), - ), - onSelected: (v) => setState(() => _showMethods = v), - ), - FilterChip( - selected: _showEvents, - label: Text( - 'Events', - style: TextStyle(fontSize: isMobile ? 10 : 11), - ), - onSelected: (v) => setState(() => _showEvents = v), - ), - FilterChip( - selected: _showOnlySupported, - label: Text( - 'Only supported', - style: TextStyle(fontSize: isMobile ? 10 : 11), - ), - onSelected: (v) => setState(() => _showOnlySupported = v), - ), - ], - ), - ], - ), - ); - } - - Widget _buildClassTab(ApiClassDefinition classDef) { - final isMobile = context.isMobile; - final filteredMethods = _getFilteredMethods(classDef); - final filteredEvents = _getFilteredEvents(classDef); - final classSupportedPlatforms = - SupportChecker.getSupportedPlatformsForClass(classDef.className); - - if (filteredMethods.isEmpty && filteredEvents.isEmpty) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.search_off, size: 64, color: Colors.grey.shade400), - const SizedBox(height: 16), - Text( - 'No APIs match your filters', - style: TextStyle(color: Colors.grey.shade600, fontSize: 16), - ), - ], - ), - ); - } - - return ListView( - padding: const EdgeInsets.all(8), - children: [ - // Class header - Card( - color: Colors.blue.shade50, - child: Padding( - padding: EdgeInsets.all(isMobile ? 8 : 12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ResponsiveRow( - spacing: 8, - runSpacing: 8, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - classDef.className, - style: TextStyle( - fontSize: isMobile ? 16 : 18, - fontWeight: FontWeight.bold, - ), - ), - if (isMobile) - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SupportBadgesRow( - supportedPlatforms: classSupportedPlatforms, - compact: true, - ), - ) - else - Flexible( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SupportBadgesRow( - supportedPlatforms: classSupportedPlatforms, - compact: true, - ), - ), - ), - ], - ), - if (classDef.description.isNotEmpty) ...[ - const SizedBox(height: 4), - Text( - classDef.description, - style: TextStyle(color: Colors.grey.shade700, fontSize: 13), - ), - ], - const SizedBox(height: 8), - Text( - 'Showing ${filteredMethods.length} methods, ${filteredEvents.length} events', - style: TextStyle(color: Colors.grey.shade600, fontSize: 12), - ), - ], - ), - ), - ), - - // Methods - if (filteredMethods.isNotEmpty) ...[ - const Padding( - padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8), - child: Text( - 'METHODS', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Colors.grey, - ), - ), - ), - ...filteredMethods.map( - (method) => _buildApiRow( - name: method.name, - description: method.description, - supportedPlatforms: SupportChecker.getSupportedPlatformsForMethod( - classDef.className, - method.name, - ), - signature: method.signature, - isStatic: method.isStatic, - isDeprecated: method.isDeprecated, - category: method.category, - isMethod: true, - ), - ), - ], - - // Events - if (filteredEvents.isNotEmpty) ...[ - const Padding( - padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8), - child: Text( - 'EVENTS', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Colors.grey, - ), - ), - ), - ...filteredEvents.map( - (event) => _buildApiRow( - name: event.name, - description: event.description, - supportedPlatforms: SupportChecker.getSupportedPlatformsForEvent( - classDef.className, - event.name, - ), - signature: event.signature, - category: event.category, - isMethod: false, - ), - ), - ], - ], - ); - } - - Widget _buildApiRow({ - required String name, - required String description, - required Set supportedPlatforms, - String? signature, - bool isStatic = false, - bool isDeprecated = false, - String? category, - required bool isMethod, - }) { - final isMobile = context.isMobile; - return Card( - margin: EdgeInsets.symmetric(horizontal: isMobile ? 2 : 4, vertical: 2), - child: ExpansionTile( - tilePadding: EdgeInsets.symmetric( - horizontal: isMobile ? 8 : 12, - vertical: 0, - ), - childrenPadding: EdgeInsets.fromLTRB( - isMobile ? 8 : 12, - 0, - isMobile ? 8 : 12, - isMobile ? 8 : 12, - ), - title: Row( - children: [ - Expanded( - child: Row( - children: [ - Icon( - isMethod ? Icons.functions : Icons.bolt, - size: isMobile ? 14 : 16, - color: isMethod ? Colors.blue : Colors.orange, - ), - const SizedBox(width: 8), - Flexible( - child: Text( - name, - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: isMobile ? 12 : 13, - decoration: isDeprecated - ? TextDecoration.lineThrough - : null, - ), - overflow: TextOverflow.ellipsis, - ), - ), - if (isStatic) ...[ - const SizedBox(width: 4), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 4, - vertical: 1, - ), - decoration: BoxDecoration( - color: Colors.purple.shade100, - borderRadius: BorderRadius.circular(2), - ), - child: const Text( - 'static', - style: TextStyle(fontSize: 9, color: Colors.purple), - ), - ), - ], - if (category != null) ...[ - const SizedBox(width: 4), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 4, - vertical: 1, - ), - decoration: BoxDecoration( - color: Colors.grey.shade200, - borderRadius: BorderRadius.circular(2), - ), - child: Text( - category, - style: TextStyle( - fontSize: 9, - color: Colors.grey.shade700, - ), - ), - ), - ], - ], - ), - ), - ], - ), - subtitle: Padding( - padding: const EdgeInsets.only(top: 4), - child: SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - ), - children: [ - if (description.isNotEmpty) - Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Text( - description, - style: TextStyle(color: Colors.grey.shade700, fontSize: 13), - ), - ), - if (signature != null && signature.isNotEmpty) - Container( - width: double.infinity, - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.grey.shade100, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - signature, - style: TextStyle( - fontFamily: 'monospace', - fontSize: 11, - color: Colors.grey.shade800, - ), - ), - ), - ], - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/screens/test_automation/test_configuration_screen.dart b/flutter_inappwebview/example/lib/screens/test_automation/test_configuration_screen.dart deleted file mode 100644 index cad2980cb8..0000000000 --- a/flutter_inappwebview/example/lib/screens/test_automation/test_configuration_screen.dart +++ /dev/null @@ -1,1256 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import '../../models/test_configuration.dart'; -import '../../utils/constants.dart'; -import '../../widgets/common/app_drawer.dart'; -import '../../widgets/test_automation/custom_test_step_dialog.dart'; - -/// Screen for managing test configurations, custom steps, and test ordering -class TestConfigurationScreen extends StatefulWidget { - const TestConfigurationScreen({super.key}); - - @override - State createState() => - _TestConfigurationScreenState(); -} - -class _TestConfigurationScreenState extends State - with SingleTickerProviderStateMixin { - late final TabController _tabController; - final TextEditingController _importController = TextEditingController(); - final TextEditingController _searchController = TextEditingController(); - String _searchQuery = ''; - - @override - void initState() { - super.initState(); - _tabController = TabController(length: 3, vsync: this); - } - - @override - void dispose() { - _tabController.dispose(); - _importController.dispose(); - _searchController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return LayoutBuilder( - builder: (context, constraints) { - final isNarrow = constraints.maxWidth < 600; - return Consumer( - builder: (context, manager, child) => Scaffold( - appBar: AppBar( - title: const Text('Test Configuration'), - backgroundColor: Colors.blue, - foregroundColor: Colors.white, - bottom: TabBar( - controller: _tabController, - indicatorColor: Colors.white, - labelColor: Colors.white, - unselectedLabelColor: Colors.white70, - isScrollable: isNarrow, - tabs: const [ - Tab(icon: Icon(Icons.edit_note), text: 'Custom Steps'), - Tab(icon: Icon(Icons.settings), text: 'Settings'), - Tab(icon: Icon(Icons.import_export), text: 'Import/Export'), - ], - ), - actions: [ - IconButton( - icon: const Icon(Icons.save), - tooltip: 'Save Configuration', - onPressed: () => _saveConfiguration(context, manager), - ), - PopupMenuButton( - icon: const Icon(Icons.more_vert), - onSelected: (action) => - _handleMenuAction(context, action, manager), - itemBuilder: (context) => [ - const PopupMenuItem( - value: 'new', - child: ListTile( - leading: Icon(Icons.add), - title: Text('New Configuration'), - contentPadding: EdgeInsets.zero, - ), - ), - const PopupMenuItem( - value: 'load', - child: ListTile( - leading: Icon(Icons.folder_open), - title: Text('Load Configuration'), - contentPadding: EdgeInsets.zero, - ), - ), - const PopupMenuDivider(), - const PopupMenuItem( - value: 'reset', - child: ListTile( - leading: Icon(Icons.restart_alt, color: Colors.orange), - title: Text('Reset to Default'), - contentPadding: EdgeInsets.zero, - ), - ), - ], - ), - ], - ), - drawer: AppDrawer(), - body: TabBarView( - controller: _tabController, - children: [ - _buildCustomStepsTab(manager), - _buildSettingsTab(manager), - _buildImportExportTab(manager), - ], - ), - ), - ); - }, - ); - } - - Widget _buildCustomStepsTab(TestConfigurationManager manager) { - final allSteps = manager.currentConfig.customSteps; - final filteredSteps = _searchQuery.isEmpty - ? allSteps - : allSteps - .where( - (step) => - step.name.toLowerCase().contains(_searchQuery) || - step.description.toLowerCase().contains(_searchQuery), - ) - .toList(); - - return Column( - children: [ - _buildConfigHeader(manager), - _buildSearchBar(allSteps.length, filteredSteps.length), - Expanded( - child: filteredSteps.isEmpty - ? _buildEmptyStepsMessage( - isFiltered: _searchQuery.isNotEmpty && allSteps.isNotEmpty, - ) - : _buildStepsList(manager, filteredSteps, allSteps), - ), - ], - ); - } - - Widget _buildSearchBar(int totalCount, int filteredCount) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - decoration: BoxDecoration( - color: Colors.white, - border: Border(bottom: BorderSide(color: Colors.grey.shade200)), - ), - child: Row( - children: [ - Expanded( - child: TextField( - controller: _searchController, - decoration: InputDecoration( - hintText: 'Search custom steps...', - prefixIcon: const Icon(Icons.search, size: 20), - suffixIcon: _searchQuery.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear, size: 20), - onPressed: () { - _searchController.clear(); - setState(() => _searchQuery = ''); - }, - ) - : null, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide(color: Colors.grey.shade300), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - isDense: true, - ), - onChanged: (value) { - setState(() => _searchQuery = value.toLowerCase()); - }, - ), - ), - if (_searchQuery.isNotEmpty) ...[ - const SizedBox(width: 12), - Text( - '$filteredCount of $totalCount', - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - ], - ], - ), - ); - } - - Widget _buildConfigHeader(TestConfigurationManager manager) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.blue.shade50, - border: Border(bottom: BorderSide(color: Colors.blue.shade200)), - ), - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - manager.currentConfig.name, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - if (manager.currentConfig.description.isNotEmpty) - Text( - manager.currentConfig.description, - style: TextStyle(color: Colors.grey.shade600), - ), - Text( - '${manager.currentConfig.customSteps.length} custom step(s)', - style: TextStyle(color: Colors.grey.shade500, fontSize: 12), - ), - ], - ), - ), - ElevatedButton.icon( - icon: const Icon(Icons.add), - label: const Text('Add Step'), - onPressed: () => _showAddStepDialog(context, manager), - ), - ], - ), - ); - } - - Widget _buildEmptyStepsMessage({bool isFiltered = false}) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - isFiltered ? Icons.search_off : Icons.playlist_add, - size: 64, - color: Colors.grey.shade400, - ), - const SizedBox(height: 16), - Text( - isFiltered ? 'No Matching Steps' : 'No Custom Test Steps', - style: TextStyle(fontSize: 18, color: Colors.grey.shade600), - ), - const SizedBox(height: 8), - Text( - isFiltered - ? 'Try a different search term' - : 'Click "Add Step" to create your first custom test', - style: TextStyle(color: Colors.grey.shade500), - ), - ], - ), - ); - } - - Widget _buildStepsList( - TestConfigurationManager manager, - List filteredSteps, - List allSteps, - ) { - // When filtering, disable reordering to avoid index confusion - final isFiltering = _searchQuery.isNotEmpty; - - if (isFiltering) { - // Use regular ListView when filtering (no reordering) - return ListView.builder( - padding: const EdgeInsets.all(8), - itemCount: filteredSteps.length, - itemBuilder: (context, index) { - final step = filteredSteps[index]; - return _buildStepCard( - context, - manager, - step, - index, - canReorder: false, - ); - }, - ); - } - - return ReorderableListView.builder( - padding: const EdgeInsets.all(8), - buildDefaultDragHandles: false, - itemCount: filteredSteps.length, - onReorder: (oldIndex, newIndex) { - manager.reorderCustomSteps(oldIndex, newIndex); - }, - itemBuilder: (context, index) { - final step = filteredSteps[index]; - return _buildStepCard(context, manager, step, index, canReorder: true); - }, - ); - } - - Widget _buildSettingsTab(TestConfigurationManager manager) { - final config = manager.currentConfig; - - return SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // WebView Type Selection - Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.web, color: Colors.blue.shade700), - const SizedBox(width: 8), - const Text( - 'WebView Type', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - 'Choose how the WebView should be rendered during tests', - style: TextStyle(color: Colors.grey.shade600), - ), - const SizedBox(height: 16), - RadioListTile( - title: Text('${InAppWebView} (Visible)'), - subtitle: const Text( - 'Display WebView in real-time during test execution', - ), - value: TestWebViewType.inAppWebView, - groupValue: config.webViewType, - onChanged: (value) { - if (value != null) { - manager.setWebViewType(value); - } - }, - ), - RadioListTile( - title: const Text('Headless WebView'), - subtitle: const Text( - 'Run tests in background without visible rendering', - ), - value: TestWebViewType.headless, - groupValue: config.webViewType, - onChanged: (value) { - if (value != null) { - manager.setWebViewType(value); - } - }, - ), - ], - ), - ), - ), - const SizedBox(height: 16), - - // Initial URL - Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.link, color: Colors.green.shade700), - const SizedBox(width: 8), - const Text( - 'Initial URL', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - 'URL to load before running tests (optional)', - style: TextStyle(color: Colors.grey.shade600), - ), - const SizedBox(height: 12), - TextField( - controller: TextEditingController( - text: config.initialUrl ?? '', - ), - decoration: const InputDecoration( - labelText: 'Initial URL', - hintText: 'https://example.com', - border: OutlineInputBorder(), - ), - onChanged: (value) { - manager.setInitialUrl(value.isEmpty ? null : value); - }, - ), - ], - ), - ), - ), - const SizedBox(height: 16), - - // Headless WebView Size (only shown when headless is selected) - if (config.webViewType == TestWebViewType.headless) - Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.aspect_ratio, color: Colors.purple.shade700), - const SizedBox(width: 8), - const Text( - 'Headless WebView Size', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - 'Set the virtual viewport size for the headless WebView', - style: TextStyle(color: Colors.grey.shade600), - ), - const SizedBox(height: 16), - Row( - children: [ - Expanded( - child: TextField( - controller: TextEditingController( - text: config.headlessWidth.toInt().toString(), - ), - decoration: const InputDecoration( - labelText: 'Width (px)', - hintText: '1920', - border: OutlineInputBorder(), - suffixText: 'px', - ), - keyboardType: TextInputType.number, - onChanged: (value) { - final width = double.tryParse(value); - if (width != null && width > 0) { - manager.setHeadlessSize( - width, - config.headlessHeight, - ); - } - }, - ), - ), - const SizedBox(width: 16), - Expanded( - child: TextField( - controller: TextEditingController( - text: config.headlessHeight.toInt().toString(), - ), - decoration: const InputDecoration( - labelText: 'Height (px)', - hintText: '1080', - border: OutlineInputBorder(), - suffixText: 'px', - ), - keyboardType: TextInputType.number, - onChanged: (value) { - final height = double.tryParse(value); - if (height != null && height > 0) { - manager.setHeadlessSize( - config.headlessWidth, - height, - ); - } - }, - ), - ), - ], - ), - const SizedBox(height: 12), - // Quick preset sizes - Wrap( - spacing: 8, - runSpacing: 8, - children: [ - _buildSizePresetChip( - manager, - config, - 'Mobile', - 375, - 667, - ), - _buildSizePresetChip( - manager, - config, - 'Tablet', - 768, - 1024, - ), - _buildSizePresetChip( - manager, - config, - 'Desktop', - 1920, - 1080, - ), - _buildSizePresetChip(manager, config, '4K', 3840, 2160), - ], - ), - ], - ), - ), - ), - if (config.webViewType == TestWebViewType.headless) - const SizedBox(height: 16), - - // Default Configuration - Card( - color: Colors.blue.shade50, - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon( - Icons.playlist_add_check, - color: Colors.blue.shade700, - ), - const SizedBox(width: 8), - const Text( - 'Default Configuration', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - 'Load a pre-built configuration with common test scenarios including navigation, JavaScript execution, security checks, and more.', - style: TextStyle(color: Colors.grey.shade700), - ), - const SizedBox(height: 12), - ElevatedButton.icon( - icon: const Icon(Icons.download), - label: const Text('Load Default Configuration'), - onPressed: () => _loadDefaultConfig(manager), - ), - ], - ), - ), - ), - ], - ), - ); - } - - Widget _buildSizePresetChip( - TestConfigurationManager manager, - TestConfiguration config, - String label, - double width, - double height, - ) { - final isSelected = - config.headlessWidth == width && config.headlessHeight == height; - return FilterChip( - label: Text('$label (${width.toInt()}×${height.toInt()})'), - selected: isSelected, - onSelected: (_) { - manager.setHeadlessSize(width, height); - }, - ); - } - - void _loadDefaultConfig(TestConfigurationManager manager) { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Load Default Configuration?'), - content: const Text( - 'This will replace your current configuration with the default test suite. ' - 'Any unsaved changes will be lost.', - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: () { - final defaultConfig = TestConfiguration.defaultConfig(); - manager.importConfig(defaultConfig.toJsonString()); - Navigator.pop(context); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Default configuration loaded')), - ); - _tabController.animateTo(0); - }, - child: const Text('Load Default'), - ), - ], - ), - ); - } - - Widget _buildStepCard( - BuildContext context, - TestConfigurationManager manager, - CustomTestStep step, - int index, { - bool canReorder = true, - }) { - return Card( - key: ValueKey(step.id), - margin: const EdgeInsets.symmetric(vertical: 4), - elevation: 1, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), - child: Row( - children: [ - // Drag handle (only when reordering is enabled) - if (canReorder) - ReorderableDragStartListener( - index: index, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: MouseRegion( - cursor: SystemMouseCursors.grab, - child: Icon( - Icons.drag_handle, - color: Colors.grey.shade400, - size: 20, - ), - ), - ), - ) - else - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: Icon(Icons.label, color: Colors.grey.shade400, size: 20), - ), - // Step content - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - step.name, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 15, - decoration: step.enabled - ? null - : TextDecoration.lineThrough, - color: step.enabled ? null : Colors.grey, - ), - ), - const SizedBox(height: 2), - Text( - step.description.isNotEmpty - ? step.description - : 'No description', - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 6), - Wrap( - spacing: 6, - runSpacing: 4, - children: [ - _buildChip(step.category.name, Colors.blue), - _buildChip( - _getActionTypeName(step.action.type), - Colors.green, - ), - ], - ), - ], - ), - ), - // Actions - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Transform.scale( - scale: 0.85, - child: Switch( - value: step.enabled, - onChanged: (value) { - manager.updateCustomStep( - step.id, - step.copyWith(enabled: value), - ); - }, - ), - ), - IconButton( - icon: const Icon(Icons.edit_outlined, size: 20), - tooltip: 'Edit', - onPressed: () => _showEditStepDialog(context, manager, step), - visualDensity: VisualDensity.compact, - ), - IconButton( - icon: Icon( - Icons.delete_outline, - size: 20, - color: Colors.red.shade400, - ), - tooltip: 'Delete', - onPressed: () => _confirmDeleteStep(context, manager, step), - visualDensity: VisualDensity.compact, - ), - ], - ), - ], - ), - ), - ); - } - - Widget _buildChip(String label, Color color) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), - decoration: BoxDecoration( - color: color.withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - border: Border.all(color: color.withOpacity(0.3)), - ), - child: Text(label, style: TextStyle(fontSize: 10, color: color)), - ); - } - - Widget _buildImportExportTab(TestConfigurationManager manager) { - return SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Export section - Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.upload, color: Colors.blue.shade700), - const SizedBox(width: 8), - const Text( - 'Export Configuration', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - 'Export your current test configuration as JSON', - style: TextStyle(color: Colors.grey.shade600), - ), - const SizedBox(height: 12), - Row( - children: [ - ElevatedButton.icon( - icon: const Icon(Icons.copy), - label: const Text('Copy to Clipboard'), - onPressed: () => _exportToClipboard(context, manager), - ), - const SizedBox(width: 8), - OutlinedButton.icon( - icon: const Icon(Icons.visibility), - label: const Text('Preview JSON'), - onPressed: () => _showJsonPreview(context, manager), - ), - ], - ), - ], - ), - ), - ), - const SizedBox(height: 16), - - // Import section - Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.download, color: Colors.green.shade700), - const SizedBox(width: 8), - const Text( - 'Import Configuration', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - 'Paste JSON configuration to import', - style: TextStyle(color: Colors.grey.shade600), - ), - const SizedBox(height: 12), - TextField( - controller: _importController, - decoration: const InputDecoration( - labelText: 'Paste JSON here', - border: OutlineInputBorder(), - hintText: '{"id": "...", "name": "...", ...}', - ), - maxLines: 8, - style: const TextStyle( - fontFamily: 'monospace', - fontSize: 12, - ), - ), - const SizedBox(height: 12), - Row( - children: [ - ElevatedButton.icon( - icon: const Icon(Icons.file_download), - label: const Text('Import'), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.green, - foregroundColor: Colors.white, - ), - onPressed: () => _importConfig(context, manager), - ), - const SizedBox(width: 8), - TextButton.icon( - icon: const Icon(Icons.paste), - label: const Text('Paste from Clipboard'), - onPressed: () => _pasteFromClipboard(), - ), - ], - ), - ], - ), - ), - ), - const SizedBox(height: 16), - - // Sample configuration - Card( - color: Colors.amber.shade50, - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.lightbulb, color: Colors.amber.shade700), - const SizedBox(width: 8), - const Text( - 'Sample Configuration', - style: TextStyle(fontWeight: FontWeight.bold), - ), - ], - ), - const SizedBox(height: 8), - Text( - 'Click below to load a sample configuration with example custom tests.', - style: TextStyle(color: Colors.grey.shade700), - ), - const SizedBox(height: 8), - OutlinedButton( - onPressed: () => _loadSampleConfig(manager), - child: const Text('Load Sample'), - ), - ], - ), - ), - ), - ], - ), - ); - } - - void _showAddStepDialog( - BuildContext context, - TestConfigurationManager manager, - ) { - showDialog( - context: context, - builder: (context) => - CustomTestStepDialog(onSave: (step) => manager.addCustomStep(step)), - ); - } - - void _showEditStepDialog( - BuildContext context, - TestConfigurationManager manager, - CustomTestStep step, - ) { - showDialog( - context: context, - builder: (context) => CustomTestStepDialog( - existingStep: step, - onSave: (updatedStep) => manager.updateCustomStep(step.id, updatedStep), - ), - ); - } - - void _confirmDeleteStep( - BuildContext context, - TestConfigurationManager manager, - CustomTestStep step, - ) { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Delete Test Step?'), - content: Text('Are you sure you want to delete "${step.name}"?'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), - ), - ElevatedButton( - style: ElevatedButton.styleFrom(backgroundColor: Colors.red), - onPressed: () { - manager.removeCustomStep(step.id); - Navigator.pop(context); - }, - child: const Text('Delete'), - ), - ], - ), - ); - } - - void _saveConfiguration( - BuildContext context, - TestConfigurationManager manager, - ) { - showDialog( - context: context, - builder: (dialogContext) { - final nameController = TextEditingController( - text: manager.currentConfig.name, - ); - return AlertDialog( - title: const Text('Save Configuration'), - content: TextField( - controller: nameController, - decoration: const InputDecoration( - labelText: 'Configuration Name', - border: OutlineInputBorder(), - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(dialogContext), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: () { - manager.saveCurrentConfig(name: nameController.text); - Navigator.pop(dialogContext); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Configuration saved')), - ); - }, - child: const Text('Save'), - ), - ], - ); - }, - ); - } - - void _handleMenuAction( - BuildContext context, - String action, - TestConfigurationManager manager, - ) { - switch (action) { - case 'new': - manager.resetConfig(); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('New configuration created')), - ); - break; - case 'load': - _showLoadDialog(context, manager); - break; - case 'reset': - _confirmReset(context, manager); - break; - } - } - - void _showLoadDialog(BuildContext context, TestConfigurationManager manager) { - if (manager.savedConfigs.isEmpty) { - ScaffoldMessenger.of( - context, - ).showSnackBar(const SnackBar(content: Text('No saved configurations'))); - return; - } - - showDialog( - context: context, - builder: (dialogContext) => StatefulBuilder( - builder: (context, setDialogState) { - final configs = manager.savedConfigs; - if (configs.isEmpty) { - Navigator.pop(dialogContext); - return const SizedBox.shrink(); - } - return AlertDialog( - title: const Text('Load Configuration'), - content: SizedBox( - width: 400, - child: ListView.builder( - shrinkWrap: true, - itemCount: configs.length, - itemBuilder: (context, index) { - final config = configs[index]; - return ListTile( - title: Text(config.name), - subtitle: Text( - '${config.customSteps.length} steps • Modified: ${_formatDate(config.modifiedAt)}', - ), - onTap: () { - manager.loadConfig(config.id); - Navigator.pop(dialogContext); - }, - trailing: IconButton( - icon: const Icon(Icons.delete, size: 20), - onPressed: () { - manager.deleteConfig(config.id); - setDialogState( - () {}, - ); // Rebuild dialog to reflect deletion - if (manager.savedConfigs.isEmpty) { - Navigator.pop(dialogContext); - } - }, - ), - ); - }, - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(dialogContext), - child: const Text('Cancel'), - ), - ], - ); - }, - ), - ); - } - - void _confirmReset(BuildContext context, TestConfigurationManager manager) { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Reset Configuration?'), - content: const Text( - 'This will clear all custom steps and reset to default settings.', - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), - ), - ElevatedButton( - style: ElevatedButton.styleFrom(backgroundColor: Colors.orange), - onPressed: () { - manager.resetConfig(); - Navigator.pop(context); - }, - child: const Text('Reset'), - ), - ], - ), - ); - } - - void _exportToClipboard( - BuildContext context, - TestConfigurationManager manager, - ) { - final json = manager.exportConfig(); - Clipboard.setData(ClipboardData(text: json)); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Configuration copied to clipboard')), - ); - } - - void _showJsonPreview( - BuildContext context, - TestConfigurationManager manager, - ) { - final json = manager.exportConfig(); - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('JSON Preview'), - content: SizedBox( - width: 500, - height: 400, - child: SingleChildScrollView( - child: SelectableText( - json, - style: const TextStyle(fontFamily: 'monospace', fontSize: 12), - ), - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Close'), - ), - ElevatedButton.icon( - icon: const Icon(Icons.copy), - label: const Text('Copy'), - onPressed: () { - Clipboard.setData(ClipboardData(text: json)); - Navigator.pop(context); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Copied to clipboard')), - ); - }, - ), - ], - ), - ); - } - - void _importConfig(BuildContext context, TestConfigurationManager manager) { - final json = _importController.text.trim(); - if (json.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Please paste JSON configuration first')), - ); - return; - } - - try { - manager.importConfig(json); - _importController.clear(); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Configuration imported successfully')), - ); - _tabController.animateTo(0); // Switch to custom steps tab - } catch (e) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Import failed: ${e.toString()}'), - backgroundColor: Colors.red, - ), - ); - } - } - - Future _pasteFromClipboard() async { - final data = await Clipboard.getData(Clipboard.kTextPlain); - if (data?.text != null) { - _importController.text = data!.text!; - } - } - - void _loadSampleConfig(TestConfigurationManager manager) { - final sample = TestConfiguration( - id: 'sample_config', - name: 'Sample Test Configuration', - description: 'A sample configuration with example custom tests', - createdAt: DateTime.now(), - modifiedAt: DateTime.now(), - customSteps: [ - CustomTestStep( - id: 'sample_step_1', - name: 'Check Page Title', - description: 'Verify the page title contains expected text', - category: TestCategory.content, - action: CustomTestAction.evaluateJs('document.title'), - expectedResult: 'Flutter', - order: 0, - ), - CustomTestStep( - id: 'sample_step_2', - name: 'Wait for Element', - description: 'Wait for the main content to load', - category: TestCategory.content, - action: CustomTestAction.waitForElement('body', timeoutMs: 5000), - order: 1, - ), - CustomTestStep( - id: 'sample_step_3', - name: 'Check Element Exists', - description: 'Verify a specific element is present', - category: TestCategory.content, - action: CustomTestAction.checkElement('a[href]'), - order: 2, - ), - CustomTestStep( - id: 'sample_step_4', - name: 'Execute Custom JS', - description: 'Run custom JavaScript and return result', - category: TestCategory.javascript, - action: CustomTestAction.evaluateJs( - 'document.querySelectorAll("a").length', - ), - order: 3, - ), - ], - ); - - manager.importConfig(sample.toJsonString()); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Sample configuration loaded')), - ); - _tabController.animateTo(0); - } - - String _getActionTypeName(CustomTestActionType type) { - return type.name - .replaceAllMapped(RegExp(r'([A-Z])'), (m) => ' ${m.group(1)}') - .trim(); - } - - String _formatDate(DateTime date) { - return '${date.month}/${date.day}/${date.year}'; - } -} diff --git a/flutter_inappwebview/example/lib/screens/test_automation/test_runner_screen.dart b/flutter_inappwebview/example/lib/screens/test_automation/test_runner_screen.dart deleted file mode 100644 index 774273bfc4..0000000000 --- a/flutter_inappwebview/example/lib/screens/test_automation/test_runner_screen.dart +++ /dev/null @@ -1,1104 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/foundation.dart'; -import 'package:provider/provider.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -import '../../models/test_configuration.dart'; -import '../../models/test_runner_models.dart'; -import '../../providers/test_runner.dart'; -import '../../widgets/common/app_drawer.dart'; - -/// Automated test runner screen -class TestRunnerScreen extends StatefulWidget { - const TestRunnerScreen({super.key}); - - @override - State createState() => _TestRunnerScreenState(); -} - -class _TestRunnerScreenState extends State { - static const String _lastConfigKey = 'test_runner_last_config'; - static const String _lastWebViewTypeKey = 'test_runner_last_webview_type'; - static const ValueKey _panelLayoutKey = ValueKey('testRunnerPanels'); - static const ValueKey _controlBarWrapKey = ValueKey( - 'testRunnerControlBarWrap', - ); - - ResultFilter _resultFilter = ResultFilter.all; - - // Custom configuration support - TestConfiguration? _currentConfiguration; - bool _configManagerInitialized = false; - - // Flag to prevent loading config multiple times - bool _configLoaded = false; - - @override - void initState() { - super.initState(); - // Defer loading last configuration until after the first frame - WidgetsBinding.instance.addPostFrameCallback((_) { - _loadLastConfiguration(); - }); - } - - Future _loadLastConfiguration() async { - if (_configLoaded) return; - _configLoaded = true; - - final prefs = await SharedPreferences.getInstance(); - final configManager = context.read(); - if (!_configManagerInitialized) { - await configManager.init(); - _configManagerInitialized = true; - } - final lastConfigJson = prefs.getString(_lastConfigKey); - final lastWebViewType = prefs.getString(_lastWebViewTypeKey); - - final runner = context.read(); - - if (lastWebViewType != null) { - final webViewType = TestWebViewType.values.firstWhere( - (e) => e.name == lastWebViewType, - orElse: () => TestWebViewType.inAppWebView, - ); - runner.setWebViewType(webViewType); - } - - TestConfiguration? configToLoad; - - // First choice: the last used configuration snapshot (represents what the user ran last) - if (lastConfigJson != null && lastConfigJson.isNotEmpty) { - try { - final parsedConfig = TestConfiguration.fromJsonString(lastConfigJson); - if (parsedConfig.id == 'default_config') { - // Always rebuild the pre-built configuration from code - configToLoad = TestConfiguration.defaultConfig(); - } else { - configToLoad = parsedConfig; - - // Use a fresher saved version if it exists - try { - final freshConfig = configManager.savedConfigs.firstWhere( - (c) => c.id == configToLoad!.id, - ); - configToLoad = freshConfig; - } catch (_) { - // Not found in saved configs - } - } - } catch (e) { - debugPrint('Failed to parse last configuration: $e'); - } - } - - // Always fall back to the pre-built default when no last snapshot is available - configToLoad ??= TestConfiguration.defaultConfig(); - - if (mounted) { - setState(() { - _currentConfiguration = configToLoad; - }); - runner.setConfiguration(configToLoad); - await _saveLastConfiguration(); - } - } - - Future _saveLastConfiguration() async { - final prefs = await SharedPreferences.getInstance(); - final runner = context.read(); - final config = _currentConfiguration; - if (config == null || config.id == 'default_config') { - await prefs.remove(_lastConfigKey); - } else { - await prefs.setString(_lastConfigKey, config.toJsonString()); - } - await prefs.setString(_lastWebViewTypeKey, runner.webViewType.name); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Test Runner'), - backgroundColor: Colors.blue, - foregroundColor: Colors.white, - actions: [ - IconButton( - icon: const Icon(Icons.settings), - tooltip: 'Load Configuration', - onPressed: _showConfigurationDialog, - ), - PopupMenuButton( - icon: const Icon(Icons.more_vert), - onSelected: _handleMenuAction, - itemBuilder: (context) => [ - const PopupMenuItem( - value: 'export_json', - child: ListTile( - leading: Icon(Icons.code), - title: Text('Export as JSON'), - contentPadding: EdgeInsets.zero, - ), - ), - const PopupMenuDivider(), - const PopupMenuItem( - value: 'clear', - child: ListTile( - leading: Icon(Icons.clear_all), - title: Text('Clear Results'), - contentPadding: EdgeInsets.zero, - ), - ), - ], - ), - ], - ), - drawer: AppDrawer(), - body: LayoutBuilder( - builder: (context, constraints) { - final isNarrow = constraints.maxWidth < 600; - return Consumer( - builder: (context, runner, child) { - final panelChildren = [ - if (runner.webViewType == TestWebViewType.inAppWebView) - Flexible( - key: const ValueKey('testRunnerWebViewPanel'), - flex: 1, - child: Container( - margin: const EdgeInsets.all(8), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey.shade300), - borderRadius: BorderRadius.circular(8), - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(8), - child: _buildVisibleWebView(runner), - ), - ), - ), - Flexible( - key: const ValueKey('testRunnerResultsPanel'), - flex: runner.webViewType == TestWebViewType.inAppWebView - ? 1 - : 2, - child: _buildResultsList(), - ), - ]; - - return Column( - children: [ - _buildConfigurationBanner(), - _buildWebViewTypeSelector(isNarrow: isNarrow), - _buildControlBar(isNarrow: isNarrow), - _buildProgressSection(), - _buildFilterBar(isNarrow: isNarrow), - Expanded( - child: Flex( - key: _panelLayoutKey, - direction: isNarrow ? Axis.vertical : Axis.horizontal, - children: panelChildren, - ), - ), - _buildSummaryBar(), - ], - ); - }, - ); - }, - ), - ); - } - - Widget _buildConfigurationBanner() { - final runner = context.read(); - final config = _currentConfiguration ?? TestConfiguration.defaultConfig(); - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.blue.shade50, - border: Border(bottom: BorderSide(color: Colors.blue.shade200)), - ), - child: Row( - children: [ - const Icon(Icons.tune, color: Colors.blue), - const SizedBox(width: 8), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Configuration: ${config.name}', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - Text( - '${config.customSteps.length} test steps • ' - '${config.webViewType == TestWebViewType.headless ? "Headless" : "Visible"} WebView', - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - ], - ), - ), - TextButton.icon( - icon: const Icon(Icons.refresh, size: 18), - label: const Text('Reset'), - onPressed: () { - setState(() { - _currentConfiguration = TestConfiguration.defaultConfig(); - }); - runner.setConfiguration(_currentConfiguration); - runner.setInitialUrl( - _currentConfiguration?.initialUrl ?? 'https://flutter.dev', - ); - // Clear saved configuration - _saveLastConfiguration(); - }, - ), - ], - ), - ); - } - - Widget _buildWebViewTypeSelector({required bool isNarrow}) { - return Consumer( - builder: (context, runner, child) { - final selector = SegmentedButton( - segments: const [ - ButtonSegment( - value: TestWebViewType.inAppWebView, - label: Text('Visible'), - icon: Icon(Icons.visibility, size: 18), - ), - ButtonSegment( - value: TestWebViewType.headless, - label: Text('Headless'), - icon: Icon(Icons.visibility_off, size: 18), - ), - ], - selected: {runner.webViewType}, - onSelectionChanged: (selection) { - runner.setWebViewType(selection.first); - _saveLastConfiguration(); - }, - ); - - final helperText = runner.webViewType == TestWebViewType.inAppWebView - ? Text( - 'Real-time rendering enabled', - style: TextStyle( - fontSize: 12, - color: Colors.green.shade700, - fontStyle: FontStyle.italic, - ), - ) - : null; - - return Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.white, - border: Border(bottom: BorderSide(color: Colors.grey.shade200)), - ), - child: isNarrow - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - const Text('WebView Mode: '), - const SizedBox(width: 8), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: selector, - ), - ), - ], - ), - if (helperText != null) ...[ - const SizedBox(height: 6), - helperText, - ], - ], - ) - : Row( - children: [ - const Text('WebView Mode: '), - const SizedBox(width: 8), - selector, - const Spacer(), - if (helperText != null) helperText, - ], - ), - ); - }, - ); - } - - Widget _buildVisibleWebView(TestRunner runner) { - return Column( - children: [ - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - color: Colors.grey.shade200, - child: Row( - children: [ - const Icon(Icons.web, size: 16), - const SizedBox(width: 4), - const Text('WebView Preview', style: TextStyle(fontSize: 12)), - const Spacer(), - if (runner.webViewReady) - Container( - padding: const EdgeInsets.symmetric( - horizontal: 6, - vertical: 2, - ), - decoration: BoxDecoration( - color: Colors.green, - borderRadius: BorderRadius.circular(4), - ), - child: const Text( - 'Ready', - style: TextStyle(color: Colors.white, fontSize: 10), - ), - ) - else - const SizedBox( - width: 12, - height: 12, - child: CircularProgressIndicator(strokeWidth: 2), - ), - ], - ), - ), - Expanded(child: runner.buildInAppWebView()), - ], - ); - } - - void _showConfigurationDialog() { - final configManager = context.read(); - final savedConfigs = configManager.savedConfigs; - final runner = context.read(); - - showDialog( - context: context, - builder: (dialogContext) => AlertDialog( - title: const Text('Load Test Configuration'), - content: SizedBox( - width: 400, - child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - leading: const Icon( - Icons.playlist_add_check, - color: Colors.blue, - ), - title: const Text('Load Default Configuration'), - subtitle: const Text('Pre-built tests for common scenarios'), - onTap: () { - Navigator.pop(dialogContext); - _loadConfiguration(TestConfiguration.defaultConfig()); - }, - ), - const Divider(), - // Show saved configurations if available - if (savedConfigs.isNotEmpty) ...[ - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 8, - ), - child: Row( - children: [ - Icon( - Icons.folder, - color: Colors.orange.shade700, - size: 18, - ), - const SizedBox(width: 8), - Text( - 'Saved Configurations (${savedConfigs.length})', - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.grey.shade700, - ), - ), - ], - ), - ), - ...savedConfigs.map( - (config) => ListTile( - leading: const Icon( - Icons.description, - color: Colors.orange, - ), - title: Text(config.name), - subtitle: Text( - '${config.customSteps.length} steps • ${config.webViewType == TestWebViewType.headless ? "Headless" : "Visible"} WebView', - ), - onTap: () { - Navigator.pop(dialogContext); - _loadConfiguration(config); - }, - ), - ), - const Divider(), - ], - ListTile( - leading: const Icon(Icons.paste, color: Colors.green), - title: const Text('Import from Clipboard'), - subtitle: const Text('Paste JSON configuration'), - onTap: () async { - Navigator.pop(dialogContext); - await _importFromClipboard(); - }, - ), - const Divider(), - ListTile( - leading: const Icon(Icons.restore, color: Colors.grey), - title: const Text('Reset to Default'), - subtitle: const Text('Load default test configuration'), - onTap: () { - Navigator.pop(dialogContext); - setState(() { - _currentConfiguration = TestConfiguration.defaultConfig(); - }); - runner.setConfiguration(_currentConfiguration); - runner.setInitialUrl( - _currentConfiguration?.initialUrl ?? - 'https://flutter.dev', - ); - // Save configuration - _saveLastConfiguration(); - }, - ), - ], - ), - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(dialogContext), - child: const Text('Cancel'), - ), - ], - ), - ); - } - - void _loadConfiguration(TestConfiguration config) { - final runner = context.read(); - final effectiveConfig = config.id == 'default_config' - ? TestConfiguration.defaultConfig() - : config; - setState(() { - _currentConfiguration = effectiveConfig; - }); - runner.setConfiguration(effectiveConfig); - // Save as last configuration - _saveLastConfiguration(); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - 'Configuration loaded: ${effectiveConfig.name} (${effectiveConfig.customSteps.length} test steps)', - ), - ), - ); - } - - Future _importFromClipboard() async { - try { - final data = await Clipboard.getData(Clipboard.kTextPlain); - final text = data?.text; - if (text != null && text.isNotEmpty) { - final config = TestConfiguration.fromJsonString(text); - _loadConfiguration(config); - } else { - if (mounted) { - ScaffoldMessenger.of( - context, - ).showSnackBar(const SnackBar(content: Text('Clipboard is empty'))); - } - } - } catch (e) { - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Failed to import: $e'), - backgroundColor: Colors.red, - ), - ); - } - } - } - - Widget _buildControlBar({required bool isNarrow}) { - return Consumer( - builder: (context, runner, child) { - final isRunning = runner.status == TestStatus.running; - final hasFailed = runner.failed > 0; - final config = - _currentConfiguration ?? TestConfiguration.defaultConfig(); - final statusChip = _buildWebViewStatusChip(runner); - - final actions = Wrap( - key: _controlBarWrapKey, - spacing: 8, - runSpacing: 8, - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - ElevatedButton.icon( - icon: Icon(isRunning ? Icons.stop : Icons.play_arrow), - label: Text( - isRunning ? 'Stop' : 'Run Tests (${config.customSteps.length})', - ), - style: ElevatedButton.styleFrom( - backgroundColor: isRunning ? Colors.red : Colors.green, - foregroundColor: Colors.white, - ), - onPressed: isRunning - ? () => runner.stopTests() - : () => _runSelectedTests(), - ), - if (hasFailed && !isRunning) - OutlinedButton.icon( - icon: const Icon(Icons.refresh), - label: const Text('Re-run Failed'), - onPressed: _rerunFailedTests, - ), - ], - ); - - return Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.white, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: Row( - children: [ - Expanded(child: actions), - if (statusChip != null) ...[ - const SizedBox(width: 12), - statusChip, - ], - ], - ), - ); - }, - ); - } - - Widget? _buildWebViewStatusChip(TestRunner runner) { - if (!runner.webViewReady && - runner.webViewType == TestWebViewType.inAppWebView) { - return const Chip( - avatar: SizedBox( - width: 16, - height: 16, - child: CircularProgressIndicator(strokeWidth: 2), - ), - label: Text('WebView loading...'), - ); - } - - if (runner.webViewReady || runner.webViewType == TestWebViewType.headless) { - return Chip( - avatar: Icon( - runner.webViewType == TestWebViewType.headless - ? Icons.visibility_off - : Icons.check_circle, - color: Colors.green, - size: 18, - ), - label: Text( - runner.webViewType == TestWebViewType.headless - ? 'Headless mode' - : 'WebView ready', - ), - ); - } - - return null; - } - - Widget _buildProgressSection() { - return Consumer( - builder: (context, runner, child) { - if (runner.status != TestStatus.running) { - return const SizedBox.shrink(); - } - - final progress = runner.total > 0 - ? runner.progress / runner.total - : 0.0; - - return Container( - padding: const EdgeInsets.all(12), - color: Colors.blue.shade50, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator(strokeWidth: 2), - ), - const SizedBox(width: 12), - Expanded( - child: Text( - 'Running: ${runner.currentTest ?? "..."}', - style: const TextStyle(fontWeight: FontWeight.w500), - overflow: TextOverflow.ellipsis, - ), - ), - Text( - '${runner.progress}/${runner.total}', - style: TextStyle(color: Colors.grey.shade600), - ), - ], - ), - const SizedBox(height: 8), - LinearProgressIndicator( - value: progress, - backgroundColor: Colors.blue.shade100, - ), - ], - ), - ); - }, - ); - } - - Widget _buildFilterBar({required bool isNarrow}) { - return Consumer( - builder: (context, runner, child) { - if (runner.results.isEmpty) { - return const SizedBox.shrink(); - } - - final filterButtons = SegmentedButton( - segments: [ - ButtonSegment( - value: ResultFilter.all, - label: Text('All (${runner.results.length})'), - ), - ButtonSegment( - value: ResultFilter.passed, - label: Text('Passed (${runner.passed})'), - icon: const Icon(Icons.check_circle, size: 16), - ), - ButtonSegment( - value: ResultFilter.failed, - label: Text('Failed (${runner.failed})'), - icon: const Icon(Icons.cancel, size: 16), - ), - ButtonSegment( - value: ResultFilter.skipped, - label: Text('Skipped (${runner.skipped})'), - icon: const Icon(Icons.skip_next, size: 16), - ), - ], - selected: {_resultFilter}, - onSelectionChanged: (selection) { - setState(() { - _resultFilter = selection.first; - }); - }, - ); - - final filterContent = isNarrow - ? SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: filterButtons, - ) - : filterButtons; - - return Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.grey.shade100, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: isNarrow - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row(children: const [Text('Filter: '), SizedBox(width: 8)]), - const SizedBox(height: 8), - filterContent, - ], - ) - : Row( - children: [ - const Text('Filter: '), - const SizedBox(width: 8), - Flexible(child: filterContent), - ], - ), - ); - }, - ); - } - - Widget _buildResultsList() { - return Consumer( - builder: (context, runner, child) { - if (runner.results.isEmpty) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.science_outlined, - size: 64, - color: Colors.grey.shade400, - ), - const SizedBox(height: 16), - Text( - 'No test results yet', - style: TextStyle(fontSize: 18, color: Colors.grey.shade600), - ), - const SizedBox(height: 8), - Text( - 'Select categories and click Run to start testing', - style: TextStyle(color: Colors.grey.shade500), - ), - ], - ), - ); - } - - final filteredResults = _filterResults(runner.results); - - return ListView.builder( - itemCount: filteredResults.length, - itemBuilder: (context, index) { - final result = filteredResults[index]; - return _buildResultTile(result); - }, - ); - }, - ); - } - - Widget _buildResultTile(ExtendedTestResult result) { - final icon = result.skipped - ? Icons.skip_next - : result.success - ? Icons.check_circle - : Icons.cancel; - final color = result.skipped - ? Colors.grey - : result.success - ? Colors.green - : Colors.red; - - return ExpansionTile( - leading: Icon(icon, color: color), - title: Text( - result.testTitle, - style: TextStyle( - fontWeight: FontWeight.w500, - color: result.skipped ? Colors.grey : null, - ), - ), - subtitle: Text( - '${result.category.name} • ${result.duration.inMilliseconds}ms', - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - trailing: Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: color.withOpacity(0.1), - borderRadius: BorderRadius.circular(4), - ), - child: Text( - result.skipped - ? 'SKIPPED' - : result.success - ? 'PASSED' - : 'FAILED', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: color, - ), - ), - ), - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.all(16), - color: Colors.grey.shade50, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Test ID: ${result.testId}', - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - const SizedBox(height: 4), - Text( - 'Message: ${result.message}', - style: const TextStyle(fontSize: 14), - ), - if (result.skipReason != null) ...[ - const SizedBox(height: 4), - Text( - 'Skip Reason: ${result.skipReason}', - style: TextStyle(fontSize: 12, color: Colors.orange.shade700), - ), - ], - if (result.data != null) ...[ - const SizedBox(height: 8), - Text( - 'Data: ${result.data}', - style: TextStyle( - fontSize: 12, - fontFamily: 'monospace', - color: Colors.grey.shade700, - ), - ), - ], - const SizedBox(height: 4), - Text( - 'Timestamp: ${result.timestamp.toIso8601String()}', - style: TextStyle(fontSize: 10, color: Colors.grey.shade500), - ), - ], - ), - ), - ], - ); - } - - Widget _buildSummaryBar() { - return Consumer( - builder: (context, runner, child) { - if (runner.results.isEmpty && runner.status == TestStatus.idle) { - return const SizedBox.shrink(); - } - - final statusColor = runner.status == TestStatus.completed - ? (runner.failed == 0 ? Colors.green : Colors.orange) - : runner.status == TestStatus.running - ? Colors.blue - : Colors.grey; - - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: statusColor.withOpacity(0.1), - border: Border( - top: BorderSide(color: statusColor.withOpacity(0.3)), - ), - ), - child: Row( - children: [ - Icon( - runner.status == TestStatus.completed - ? (runner.failed == 0 ? Icons.check_circle : Icons.warning) - : runner.status == TestStatus.running - ? Icons.hourglass_empty - : Icons.info, - color: statusColor, - ), - const SizedBox(width: 8), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - _getStatusText(runner), - style: TextStyle( - fontWeight: FontWeight.bold, - color: statusColor, - ), - ), - if (runner.results.isNotEmpty) - Text( - 'Success Rate: ${runner.successRate.toStringAsFixed(1)}% • ' - 'Elapsed: ${_formatDuration(runner.elapsedTime)}', - style: TextStyle( - fontSize: 12, - color: Colors.grey.shade600, - ), - ), - ], - ), - ), - _buildStatChip('Passed', runner.passed, Colors.green), - const SizedBox(width: 8), - _buildStatChip('Failed', runner.failed, Colors.red), - const SizedBox(width: 8), - _buildStatChip('Skipped', runner.skipped, Colors.grey), - ], - ), - ); - }, - ); - } - - Widget _buildStatChip(String label, int count, Color color) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), - decoration: BoxDecoration( - color: color.withOpacity(0.1), - borderRadius: BorderRadius.circular(16), - border: Border.all(color: color.withOpacity(0.3)), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - '$count', - style: TextStyle(fontWeight: FontWeight.bold, color: color), - ), - const SizedBox(width: 4), - Text(label, style: TextStyle(fontSize: 12, color: color)), - ], - ), - ); - } - - List _filterResults(List results) { - switch (_resultFilter) { - case ResultFilter.passed: - return results.where((r) => r.success && !r.skipped).toList(); - case ResultFilter.failed: - return results.where((r) => !r.success && !r.skipped).toList(); - case ResultFilter.skipped: - return results.where((r) => r.skipped).toList(); - case ResultFilter.all: - return results; - } - } - - /// Waits for the WebView to be ready (for visible mode) or initializes headless WebView - Future _ensureWebViewReady() async { - final runner = context.read(); - final config = _currentConfiguration ?? TestConfiguration.defaultConfig(); - - if (runner.webViewType == TestWebViewType.headless) { - // For headless mode, initialize the headless WebView - await runner.initializeHeadlessWebView( - initialUrl: config.initialUrl ?? 'https://flutter.dev', - width: config.headlessWidth, - height: config.headlessHeight, - ); - } else { - // For visible mode, recreate the WebView and wait for it to be ready - runner.recreateWebView(); - - // Wait for the WebView to be ready - int attempts = 0; - while (!runner.webViewReady && attempts < 100) { - await Future.delayed(const Duration(milliseconds: 100)); - attempts++; - } - - if (!runner.webViewReady) { - throw Exception('WebView failed to initialize within timeout'); - } - } - } - - void _runSelectedTests() async { - final runner = context.read(); - final config = _currentConfiguration ?? TestConfiguration.defaultConfig(); - - try { - await _ensureWebViewReady(); - await runner.runConfigurationWithCurrentWebView(config); - } catch (e) { - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Failed to run tests: $e'), - backgroundColor: Colors.red, - ), - ); - } - } - } - - void _rerunFailedTests() async { - final runner = context.read(); - - try { - await _ensureWebViewReady(); - await runner.rerunFailedTests(); - } catch (e) { - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Failed to re-run tests: $e'), - backgroundColor: Colors.red, - ), - ); - } - } - } - - void _handleMenuAction(String action) { - final runner = context.read(); - - switch (action) { - case 'export_json': - _exportResults(runner.exportResultsAsJson(), 'test_results.json'); - break; - case 'clear': - runner.clearResults(); - break; - } - } - - void _exportResults(String content, String filename) { - // Copy to clipboard for now - Clipboard.setData(ClipboardData(text: content)); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Results copied to clipboard ($filename)'), - action: SnackBarAction(label: 'OK', onPressed: () {}), - ), - ); - } - - String _getStatusText(TestRunner runner) { - switch (runner.status) { - case TestStatus.idle: - return 'Ready to run tests'; - case TestStatus.running: - return 'Running tests...'; - case TestStatus.paused: - return 'Tests paused'; - case TestStatus.completed: - return runner.failed == 0 - ? 'All tests passed!' - : '${runner.failed} test(s) failed'; - case TestStatus.error: - return 'Error occurred'; - } - } - - String _formatDuration(Duration duration) { - if (duration.inSeconds < 60) { - return '${duration.inSeconds}s'; - } else if (duration.inMinutes < 60) { - final secs = duration.inSeconds % 60; - return '${duration.inMinutes}m ${secs}s'; - } else { - final mins = duration.inMinutes % 60; - return '${duration.inHours}h ${mins}m'; - } - } -} - -enum ResultFilter { all, passed, failed, skipped } diff --git a/flutter_inappwebview/example/lib/screens/webview_environment_settings_editor_screen.dart b/flutter_inappwebview/example/lib/screens/webview_environment_settings_editor_screen.dart deleted file mode 100644 index 159caf1487..0000000000 --- a/flutter_inappwebview/example/lib/screens/webview_environment_settings_editor_screen.dart +++ /dev/null @@ -1,1165 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; -import 'package:flutter_inappwebview_example/models/environment_setting_definition.dart'; -import 'package:flutter_inappwebview_example/models/webview_environment_profile.dart'; -import 'package:flutter_inappwebview_example/utils/platform_utils.dart'; -import 'package:flutter_inappwebview_example/utils/responsive_utils.dart'; -import 'package:flutter_inappwebview_example/widgets/common/app_drawer.dart'; -import 'package:flutter_inappwebview_example/widgets/settings/responsive_setting_tile.dart'; -import 'package:flutter_inappwebview_example/widgets/common/support_badge.dart'; - -import '../utils/support_checker.dart'; - -/// Comprehensive settings editor for WebViewEnvironmentSettings -/// Used to configure WebView2 (Windows) and WPE WebKit (Linux) environments -class WebViewEnvironmentSettingsEditorScreen extends StatefulWidget { - const WebViewEnvironmentSettingsEditorScreen({super.key}); - - @override - State createState() => - _WebViewEnvironmentSettingsEditorScreenState(); -} - -class _WebViewEnvironmentSettingsEditorScreenState - extends State { - final TextEditingController _profileNameController = TextEditingController(); - final TextEditingController _searchController = TextEditingController(); - String _searchQuery = ''; - Set _expandedCategories = {}; - Map _localSettings = {}; - Set _modifiedKeys = {}; - - @override - void initState() { - super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) { - final settingsManager = context.read(); - if (settingsManager.isLoading) { - settingsManager.init(); - } - _loadCurrentSettings(); - }); - } - - void _loadCurrentSettings() { - final settingsManager = context.read(); - setState(() { - _localSettings = Map.from( - settingsManager.currentEnvironmentSettings, - ); - _modifiedKeys.clear(); - }); - } - - @override - void dispose() { - _profileNameController.dispose(); - _searchController.dispose(); - super.dispose(); - } - - SupportedPlatform? get _currentPlatform => PlatformUtils.getCurrentPlatform(); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Environment Settings'), - actions: [ - IconButton( - icon: const Icon(Icons.save), - tooltip: 'Save Profile', - onPressed: _showSaveProfileDialog, - ), - IconButton( - icon: const Icon(Icons.folder_open), - tooltip: 'Load Profile', - onPressed: _showLoadProfileDialog, - ), - PopupMenuButton( - icon: const Icon(Icons.more_vert), - onSelected: _handleMenuAction, - itemBuilder: (context) => [ - const PopupMenuItem( - value: 'reset', - child: ListTile( - leading: Icon(Icons.restore), - title: Text('Reset to Defaults'), - contentPadding: EdgeInsets.zero, - ), - ), - const PopupMenuItem( - value: 'clear_selection', - child: ListTile( - leading: Icon(Icons.clear), - title: Text('Clear Environment'), - contentPadding: EdgeInsets.zero, - ), - ), - const PopupMenuDivider(), - const PopupMenuItem( - value: 'expand_all', - child: ListTile( - leading: Icon(Icons.unfold_more), - title: Text('Expand All'), - contentPadding: EdgeInsets.zero, - ), - ), - const PopupMenuItem( - value: 'collapse_all', - child: ListTile( - leading: Icon(Icons.unfold_less), - title: Text('Collapse All'), - contentPadding: EdgeInsets.zero, - ), - ), - ], - ), - ], - ), - drawer: AppDrawer(), - body: Consumer( - builder: (context, settingsManager, child) { - if (settingsManager.isLoading) { - return const Center(child: CircularProgressIndicator()); - } - - final definitions = - SettingsManager.getEnvironmentSettingDefinitions(); - - return Column( - children: [ - _buildHeader(settingsManager), - _buildSearchBar(), - Expanded( - child: ListView( - padding: const EdgeInsets.all(16), - children: definitions.entries.map((entry) { - return _buildCategorySection( - entry.key, - entry.value, - settingsManager, - ); - }).toList(), - ), - ), - _buildBottomBar(settingsManager), - ], - ); - }, - ), - ); - } - - Widget _buildHeader(SettingsManager settingsManager) { - final profile = settingsManager.currentEnvironmentProfile; - final modifiedCount = _modifiedKeys.length; - final envStatus = settingsManager.webViewEnvironment != null - ? 'Active' - : profile != null - ? 'Pending' - : 'None'; - - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.purple.shade50, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: Row( - children: [ - Icon(Icons.memory, color: Colors.purple.shade700), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - profile != null - ? 'Profile: ${profile.name}' - : 'New Environment Configuration', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - Row( - children: [ - Text( - modifiedCount > 0 - ? '$modifiedCount setting${modifiedCount == 1 ? '' : 's'} modified' - : 'Using default settings', - style: TextStyle( - fontSize: 12, - color: modifiedCount > 0 - ? Colors.orange.shade700 - : Colors.grey.shade600, - ), - ), - const SizedBox(width: 8), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 6, - vertical: 2, - ), - decoration: BoxDecoration( - color: envStatus == 'Active' - ? Colors.green.shade100 - : envStatus == 'Pending' - ? Colors.orange.shade100 - : Colors.grey.shade200, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - 'Env: $envStatus', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: envStatus == 'Active' - ? Colors.green.shade800 - : envStatus == 'Pending' - ? Colors.orange.shade800 - : Colors.grey.shade600, - ), - ), - ), - ], - ), - ], - ), - ), - Chip( - label: Text( - _currentPlatform?.displayName.toUpperCase() ?? 'UNKNOWN', - ), - backgroundColor: Colors.purple.shade100, - labelStyle: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Colors.purple.shade800, - ), - ), - ], - ), - ); - } - - Widget _buildSearchBar() { - return Padding( - padding: const EdgeInsets.all(16), - child: TextField( - controller: _searchController, - decoration: InputDecoration( - hintText: 'Search environment settings...', - prefixIcon: const Icon(Icons.search), - suffixIcon: _searchQuery.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear), - onPressed: () { - _searchController.clear(); - setState(() => _searchQuery = ''); - }, - ) - : null, - border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 12, - ), - ), - onChanged: (value) { - setState(() => _searchQuery = value.toLowerCase()); - }, - ), - ); - } - - Widget _buildCategorySection( - String category, - List settings, - SettingsManager settingsManager, - ) { - // Filter settings based on search query only (show all platforms) - final filteredSettings = settings.where((setting) { - // Filter by search query - if (_searchQuery.isEmpty) return true; - return setting.name.toLowerCase().contains(_searchQuery) || - setting.description.toLowerCase().contains(_searchQuery) || - setting.key.toLowerCase().contains(_searchQuery); - }).toList(); - - if (filteredSettings.isEmpty) return const SizedBox.shrink(); - - final isExpanded = - _expandedCategories.contains(category) || _searchQuery.isNotEmpty; - final header = Row( - children: [ - Text( - category, - style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), - ), - const SizedBox(width: 8), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), - decoration: BoxDecoration( - color: Colors.grey.shade200, - borderRadius: BorderRadius.circular(12), - ), - child: Text( - '${filteredSettings.length}', - style: TextStyle(fontSize: 12, color: Colors.grey.shade700), - ), - ), - ], - ); - final subtitle = Text( - '${filteredSettings.length} setting${filteredSettings.length == 1 ? '' : 's'}', - style: TextStyle(color: Colors.grey.shade600, fontSize: 12), - ); - - return Card( - margin: const EdgeInsets.only(bottom: 8), - child: ExpansionTile( - key: ValueKey('$category-$isExpanded'), - initiallyExpanded: isExpanded, - onExpansionChanged: (expanded) { - setState(() { - if (expanded) { - _expandedCategories.add(category); - } else { - _expandedCategories.remove(category); - } - }); - }, - title: header, - subtitle: subtitle, - children: filteredSettings.map((setting) { - return _buildSettingTile(setting, settingsManager); - }).toList(), - ), - ); - } - - Widget _buildSettingTile( - EnvironmentSettingDefinition setting, - SettingsManager settingsManager, - ) { - final isModified = _modifiedKeys.contains(setting.key); - final currentValue = _localSettings[setting.key] ?? setting.defaultValue; - final hasPlatformLimitations = setting.supportedPlatforms.isNotEmpty; - - return Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - decoration: BoxDecoration( - color: isModified ? Colors.orange.shade50 : null, - border: Border(bottom: BorderSide(color: Colors.grey.shade200)), - ), - child: ResponsiveSettingTile( - title: Row( - children: [ - Flexible( - child: Text( - setting.name, - style: const TextStyle( - fontWeight: FontWeight.w600, - color: Colors.black87, - ), - ), - ), - if (isModified) ...[ - const SizedBox(width: 8), - Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: Colors.orange.shade200, - borderRadius: BorderRadius.circular(4), - ), - child: const Text( - 'Modified', - style: TextStyle(fontSize: 10, fontWeight: FontWeight.bold), - ), - ), - ], - ], - ), - description: Text( - setting.description, - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - badges: hasPlatformLimitations - ? SupportBadgesRow( - supportedPlatforms: setting.supportedPlatforms, - compact: true, - ) - : null, - trailing: isModified - ? IconButton( - icon: const Icon(Icons.restore, size: 20), - tooltip: 'Reset to default', - onPressed: () => _resetSetting(setting.key), - ) - : null, - control: _buildSettingControl(setting, currentValue), - inlineControl: setting.type == EnvironmentSettingType.boolean, - ), - ); - } - - Widget _buildSettingControl( - EnvironmentSettingDefinition setting, - dynamic currentValue, - ) { - switch (setting.type) { - case EnvironmentSettingType.boolean: - return Switch( - value: currentValue ?? setting.defaultValue ?? false, - onChanged: (value) => _updateSetting(setting.key, value), - ); - - case EnvironmentSettingType.string: - return SizedBox( - width: double.infinity, - child: TextField( - controller: TextEditingController( - text: currentValue?.toString() ?? '', - ), - decoration: InputDecoration( - isDense: true, - contentPadding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 8, - ), - border: const OutlineInputBorder(), - hintText: setting.hint ?? 'Enter value...', - ), - style: const TextStyle(fontSize: 14), - onChanged: (value) => - _updateSetting(setting.key, value.isEmpty ? null : value), - ), - ); - - case EnvironmentSettingType.stringList: - return _buildStringListControl(setting, currentValue); - - case EnvironmentSettingType.enumeration: - if (setting.enumValues == null || setting.enumValues!.isEmpty) { - return const SizedBox.shrink(); - } - if (_isBitmaskEnumSetting(setting)) { - return _buildBitmaskEnumControl(setting, currentValue); - } - final selectedValue = _resolveEnumSelection(setting, currentValue); - return DropdownButton( - value: selectedValue, - isExpanded: true, - items: [ - const DropdownMenuItem( - value: null, - child: Text('Not Set', style: TextStyle(fontSize: 14)), - ), - ...setting.enumValues!.map((enumValue) { - return DropdownMenuItem( - value: enumValue, - child: Text( - EnvironmentSettingDefinition.enumDisplayName(enumValue), - style: const TextStyle(fontSize: 14), - ), - ); - }), - ], - onChanged: (value) => _updateSetting( - setting.key, - EnvironmentSettingDefinition.enumValueToNative(value), - ), - ); - - case EnvironmentSettingType.customSchemeRegistrations: - return _buildCustomSchemeRegistrationsControl(setting, currentValue); - } - } - - Widget _buildStringListControl( - EnvironmentSettingDefinition setting, - dynamic currentValue, - ) { - final List items = currentValue != null - ? List.from(currentValue as List) - : []; - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Wrap( - spacing: 8, - runSpacing: 4, - children: [ - ...items.map((item) { - return Chip( - label: Text(item, style: const TextStyle(fontSize: 12)), - deleteIcon: const Icon(Icons.close, size: 16), - onDeleted: () { - final newItems = List.from(items)..remove(item); - _updateSetting( - setting.key, - newItems.isEmpty ? null : newItems, - ); - }, - ); - }), - ActionChip( - avatar: const Icon(Icons.add, size: 16), - label: const Text('Add', style: TextStyle(fontSize: 12)), - onPressed: () => _showAddStringItemDialog(setting, items), - ), - ], - ), - ], - ); - } - - void _showAddStringItemDialog( - EnvironmentSettingDefinition setting, - List currentItems, - ) { - final controller = TextEditingController(); - - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Add ${setting.name}'), - content: TextField( - controller: controller, - decoration: InputDecoration( - labelText: 'Value', - hintText: setting.hint ?? 'Enter value...', - border: const OutlineInputBorder(), - ), - autofocus: true, - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: () { - final value = controller.text.trim(); - if (value.isNotEmpty) { - final newItems = List.from(currentItems)..add(value); - _updateSetting(setting.key, newItems); - Navigator.pop(context); - } - }, - child: const Text('Add'), - ), - ], - ), - ); - } - - Widget _buildCustomSchemeRegistrationsControl( - EnvironmentSettingDefinition setting, - dynamic currentValue, - ) { - // For now, show as JSON editable text - final List> items = currentValue != null - ? List>.from( - (currentValue as List).map((e) => Map.from(e)), - ) - : >[]; - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (items.isEmpty) - Text( - 'No custom schemes registered', - style: TextStyle(color: Colors.grey.shade600, fontSize: 12), - ) - else - ...items.asMap().entries.map((entry) { - final index = entry.key; - final scheme = entry.value; - return Card( - margin: const EdgeInsets.only(bottom: 4), - child: ListTile( - dense: true, - title: Text( - scheme['scheme']?.toString() ?? 'Unknown', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - subtitle: Text( - 'Fetch: ${scheme['treatAsSecure'] ?? false}', - style: const TextStyle(fontSize: 11), - ), - trailing: IconButton( - icon: const Icon(Icons.delete, size: 20), - onPressed: () { - final newItems = List>.from(items) - ..removeAt(index); - _updateSetting( - setting.key, - newItems.isEmpty ? null : newItems, - ); - }, - ), - ), - ); - }), - const SizedBox(height: 4), - OutlinedButton.icon( - icon: const Icon(Icons.add, size: 16), - label: const Text('Add Custom Scheme'), - onPressed: () => _showAddCustomSchemeDialog(setting.key, items), - ), - ], - ); - } - - void _showAddCustomSchemeDialog( - String settingKey, - List> currentItems, - ) { - final schemeController = TextEditingController(); - bool treatAsSecure = false; - bool hasAccess = true; - - showDialog( - context: context, - builder: (context) => StatefulBuilder( - builder: (context, setDialogState) => AlertDialog( - title: const Text('Add Custom Scheme'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextField( - controller: schemeController, - decoration: const InputDecoration( - labelText: 'Scheme Name', - hintText: 'e.g., myapp', - border: OutlineInputBorder(), - ), - autofocus: true, - ), - const SizedBox(height: 16), - SwitchListTile( - title: const Text('Treat as Secure'), - subtitle: const Text('Allow secure context features'), - value: treatAsSecure, - onChanged: (value) => - setDialogState(() => treatAsSecure = value), - ), - SwitchListTile( - title: const Text('Has Access'), - subtitle: const Text('Allow access to other schemes'), - value: hasAccess, - onChanged: (value) => setDialogState(() => hasAccess = value), - ), - ], - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: () { - final scheme = schemeController.text.trim(); - if (scheme.isNotEmpty) { - final newItems = List>.from(currentItems) - ..add({ - 'scheme': scheme, - 'treatAsSecure': treatAsSecure, - 'hasAccess': hasAccess, - }); - _updateSetting(settingKey, newItems); - Navigator.pop(context); - } - }, - child: const Text('Add'), - ), - ], - ), - ), - ); - } - - bool _isBitmaskEnumSetting(EnvironmentSettingDefinition setting) { - return setting.property == - WebViewEnvironmentSettingsProperty.releaseChannels; - } - - int _resolveBitmaskValue(dynamic currentValue) { - if (currentValue == null) return 0; - if (currentValue is int) return currentValue; - final nativeValue = EnvironmentSettingDefinition.enumValueToNative( - currentValue, - ); - return nativeValue is int ? nativeValue : 0; - } - - dynamic _resolveEnumSelection( - EnvironmentSettingDefinition setting, - dynamic currentValue, - ) { - if (currentValue == null) return null; - final enumValues = setting.enumValues; - if (enumValues == null || enumValues.isEmpty) return null; - - if (enumValues.contains(currentValue)) { - return currentValue; - } - - for (final enumValue in enumValues) { - final nativeValue = EnvironmentSettingDefinition.enumValueToNative( - enumValue, - ); - if (nativeValue == currentValue) { - return enumValue; - } - } - - return null; - } - - Widget _buildBitmaskEnumControl( - EnvironmentSettingDefinition setting, - dynamic currentValue, - ) { - final enumValues = setting.enumValues ?? []; - if (enumValues.isEmpty) { - return const SizedBox.shrink(); - } - - final currentMask = _resolveBitmaskValue(currentValue); - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Wrap( - spacing: 8, - runSpacing: 4, - children: enumValues.map((enumValue) { - final nativeValue = EnvironmentSettingDefinition.enumValueToNative( - enumValue, - ); - final maskValue = nativeValue is int ? nativeValue : 0; - final isSelected = - maskValue != 0 && (currentMask & maskValue) == maskValue; - - return FilterChip( - label: Text( - EnvironmentSettingDefinition.enumDisplayName(enumValue), - style: const TextStyle(fontSize: 12), - ), - selected: isSelected, - onSelected: (selected) { - final updatedMask = selected - ? (currentMask | maskValue) - : (currentMask & ~maskValue); - _updateSetting( - setting.key, - updatedMask == 0 ? null : updatedMask, - ); - }, - ); - }).toList(), - ), - if (currentMask == 0) - Padding( - padding: const EdgeInsets.only(top: 6), - child: Text( - 'No release channels selected', - style: TextStyle(color: Colors.grey.shade600, fontSize: 12), - ), - ), - ], - ); - } - - void _updateSetting(String key, dynamic value) { - setState(() { - if (value == null) { - _localSettings.remove(key); - } else { - _localSettings[key] = value; - } - _modifiedKeys.add(key); - }); - } - - void _resetSetting(String key) { - setState(() { - _localSettings.remove(key); - _modifiedKeys.remove(key); - }); - } - - Widget _buildBottomBar(SettingsManager settingsManager) { - final isMobile = context.isMobile; - final resetButton = OutlinedButton.icon( - icon: const Icon(Icons.restore), - label: const Text('Reset All'), - onPressed: () => _showResetConfirmDialog(settingsManager), - ); - final recreateButton = OutlinedButton.icon( - icon: const Icon(Icons.refresh), - label: const Text('Recreate Env'), - onPressed: () async { - await settingsManager.recreateEnvironment(); - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('$WebViewEnvironment recreated')), - ); - } - }, - ); - final applyButton = ElevatedButton.icon( - icon: const Icon(Icons.check), - label: const Text('Apply & Create'), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.purple, - foregroundColor: Colors.white, - ), - onPressed: () => _applySettings(settingsManager), - ); - - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: Colors.grey.shade300)), - boxShadow: [ - BoxShadow( - color: Colors.grey.shade200, - blurRadius: 4, - offset: const Offset(0, -2), - ), - ], - ), - child: isMobile - ? Wrap( - key: const ValueKey('settings_bottom_bar_actions'), - spacing: 12, - runSpacing: 8, - children: [ - resetButton, - if (settingsManager.webViewEnvironment != null) recreateButton, - applyButton, - ], - ) - : Row( - key: const ValueKey('settings_bottom_bar_actions'), - children: [ - resetButton, - const SizedBox(width: 8), - if (settingsManager.webViewEnvironment != null) recreateButton, - const Spacer(), - applyButton, - ], - ), - ); - } - - Future _applySettings(SettingsManager settingsManager) async { - // Save to current environment profile or create new - if (settingsManager.currentEnvironmentProfile != null) { - await settingsManager.updateEnvironmentProfile( - settingsManager.currentEnvironmentProfileId!, - settings: Map.from(_localSettings), - ); - } else { - // Just update internal state and recreate - for (final entry in _localSettings.entries) { - settingsManager.currentEnvironmentSettings[entry.key] = entry.value; - } - await settingsManager.recreateEnvironment(); - } - - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Environment settings applied')), - ); - } - } - - void _handleMenuAction(String action) { - final settingsManager = context.read(); - - switch (action) { - case 'reset': - _showResetConfirmDialog(settingsManager); - break; - case 'clear_selection': - _clearEnvironmentSelection(settingsManager); - break; - case 'expand_all': - setState(() { - _expandedCategories = - SettingsManager.getEnvironmentSettingDefinitions().keys.toSet(); - }); - break; - case 'collapse_all': - setState(() { - _expandedCategories.clear(); - }); - break; - } - } - - Future _clearEnvironmentSelection( - SettingsManager settingsManager, - ) async { - final confirmed = await showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Clear Environment'), - content: Text( - 'This will dispose the current $WebViewEnvironment and clear the selection. ' - 'Any WebViews using this environment will need to be recreated.', - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context, false), - child: const Text('Cancel'), - ), - ElevatedButton( - style: ElevatedButton.styleFrom(backgroundColor: Colors.orange), - onPressed: () => Navigator.pop(context, true), - child: const Text('Clear'), - ), - ], - ), - ); - - if (confirmed == true) { - await settingsManager.clearEnvironmentSelection(); - _loadCurrentSettings(); - if (mounted) { - ScaffoldMessenger.of( - context, - ).showSnackBar(const SnackBar(content: Text('Environment cleared'))); - } - } - } - - void _showSaveProfileDialog() { - final settingsManager = context.read(); - final currentProfile = settingsManager.currentEnvironmentProfile; - _profileNameController.text = currentProfile?.name ?? ''; - - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Save Environment Profile'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextField( - controller: _profileNameController, - decoration: const InputDecoration( - labelText: 'Profile Name', - hintText: 'Enter a name for this profile', - border: OutlineInputBorder(), - ), - autofocus: true, - ), - const SizedBox(height: 16), - Text( - 'This will save ${_modifiedKeys.length} modified settings.', - style: TextStyle(color: Colors.grey.shade600, fontSize: 12), - ), - ], - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: () async { - final name = _profileNameController.text.trim(); - if (name.isNotEmpty) { - // Update internal settings first - for (final entry in _localSettings.entries) { - settingsManager.currentEnvironmentSettings[entry.key] = - entry.value; - } - await settingsManager.saveCurrentEnvironmentSettings(name); - _modifiedKeys.clear(); - if (mounted) { - Navigator.pop(context); - ScaffoldMessenger.of(this.context).showSnackBar( - SnackBar(content: Text('Profile "$name" saved')), - ); - } - } - }, - child: const Text('Save'), - ), - ], - ), - ); - } - - void _showLoadProfileDialog() { - final settingsManager = context.read(); - - if (settingsManager.environmentProfiles.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('No saved environment profiles found')), - ); - return; - } - - showDialog( - context: context, - builder: (dialogContext) => StatefulBuilder( - builder: (context, setDialogState) { - final profiles = settingsManager.environmentProfiles; - - if (profiles.isEmpty) { - WidgetsBinding.instance.addPostFrameCallback((_) { - Navigator.pop(dialogContext); - }); - return const SizedBox.shrink(); - } - - return AlertDialog( - title: const Text('Load Environment Profile'), - content: SizedBox( - width: double.maxFinite, - child: ListView.builder( - shrinkWrap: true, - itemCount: profiles.length, - itemBuilder: (context, index) { - final profile = profiles[index]; - final isCurrentProfile = - profile.id == settingsManager.currentEnvironmentProfileId; - - return ListTile( - title: Text(profile.name), - subtitle: Text( - '${profile.settings.length} settings • Created ${_formatDate(profile.createdAt)}', - style: const TextStyle(fontSize: 12), - ), - leading: Icon( - isCurrentProfile ? Icons.check_circle : Icons.memory, - color: isCurrentProfile ? Colors.green : null, - ), - trailing: IconButton( - icon: const Icon(Icons.delete, color: Colors.red), - onPressed: () => _confirmDeleteProfile( - profile, - onDeleted: () => setDialogState(() {}), - ), - ), - onTap: () async { - await settingsManager.loadEnvironmentProfile(profile.id); - _loadCurrentSettings(); - if (mounted) { - Navigator.pop(dialogContext); - ScaffoldMessenger.of(this.context).showSnackBar( - SnackBar( - content: Text('Loaded profile "${profile.name}"'), - ), - ); - } - }, - ); - }, - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(dialogContext), - child: const Text('Close'), - ), - ], - ); - }, - ), - ); - } - - void _confirmDeleteProfile( - WebViewEnvironmentProfile profile, { - VoidCallback? onDeleted, - }) { - showDialog( - context: context, - builder: (dialogContext) => AlertDialog( - title: const Text('Delete Profile'), - content: Text('Are you sure you want to delete "${profile.name}"?'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(dialogContext), - child: const Text('Cancel'), - ), - ElevatedButton( - style: ElevatedButton.styleFrom(backgroundColor: Colors.red), - onPressed: () async { - await context.read().deleteEnvironmentProfile( - profile.id, - ); - if (mounted) { - Navigator.pop(dialogContext); - onDeleted?.call(); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Deleted profile "${profile.name}"')), - ); - } - }, - child: const Text('Delete'), - ), - ], - ), - ); - } - - void _showResetConfirmDialog(SettingsManager settingsManager) { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Reset Settings'), - content: const Text( - 'Are you sure you want to reset all environment settings to their default values?', - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), - ), - ElevatedButton( - style: ElevatedButton.styleFrom(backgroundColor: Colors.red), - onPressed: () { - _loadCurrentSettings(); - Navigator.pop(context); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Settings reset to defaults')), - ); - }, - child: const Text('Reset'), - ), - ], - ), - ); - } - - String _formatDate(DateTime date) { - final now = DateTime.now(); - final diff = now.difference(date); - - if (diff.inDays == 0) { - return 'today'; - } else if (diff.inDays == 1) { - return 'yesterday'; - } else if (diff.inDays < 7) { - return '${diff.inDays} days ago'; - } else { - return '${date.day}/${date.month}/${date.year}'; - } - } -} diff --git a/flutter_inappwebview/example/lib/screens/webview_tester_screen.dart b/flutter_inappwebview/example/lib/screens/webview_tester_screen.dart deleted file mode 100644 index c8904e604a..0000000000 --- a/flutter_inappwebview/example/lib/screens/webview_tester_screen.dart +++ /dev/null @@ -1,1496 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/models/event_log_entry.dart'; -import 'package:flutter_inappwebview_example/models/network_request.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/providers/network_monitor.dart'; -import 'package:flutter_inappwebview_example/widgets/webview/event_console_widget.dart'; -import 'package:flutter_inappwebview_example/widgets/webview/network_monitor_widget.dart'; -import 'package:flutter_inappwebview_example/widgets/webview/method_tester_widget.dart'; -import 'package:flutter_inappwebview_example/widgets/webview/javascript_console_widget.dart'; -import 'package:flutter_inappwebview_example/widgets/webview/user_script_tester_widget.dart'; -import 'package:flutter_inappwebview_example/widgets/common/app_drawer.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; -import 'package:flutter_inappwebview_example/widgets/common/profile_selector_card.dart'; -import 'package:flutter_inappwebview_example/utils/responsive_utils.dart'; - -/// Main screen for testing InAppWebView functionality -class WebViewTesterScreen extends StatefulWidget { - const WebViewTesterScreen({super.key}); - - @override - State createState() => _WebViewTesterScreenState(); -} - -class _WebViewTesterScreenState extends State - with SingleTickerProviderStateMixin { - final TextEditingController _urlController = TextEditingController( - text: 'https://flutter.dev', - ); - - InAppWebViewController? _webViewController; - bool _canGoBack = false; - bool _canGoForward = false; - double _progress = 0; - bool _forceShowReloadAfterStop = false; - String? _currentUrl; - String? _currentTitle; - late TabController _tabController; - final List _userScripts = []; - double _webViewHeight = 320; - static const double _minWebViewHeight = 160; - static const double _minTabsHeight = 220; - static const double _dividerHeight = 6; - static const double _minChromeHeight = 140; - bool _settingsExpanded = false; - - bool get _shouldShowStopButton { - return _progress > 0 && _progress < 1.0 && !_forceShowReloadAfterStop; - } - - @override - void initState() { - super.initState(); - _tabController = TabController(length: 5, vsync: this); - } - - @override - void dispose() { - _urlController.dispose(); - _tabController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final settingsManager = context.watch(); - - return Scaffold( - appBar: AppBar( - title: const Text('WebView Tester'), - actions: [ - IconButton( - icon: const Icon(Icons.clear_all), - tooltip: 'Clear Events', - onPressed: () { - context.read().clear(); - }, - ), - ], - ), - drawer: AppDrawer(), - body: LayoutBuilder( - builder: (context, constraints) { - final minRequiredHeight = - _minWebViewHeight + - _minTabsHeight + - _dividerHeight + - _minChromeHeight; - final useScroll = constraints.maxHeight < minRequiredHeight; - - if (useScroll) { - return _buildScrollableBody(settingsManager); - } - - return _buildStandardBody(settingsManager); - }, - ), - ); - } - - Widget _buildStandardBody(SettingsManager settingsManager) { - final isMobile = context.isMobile; - return Column( - children: [ - _buildCombinedControlBar(isMobile), - Expanded(child: _buildResizableContent(settingsManager, isMobile)), - ], - ); - } - - Widget _buildScrollableBody(SettingsManager settingsManager) { - final isMobile = context.isMobile; - return SingleChildScrollView( - child: Column( - children: [ - _buildCombinedControlBar(isMobile), - SizedBox( - height: _minWebViewHeight, - child: _buildWebViewWithProgress(settingsManager), - ), - if (isMobile) - _buildCollapsibleSettings() - else - ProfileSelectorCard( - compact: true, - onEditSettingsProfile: () => - Navigator.pushNamed(context, '/settings'), - onEditEnvironmentProfile: () => - Navigator.pushNamed(context, '/environment-settings'), - ), - Container(height: _dividerHeight, color: Colors.grey.shade300), - SizedBox(height: _minTabsHeight, child: _buildBottomTabs()), - ], - ), - ); - } - - Widget _buildResizableContent( - SettingsManager settingsManager, - bool isMobile, - ) { - return LayoutBuilder( - builder: (context, constraints) { - // Account for ProfileSelectorCard height - smaller on mobile when collapsed - final profileCardHeight = isMobile - ? (_settingsExpanded ? 100.0 : 40.0) - : 120.0; - final maxWebViewHeight = - constraints.maxHeight - - _minTabsHeight - - _dividerHeight - - profileCardHeight; - final effectiveMax = maxWebViewHeight < _minWebViewHeight - ? _minWebViewHeight - : maxWebViewHeight; - final webViewHeight = _webViewHeight - .clamp(_minWebViewHeight, effectiveMax) - .toDouble(); - - return Column( - children: [ - _buildWebViewWithProgress(settingsManager, height: webViewHeight), - if (isMobile) - _buildCollapsibleSettings() - else - ProfileSelectorCard( - compact: true, - onEditSettingsProfile: () => - Navigator.pushNamed(context, '/settings'), - onEditEnvironmentProfile: () => - Navigator.pushNamed(context, '/environment-settings'), - ), - _buildResizeHandle( - onDrag: (delta) { - setState(() { - _webViewHeight = (_webViewHeight + delta) - .clamp(_minWebViewHeight, effectiveMax) - .toDouble(); - }); - }, - ), - Expanded(child: _buildBottomTabs()), - ], - ); - }, - ); - } - - Widget _buildResizeHandle({required ValueChanged onDrag}) { - return MouseRegion( - cursor: SystemMouseCursors.resizeRow, - child: GestureDetector( - behavior: HitTestBehavior.translucent, - onVerticalDragUpdate: (details) => onDrag(details.delta.dy), - child: Container( - height: _dividerHeight, - color: Colors.grey.shade300, - child: Center( - child: Container( - width: 40, - height: 2, - decoration: BoxDecoration( - color: Colors.grey.shade600, - borderRadius: BorderRadius.circular(2), - ), - ), - ), - ), - ), - ); - } - - Widget _buildWebViewWithProgress( - SettingsManager settingsManager, { - double? height, - }) { - final webView = _buildWebView(settingsManager); - - final stack = Stack( - children: [ - Positioned.fill(child: webView), - if (_progress < 1.0) - Positioned( - top: 0, - left: 0, - right: 0, - child: LinearProgressIndicator( - value: _progress, - backgroundColor: Colors.grey.shade200, - ), - ), - ], - ); - - if (height != null) { - return SizedBox(height: height, child: stack); - } - - return stack; - } - - /// Combined URL bar and navigation controls - optimized for mobile - Widget _buildCombinedControlBar(bool isMobile) { - if (isMobile) { - // Mobile: single compact row with URL field containing nav buttons - return Container( - padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4), - decoration: BoxDecoration( - color: Colors.white, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: Row( - children: [ - // Compact nav buttons - _buildCompactNavButton( - Icons.arrow_back, - 'Back', - _canGoBack ? () => _webViewController?.goBack() : null, - ), - _buildCompactNavButton( - Icons.arrow_forward, - 'Forward', - _canGoForward ? () => _webViewController?.goForward() : null, - ), - _buildCompactNavButton( - _shouldShowStopButton ? Icons.stop : Icons.refresh, - _shouldShowStopButton ? 'Stop' : 'Reload', - _shouldShowStopButton - ? () { - setState(() => _forceShowReloadAfterStop = true); - _webViewController?.stopLoading(); - } - : () { - setState(() => _forceShowReloadAfterStop = false); - _webViewController?.reload(); - }, - ), - const SizedBox(width: 4), - // URL field takes remaining space - Expanded(child: _buildUrlTextField(isMobile: true)), - ], - ), - ); - } - - // Desktop: separate URL bar and navigation controls - return Column( - children: [ - Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: Colors.white, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: Row( - children: [ - Expanded(child: _buildUrlTextField()), - const SizedBox(width: 8), - IconButton( - icon: const Icon(Icons.arrow_forward), - tooltip: 'Go', - onPressed: _loadUrl, - ), - ], - ), - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: Colors.grey.shade100, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: Row( - children: [ - _buildNavigationButtons(false), - const SizedBox(width: 12), - Expanded(child: _buildTitleAndUrlInfo(false)), - ], - ), - ), - ], - ); - } - - Widget _buildCompactNavButton( - IconData icon, - String tooltip, - VoidCallback? onPressed, - ) { - return SizedBox( - width: 32, - height: 32, - child: IconButton( - icon: Icon(icon, size: 18), - tooltip: tooltip, - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - onPressed: onPressed, - ), - ); - } - - /// Collapsible settings section for mobile - Widget _buildCollapsibleSettings() { - return GestureDetector( - onTap: () => setState(() => _settingsExpanded = !_settingsExpanded), - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 4, vertical: 2), - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: Colors.grey.shade50, - borderRadius: BorderRadius.circular(4), - border: Border.all(color: Colors.grey.shade300), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - children: [ - Icon( - _settingsExpanded ? Icons.expand_less : Icons.expand_more, - size: 18, - color: Colors.grey.shade600, - ), - const SizedBox(width: 4), - Text( - 'Settings', - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w500, - color: Colors.grey.shade700, - ), - ), - const Spacer(), - Text( - context.watch().currentProfile?.name ?? - 'Default', - style: TextStyle(fontSize: 10, color: Colors.grey.shade600), - ), - const SizedBox(width: 8), - InkWell( - onTap: () => Navigator.pushNamed(context, '/settings'), - child: Icon( - Icons.edit, - size: 14, - color: Colors.blue.shade400, - ), - ), - ], - ), - if (_settingsExpanded) ...[ - const SizedBox(height: 8), - ProfileSelectorCard( - compact: true, - onEditSettingsProfile: () => - Navigator.pushNamed(context, '/settings'), - onEditEnvironmentProfile: () => - Navigator.pushNamed(context, '/environment-settings'), - ), - ], - ], - ), - ), - ); - } - - Widget _buildUrlTextField({bool isMobile = false}) { - return TextField( - controller: _urlController, - style: TextStyle(fontSize: isMobile ? 13 : 14), - decoration: InputDecoration( - hintText: 'Enter URL', - isDense: isMobile, - border: const OutlineInputBorder(), - contentPadding: EdgeInsets.symmetric( - horizontal: isMobile ? 8 : 12, - vertical: isMobile ? 6 : 8, - ), - suffixIcon: isMobile - ? SizedBox( - width: 32, - child: IconButton( - icon: const Icon(Icons.arrow_forward, size: 18), - tooltip: 'Go', - padding: EdgeInsets.zero, - onPressed: _loadUrl, - ), - ) - : null, - ), - onSubmitted: (_) => _loadUrl(), - ); - } - - Widget _buildNavigationButtons(bool isMobile) { - final buttons = [ - IconButton( - icon: const Icon(Icons.arrow_back), - tooltip: 'Back', - onPressed: _canGoBack ? () => _webViewController?.goBack() : null, - ), - IconButton( - icon: const Icon(Icons.arrow_forward), - tooltip: 'Forward', - onPressed: _canGoForward ? () => _webViewController?.goForward() : null, - ), - IconButton( - icon: const Icon(Icons.refresh), - tooltip: 'Reload', - onPressed: () => _webViewController?.reload(), - ), - IconButton( - icon: const Icon(Icons.stop), - tooltip: 'Stop', - onPressed: () => _webViewController?.stopLoading(), - ), - ]; - - if (isMobile) { - return Wrap(spacing: 4, runSpacing: 4, children: buttons); - } - - return Row(mainAxisSize: MainAxisSize.min, children: buttons); - } - - Widget _buildTitleAndUrlInfo(bool isMobile) { - final titleStyle = TextStyle( - fontSize: isMobile ? 11 : 12, - fontWeight: FontWeight.bold, - ); - final urlStyle = TextStyle( - fontSize: isMobile ? 9 : 10, - color: Colors.grey.shade600, - ); - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - if (_currentTitle != null) - Text( - _currentTitle!, - style: titleStyle, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - if (_currentUrl != null) - Text( - _currentUrl!, - style: urlStyle, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ], - ); - } - - Widget _buildWebView(SettingsManager settingsManager) { - final baseSettings = settingsManager.buildSettings(); - final mergedSettings = - InAppWebViewSettings.fromMap({ - ...baseSettings.toMap(), - 'useShouldOverrideUrlLoading': true, - 'useShouldInterceptAjaxRequest': true, - 'useShouldInterceptFetchRequest': true, - 'useShouldInterceptRequest': true, - 'useOnLoadResource': true, - 'useOnDownloadStart': true, - 'mediaPlaybackRequiresUserGesture': false, - 'javaScriptEnabled': true, - 'javaScriptCanOpenWindowsAutomatically': true, - }) ?? - InAppWebViewSettings(); - - return InAppWebView( - key: ValueKey( - 'webview-${settingsManager.settingsRevision}-${settingsManager.environmentRevision}', - ), - initialUrlRequest: URLRequest(url: WebUri(_urlController.text)), - webViewEnvironment: settingsManager.webViewEnvironment, - initialSettings: mergedSettings, - - // ============================================================ - // CORE EVENTS (8) - // ============================================================ - - // 1. onWebViewCreated - onWebViewCreated: (controller) { - _webViewController = controller; - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onWebViewCreated.name, - data: {'viewId': controller.getViewId()}, - ); - }, - - // 2. onLoadStart - onLoadStart: (controller, url) { - _forceShowReloadAfterStop = false; - _logEvent( - EventType.navigation, - PlatformWebViewCreationParamsProperty.onLoadStart.name, - data: {'url': url?.toString()}, - ); - if (url != null) { - _urlController.text = url.toString(); - } - _updateNavigationState(); - }, - - // 3. onLoadStop - onLoadStop: (controller, url) async { - _forceShowReloadAfterStop = false; - _logEvent( - EventType.navigation, - PlatformWebViewCreationParamsProperty.onLoadStop.name, - data: {'url': url?.toString()}, - ); - if (url != null) { - _urlController.text = url.toString(); - } - _updateNavigationState(); - final title = await controller.getTitle(); - setState(() { - _currentUrl = url?.toString(); - _currentTitle = title; - }); - }, - - // 4. onReceivedError - onReceivedError: (controller, request, error) { - _logEvent( - EventType.error, - PlatformWebViewCreationParamsProperty.onReceivedError.name, - data: { - 'url': request.url.toString(), - 'errorType': error.type.name(), - 'description': error.description, - }, - ); - }, - - // 5. onReceivedHttpError - onReceivedHttpError: (controller, request, response) { - _logEvent( - EventType.error, - PlatformWebViewCreationParamsProperty.onReceivedHttpError.name, - data: { - 'url': request.url.toString(), - 'statusCode': response.statusCode, - 'reasonPhrase': response.reasonPhrase, - }, - ); - }, - - // 6. onProgressChanged - onProgressChanged: (controller, progress) { - setState(() { - _progress = progress / 100; - if (_progress >= 1.0) { - _forceShowReloadAfterStop = false; - } - }); - _logEvent( - EventType.performance, - PlatformWebViewCreationParamsProperty.onProgressChanged.name, - data: {'progress': progress}, - ); - }, - - // 7. onConsoleMessage - onConsoleMessage: (controller, consoleMessage) { - _logEvent( - EventType.console, - PlatformWebViewCreationParamsProperty.onConsoleMessage.name, - data: { - 'message': consoleMessage.message, - 'level': consoleMessage.messageLevel.name(), - }, - ); - }, - - // 8. onTitleChanged - onTitleChanged: (controller, title) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onTitleChanged.name, - data: {'title': title}, - ); - setState(() { - _currentTitle = title; - }); - }, - - // ============================================================ - // NAVIGATION EVENTS (6) - // ============================================================ - - // 9. shouldOverrideUrlLoading - shouldOverrideUrlLoading: (controller, navigationAction) async { - final url = navigationAction.request.url; - _logEvent( - EventType.navigation, - PlatformWebViewCreationParamsProperty.shouldOverrideUrlLoading.name, - data: { - 'url': url?.toString(), - 'isForMainFrame': navigationAction.isForMainFrame, - 'navigationType': navigationAction.navigationType?.name(), - }, - ); - - // Monitor network requests if enabled - final monitor = context.read(); - if (monitor.isMonitoring) { - final requestId = DateTime.now().millisecondsSinceEpoch.toString(); - monitor.addRequest( - NetworkRequest( - id: requestId, - method: 'GET', - url: url?.toString() ?? '', - timestamp: DateTime.now(), - ), - ); - } - - return NavigationActionPolicy.ALLOW; - }, - - // 10. onLoadResource - onLoadResource: (controller, resource) { - // _logEvent( - // EventType.network, - // PlatformWebViewCreationParamsProperty.onLoadResource.name, - // data: { - // 'url': resource.url?.toString(), - // 'initiatorType': resource.initiatorType, - // 'startTime': resource.startTime, - // 'duration': resource.duration, - // }, - // ); - }, - - // 11. onUpdateVisitedHistory - onUpdateVisitedHistory: (controller, url, isReload) { - _logEvent( - EventType.navigation, - PlatformWebViewCreationParamsProperty.onUpdateVisitedHistory.name, - data: {'url': url?.toString(), 'isReload': isReload}, - ); - if (url != null) { - _urlController.text = url.toString(); - } - _updateNavigationState(); - }, - - // 12. onPageCommitVisible - onPageCommitVisible: (controller, url) { - _logEvent( - EventType.navigation, - PlatformWebViewCreationParamsProperty.onPageCommitVisible.name, - data: {'url': url?.toString()}, - ); - if (url != null) { - _urlController.text = url.toString(); - } - }, - - // 13. onNavigationResponse - onNavigationResponse: (controller, navigationResponse) async { - _logEvent( - EventType.navigation, - PlatformWebViewCreationParamsProperty.onNavigationResponse.name, - data: { - 'url': navigationResponse.response?.url?.toString(), - 'statusCode': navigationResponse.response?.statusCode, - 'isForMainFrame': navigationResponse.isForMainFrame, - 'canShowMIMEType': navigationResponse.canShowMIMEType, - }, - ); - return NavigationResponseAction.ALLOW; - }, - - // 14. onDidReceiveServerRedirectForProvisionalNavigation - onDidReceiveServerRedirectForProvisionalNavigation: (controller) { - _logEvent( - EventType.navigation, - PlatformWebViewCreationParamsProperty - .onDidReceiveServerRedirectForProvisionalNavigation - .name, - ); - }, - - // ============================================================ - // WINDOW EVENTS (4) - // ============================================================ - - // 15. onCreateWindow - onCreateWindow: (controller, createWindowAction) async { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onCreateWindow.name, - data: { - 'url': createWindowAction.request.url?.toString(), - 'windowId': createWindowAction.windowId, - 'isForMainFrame': createWindowAction.isForMainFrame, - }, - ); - return false; // Don't create a new window - }, - - // 16. onCloseWindow - onCloseWindow: (controller) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onCloseWindow.name, - ); - }, - - // 17. onWindowFocus - onWindowFocus: (controller) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onWindowFocus.name, - ); - }, - - // 18. onWindowBlur - onWindowBlur: (controller) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onWindowBlur.name, - ); - }, - - // ============================================================ - // JAVASCRIPT DIALOG EVENTS (4) - // ============================================================ - - // 19. onJsAlert - onJsAlert: (controller, jsAlertRequest) async { - _logEvent( - EventType.javascript, - PlatformWebViewCreationParamsProperty.onJsAlert.name, - data: { - 'message': jsAlertRequest.message, - 'url': jsAlertRequest.url?.toString(), - }, - ); - return JsAlertResponse(handledByClient: false); - }, - - // 20. onJsConfirm - onJsConfirm: (controller, jsConfirmRequest) async { - _logEvent( - EventType.javascript, - PlatformWebViewCreationParamsProperty.onJsConfirm.name, - data: { - 'message': jsConfirmRequest.message, - 'url': jsConfirmRequest.url?.toString(), - }, - ); - return JsConfirmResponse(handledByClient: false); - }, - - // 21. onJsPrompt - onJsPrompt: (controller, jsPromptRequest) async { - _logEvent( - EventType.javascript, - PlatformWebViewCreationParamsProperty.onJsPrompt.name, - data: { - 'message': jsPromptRequest.message, - 'defaultValue': jsPromptRequest.defaultValue, - 'url': jsPromptRequest.url?.toString(), - }, - ); - return JsPromptResponse(handledByClient: false); - }, - - // 22. onJsBeforeUnload - onJsBeforeUnload: (controller, jsBeforeUnloadRequest) async { - _logEvent( - EventType.javascript, - PlatformWebViewCreationParamsProperty.onJsBeforeUnload.name, - data: { - 'message': jsBeforeUnloadRequest.message, - 'url': jsBeforeUnloadRequest.url?.toString(), - }, - ); - return JsBeforeUnloadResponse(handledByClient: false); - }, - - // ============================================================ - // AUTHENTICATION EVENTS (3) - // ============================================================ - - // 23. onReceivedHttpAuthRequest - onReceivedHttpAuthRequest: (controller, challenge) async { - _logEvent( - EventType.network, - PlatformWebViewCreationParamsProperty.onReceivedHttpAuthRequest.name, - data: { - 'host': challenge.protectionSpace.host, - 'port': challenge.protectionSpace.port, - 'protocol': challenge.protectionSpace.protocol, - 'realm': challenge.protectionSpace.realm, - }, - ); - return HttpAuthResponse(action: HttpAuthResponseAction.CANCEL); - }, - - // 24. onReceivedServerTrustAuthRequest - onReceivedServerTrustAuthRequest: (controller, challenge) async { - _logEvent( - EventType.network, - PlatformWebViewCreationParamsProperty - .onReceivedServerTrustAuthRequest - .name, - data: { - 'host': challenge.protectionSpace.host, - 'port': challenge.protectionSpace.port, - 'protocol': challenge.protectionSpace.protocol, - }, - ); - return ServerTrustAuthResponse( - action: ServerTrustAuthResponseAction.PROCEED, - ); - }, - - // 25. onReceivedClientCertRequest - onReceivedClientCertRequest: (controller, challenge) async { - _logEvent( - EventType.network, - PlatformWebViewCreationParamsProperty - .onReceivedClientCertRequest - .name, - data: { - 'host': challenge.protectionSpace.host, - 'port': challenge.protectionSpace.port, - 'protocol': challenge.protectionSpace.protocol, - }, - ); - return ClientCertResponse(action: ClientCertResponseAction.CANCEL); - }, - - // ============================================================ - // NETWORK INTERCEPTION EVENTS (6) - // ============================================================ - - // 26. shouldInterceptAjaxRequest - shouldInterceptAjaxRequest: (controller, ajaxRequest) async { - _logEvent( - EventType.network, - PlatformWebViewCreationParamsProperty.shouldInterceptAjaxRequest.name, - data: { - 'url': ajaxRequest.url?.toString(), - 'method': ajaxRequest.method, - 'isAsync': ajaxRequest.isAsync, - }, - ); - return ajaxRequest; - }, - - // 27. onAjaxReadyStateChange - onAjaxReadyStateChange: (controller, ajaxRequest) async { - _logEvent( - EventType.network, - PlatformWebViewCreationParamsProperty.onAjaxReadyStateChange.name, - data: { - 'url': ajaxRequest.url?.toString(), - 'method': ajaxRequest.method, - 'readyState': ajaxRequest.readyState?.name(), - 'status': ajaxRequest.status, - }, - ); - return AjaxRequestAction.PROCEED; - }, - - // 28. onAjaxProgress - onAjaxProgress: (controller, ajaxRequest) async { - _logEvent( - EventType.network, - PlatformWebViewCreationParamsProperty.onAjaxProgress.name, - data: { - 'url': ajaxRequest.url?.toString(), - 'method': ajaxRequest.method, - 'status': ajaxRequest.status, - }, - ); - return AjaxRequestAction.PROCEED; - }, - - // 29. shouldInterceptFetchRequest - shouldInterceptFetchRequest: (controller, fetchRequest) async { - _logEvent( - EventType.network, - PlatformWebViewCreationParamsProperty - .shouldInterceptFetchRequest - .name, - data: { - 'url': fetchRequest.url?.toString(), - 'method': fetchRequest.method, - 'mode': fetchRequest.mode, - 'credentialsType': fetchRequest.credentials?.type, - }, - ); - return fetchRequest; - }, - - // 30. shouldInterceptRequest - shouldInterceptRequest: (controller, request) async { - _logEvent( - EventType.network, - PlatformWebViewCreationParamsProperty.shouldInterceptRequest.name, - data: { - 'url': request.url.toString(), - 'method': request.method, - 'isForMainFrame': request.isForMainFrame, - }, - ); - return null; // Don't intercept - }, - - // 31. onLoadResourceWithCustomScheme - onLoadResourceWithCustomScheme: (controller, request) async { - _logEvent( - EventType.network, - PlatformWebViewCreationParamsProperty - .onLoadResourceWithCustomScheme - .name, - data: {'url': request.url.toString(), 'scheme': request.url.scheme}, - ); - return null; // Don't handle custom scheme - }, - - // ============================================================ - // DOWNLOAD EVENTS (1) - // ============================================================ - - // 32. onDownloadStarting - onDownloadStarting: (controller, downloadStartRequest) async { - _logEvent( - EventType.network, - PlatformWebViewCreationParamsProperty.onDownloadStarting.name, - data: { - 'url': downloadStartRequest.url.toString(), - 'mimeType': downloadStartRequest.mimeType, - 'contentLength': downloadStartRequest.contentLength, - 'suggestedFilename': downloadStartRequest.suggestedFilename, - }, - ); - return DownloadStartResponse( - handled: true, - action: DownloadStartResponseAction.CANCEL, - ); - }, - - // ============================================================ - // SCROLL EVENTS (2) - // ============================================================ - - // 33. onScrollChanged - onScrollChanged: (controller, x, y) { - // _logEvent( - // EventType.ui, - // PlatformWebViewCreationParamsProperty.onScrollChanged.name, - // data: {'x': x, 'y': y}, - // ); - }, - - // 34. onOverScrolled - onOverScrolled: (controller, x, y, clampedX, clampedY) { - // _logEvent( - // EventType.ui, - // PlatformWebViewCreationParamsProperty.onOverScrolled.name, - // data: {'x': x, 'y': y, 'clampedX': clampedX, 'clampedY': clampedY}, - // ); - }, - - // ============================================================ - // ZOOM EVENTS (1) - // ============================================================ - - // 35. onZoomScaleChanged - onZoomScaleChanged: (controller, oldScale, newScale) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onZoomScaleChanged.name, - data: {'oldScale': oldScale, 'newScale': newScale}, - ); - }, - - // ============================================================ - // PRINT EVENTS (1) - // ============================================================ - - // 36. onPrintRequest - onPrintRequest: (controller, url, printJobController) async { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onPrintRequest.name, - data: {'url': url?.toString()}, - ); - return false; // Don't handle print - }, - - // ============================================================ - // FULLSCREEN EVENTS (2) - // ============================================================ - - // 37. onEnterFullscreen - onEnterFullscreen: (controller) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onEnterFullscreen.name, - ); - }, - - // 38. onExitFullscreen - onExitFullscreen: (controller) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onExitFullscreen.name, - ); - }, - - // ============================================================ - // PERMISSION EVENTS (4) - // ============================================================ - - // 39. onPermissionRequest - onPermissionRequest: (controller, permissionRequest) async { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onPermissionRequest.name, - data: { - 'resources': permissionRequest.resources - .map((r) => r.name) - .toList(), - }, - ); - return PermissionResponse( - resources: permissionRequest.resources, - action: PermissionResponseAction.GRANT, - ); - }, - - // 40. onPermissionRequestCanceled - onPermissionRequestCanceled: (controller, permissionRequest) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty - .onPermissionRequestCanceled - .name, - data: { - 'resources': permissionRequest.resources - .map((r) => r.name) - .toList(), - }, - ); - }, - - // 41. onGeolocationPermissionsShowPrompt - onGeolocationPermissionsShowPrompt: (controller, origin) async { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty - .onGeolocationPermissionsShowPrompt - .name, - data: {'origin': origin}, - ); - return GeolocationPermissionShowPromptResponse( - origin: origin, - allow: false, - retain: false, - ); - }, - - // 42. onGeolocationPermissionsHidePrompt - onGeolocationPermissionsHidePrompt: (controller) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty - .onGeolocationPermissionsHidePrompt - .name, - ); - }, - - // ============================================================ - // TOUCH & HIT TEST EVENTS (1) - // ============================================================ - - // 43. onLongPressHitTestResult - onLongPressHitTestResult: (controller, hitTestResult) async { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onLongPressHitTestResult.name, - data: { - 'type': hitTestResult.type?.name(), - 'extra': hitTestResult.extra, - }, - ); - }, - - // ============================================================ - // RENDER PROCESS EVENTS (3) - // ============================================================ - - // 44. onRenderProcessUnresponsive - onRenderProcessUnresponsive: (controller, url) async { - _logEvent( - EventType.error, - PlatformWebViewCreationParamsProperty - .onRenderProcessUnresponsive - .name, - data: {'url': url?.toString()}, - ); - return WebViewRenderProcessAction.TERMINATE; - }, - - // 45. onRenderProcessResponsive - onRenderProcessResponsive: (controller, url) async { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onRenderProcessResponsive.name, - data: {'url': url?.toString()}, - ); - return WebViewRenderProcessAction.TERMINATE; - }, - - // 46. onRenderProcessGone - onRenderProcessGone: (controller, detail) { - _logEvent( - EventType.error, - PlatformWebViewCreationParamsProperty.onRenderProcessGone.name, - data: { - 'didCrash': detail.didCrash, - 'rendererPriorityAtExit': detail.rendererPriorityAtExit?.name(), - }, - ); - }, - - // ============================================================ - // FORM EVENTS (2) - // ============================================================ - - // 47. onFormResubmission - onFormResubmission: (controller, url) async { - _logEvent( - EventType.navigation, - PlatformWebViewCreationParamsProperty.onFormResubmission.name, - data: {'url': url?.toString()}, - ); - return FormResubmissionAction.DONT_RESEND; - }, - - // 48. onReceivedLoginRequest - onReceivedLoginRequest: (controller, loginRequest) { - _logEvent( - EventType.network, - PlatformWebViewCreationParamsProperty.onReceivedLoginRequest.name, - data: { - 'realm': loginRequest.realm, - 'account': loginRequest.account, - 'args': loginRequest.args, - }, - ); - }, - - // ============================================================ - // ICON EVENTS (2) - // ============================================================ - - // 49. onReceivedIcon - onReceivedIcon: (controller, icon) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onReceivedIcon.name, - data: {'iconSize': icon.length}, - ); - }, - - // 50. onReceivedTouchIconUrl - onReceivedTouchIconUrl: (controller, url, precomposed) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onReceivedTouchIconUrl.name, - data: {'url': url.toString(), 'precomposed': precomposed}, - ); - }, - - // ============================================================ - // SAFE BROWSING EVENTS (1) - // ============================================================ - - // 51. onSafeBrowsingHit - onSafeBrowsingHit: (controller, url, threatType) async { - _logEvent( - EventType.error, - PlatformWebViewCreationParamsProperty.onSafeBrowsingHit.name, - data: {'url': url.toString(), 'threatType': threatType?.name}, - ); - return SafeBrowsingResponse( - report: true, - action: SafeBrowsingResponseAction.BACK_TO_SAFETY, - ); - }, - - // ============================================================ - // ADDITIONAL EVENTS (5) - // ============================================================ - - // 52. onWebContentProcessDidTerminate - onWebContentProcessDidTerminate: (controller) { - _logEvent( - EventType.error, - PlatformWebViewCreationParamsProperty - .onWebContentProcessDidTerminate - .name, - ); - }, - - // 53. shouldAllowDeprecatedTLS - shouldAllowDeprecatedTLS: (controller, challenge) async { - _logEvent( - EventType.network, - PlatformWebViewCreationParamsProperty.shouldAllowDeprecatedTLS.name, - data: { - 'host': challenge.protectionSpace.host, - 'port': challenge.protectionSpace.port, - 'protocol': challenge.protectionSpace.protocol, - }, - ); - return ShouldAllowDeprecatedTLSAction.CANCEL; - }, - - // 54. onCameraCaptureStateChanged - onCameraCaptureStateChanged: (controller, oldState, newState) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty - .onCameraCaptureStateChanged - .name, - data: {'oldState': oldState?.name(), 'newState': newState?.name()}, - ); - }, - - // 55. onMicrophoneCaptureStateChanged - onMicrophoneCaptureStateChanged: (controller, oldState, newState) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty - .onMicrophoneCaptureStateChanged - .name, - data: {'oldState': oldState?.name(), 'newState': newState?.name()}, - ); - }, - - // 56. onContentSizeChanged - onContentSizeChanged: (controller, oldContentSize, newContentSize) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onContentSizeChanged.name, - data: { - 'oldWidth': oldContentSize.width, - 'oldHeight': oldContentSize.height, - 'newWidth': newContentSize.width, - 'newHeight': newContentSize.height, - }, - ); - }, - - // ============================================================ - // SYSTEM EVENTS (2) - // ============================================================ - - // 57. onProcessFailed - onProcessFailed: (controller, detail) { - _logEvent( - EventType.error, - PlatformWebViewCreationParamsProperty.onProcessFailed.name, - data: { - 'kind': detail.kind.name(), - 'reason': detail.reason?.name(), - 'exitCode': detail.exitCode, - }, - ); - }, - - // 58. onAcceleratorKeyPressed - onAcceleratorKeyPressed: (controller, keyEventInfo) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onAcceleratorKeyPressed.name, - data: { - 'keyEventKind': keyEventInfo.keyEventKind, - 'virtualKey': keyEventInfo.virtualKey, - 'physicalKeyStatus': keyEventInfo.physicalKeyStatus?.toMap(), - }, - ); - }, - - // ============================================================ - // OTHER EVENTS (2) - // ============================================================ - - // 59. onRequestFocus - onRequestFocus: (controller) { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onRequestFocus.name, - ); - }, - - // 60. onShowFileChooser - onShowFileChooser: (controller, fileChooserParams) async { - _logEvent( - EventType.ui, - PlatformWebViewCreationParamsProperty.onShowFileChooser.name, - data: { - 'mode': fileChooserParams.mode.name(), - 'acceptTypes': fileChooserParams.acceptTypes, - 'isCaptureEnabled': fileChooserParams.isCaptureEnabled, - }, - ); - return ShowFileChooserResponse(handledByClient: false); - }, - ); - } - - Widget _buildBottomTabs() { - final isMobile = context.isMobile; - return Container( - decoration: BoxDecoration( - border: Border(top: BorderSide(color: Colors.grey.shade300)), - ), - child: Column( - children: [ - TabBar( - controller: _tabController, - isScrollable: isMobile, - labelColor: Colors.blue, - unselectedLabelColor: Colors.grey, - indicatorColor: Colors.blue, - labelStyle: TextStyle(fontSize: isMobile ? 12 : 14), - unselectedLabelStyle: TextStyle(fontSize: isMobile ? 12 : 14), - labelPadding: isMobile - ? const EdgeInsets.symmetric(horizontal: 10) - : null, - tabs: const [ - Tab(text: 'Events'), - Tab(text: 'Network'), - Tab(text: 'Methods'), - Tab(text: 'JavaScript'), - Tab(text: 'UserScripts'), - ], - ), - Expanded( - child: TabBarView( - controller: _tabController, - children: [ - const EventConsoleWidget(), - const NetworkMonitorWidget(), - MethodTesterWidget(controller: _webViewController), - JavaScriptConsoleWidget( - onExecute: (code) => - _webViewController!.evaluateJavascript(source: code), - onExecuteAsync: (code) => _webViewController! - .callAsyncJavaScript(functionBody: code), - ), - UserScriptTesterWidget( - onAddScript: _addUserScript, - onRemoveScript: _removeUserScript, - scripts: _userScripts, - ), - ], - ), - ), - ], - ), - ); - } - - Future _loadUrl() async { - final url = _urlController.text.trim(); - if (url.isEmpty) return; - - // Add https:// if no protocol specified - String finalUrl = url; - if (!url.startsWith('http://') && !url.startsWith('https://')) { - finalUrl = 'https://$url'; - } - - await _webViewController?.loadUrl( - urlRequest: URLRequest(url: WebUri(finalUrl)), - ); - - _logEvent(EventType.navigation, 'Loading URL: $finalUrl'); - } - - Future _updateNavigationState() async { - if (_webViewController == null) return; - - final canGoBack = await _webViewController!.canGoBack(); - final canGoForward = await _webViewController!.canGoForward(); - - if (mounted) { - setState(() { - _canGoBack = canGoBack; - _canGoForward = canGoForward; - }); - } - } - - void _logEvent(EventType type, String message, {Map? data}) { - context.read().addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: type, - message: message, - data: data, - ), - ); - } - - Future _addUserScript(UserScript script) async { - if (_webViewController == null) { - throw Exception('WebView not initialized'); - } - - await _webViewController!.addUserScript(userScript: script); - - setState(() { - _userScripts.add(script); - }); - - _logEvent( - EventType.javascript, - 'User script added', - data: {'injectionTime': script.injectionTime.name}, - ); - } - - Future _removeUserScript(UserScript script) async { - if (_webViewController == null) { - throw Exception('WebView not initialized'); - } - - await _webViewController!.removeUserScript(userScript: script); - - setState(() { - _userScripts.remove(script); - }); - - _logEvent(EventType.javascript, 'User script removed'); - } -} diff --git a/flutter_inappwebview/example/lib/utils/constants.dart b/flutter_inappwebview/example/lib/utils/constants.dart deleted file mode 100644 index ef204dea95..0000000000 --- a/flutter_inappwebview/example/lib/utils/constants.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'package:flutter/material.dart'; - -/// Test categories for organizing tests -enum TestCategory { - navigation('Navigation', 'Tests for navigation-related methods'), - javascript('JavaScript', 'Tests for JavaScript execution and handlers'), - content('Content', 'Tests for content manipulation and retrieval'), - storage('Storage', 'Tests for storage and cookie management'), - advanced('Advanced', 'Advanced and misc test cases'), - browsers('Browsers', 'Tests for browser-related functionality'); - - final String displayName; - final String description; - - const TestCategory(this.displayName, this.description); -} - -/// Test complexity levels -enum TestComplexity { - quick, // < 1 second - medium, // 1-5 seconds - long, // 5-30 seconds - interactive, // Requires user interaction -} - -/// Color constants for performance indicators -class PerformanceColors { - static const Color fast = Color(0xFF4CAF50); // Green < 100ms - static const Color medium = Color(0xFFFFC107); // Yellow 100-500ms - static const Color slow = Color(0xFFF44336); // Red >= 500ms -} - -/// Performance thresholds in milliseconds -class PerformanceThresholds { - static const int fast = 100; - static const int medium = 500; -} diff --git a/flutter_inappwebview/example/lib/utils/controller_methods_registry.dart b/flutter_inappwebview/example/lib/utils/controller_methods_registry.dart deleted file mode 100644 index c8f86134e9..0000000000 --- a/flutter_inappwebview/example/lib/utils/controller_methods_registry.dart +++ /dev/null @@ -1,1231 +0,0 @@ -import 'dart:convert'; -import 'dart:typed_data'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; - -List _safeEnumValues(Iterable Function() getter) { - try { - return getter().toList(); - } catch (_) { - return []; - } -} - -/// Extracts the raw value from a parameter, unwrapping ParameterValueHint if necessary -T? extractParam(dynamic value) { - if (value == null) return null; - if (value is ParameterValueHint) { - return value.value as T?; - } - if (value is T) return value; - return null; -} - -/// Enum representing the categories of controller methods -enum ControllerMethodCategoryType { - navigation('Navigation & Loading', Icons.navigation), - pageInfo('Page Info & Content', Icons.info_outline), - javascript('JavaScript Execution', Icons.code), - jsHandlers('JavaScript Handlers', Icons.link), - userScripts('User Scripts', Icons.description), - scrolling('Scrolling & Layout', Icons.swap_vert), - zoom('Zoom', Icons.zoom_in), - settings('Settings & State', Icons.settings), - screenshotPrint('Screenshot & Print', Icons.camera_alt), - cacheHistory('Cache & History', Icons.history), - pauseResume('Pause & Resume', Icons.pause_circle_outline), - webMessaging('Web Messaging', Icons.message), - media('Media & Fullscreen', Icons.play_circle_outline), - cameraMic('Camera & Microphone', Icons.videocam), - security('Security', Icons.security), - saveRestore('Save & Restore', Icons.save), - misc('Misc/Advanced', Icons.more_horiz); - - final String displayName; - final IconData icon; - - const ControllerMethodCategoryType(this.displayName, this.icon); -} - -/// Method entry for a single controller method -class ControllerMethodEntry { - /// The method enum that this entry represents. - /// The id and name are derived from methodEnum.name. - final PlatformInAppWebViewControllerMethod methodEnum; - final String description; - final Map parameters; - final List requiredParameters; - final Future Function( - InAppWebViewController controller, - Map params, - ) - execute; - - const ControllerMethodEntry({ - required this.methodEnum, - required this.description, - this.parameters = const {}, - this.requiredParameters = const [], - required this.execute, - }); - - /// The unique identifier derived from methodEnum.name - String get id => methodEnum.name; - - /// The display name derived from methodEnum.name - String get name => methodEnum.name; - - Map toJson() { - return { - 'id': id, - 'name': name, - 'description': description, - 'methodEnum': methodEnum.name, - 'parameters': _serializeParameters(parameters), - 'requiredParameters': requiredParameters, - }; - } - - static Map _serializeParameters( - Map params, - ) { - final result = {}; - params.forEach((key, value) { - if (value is ParameterValueHint) { - result[key] = { - '_type': 'hint', - 'valueType': value.type.name, - 'value': value.value is Uint8List - ? base64.encode(value.value as Uint8List) - : value.value, - }; - } else if (value is Uint8List) { - result[key] = {'_type': 'bytes', 'value': base64.encode(value)}; - } else { - result[key] = value; - } - }); - return result; - } - - /// Creates a copy with updated parameters - ControllerMethodEntry copyWithParameters(Map newParams) { - return ControllerMethodEntry( - methodEnum: methodEnum, - description: description, - parameters: newParams, - requiredParameters: requiredParameters, - execute: execute, - ); - } -} - -/// A category of methods -class ControllerMethodCategory { - /// The category type enum - id, name and icon are derived from this - final ControllerMethodCategoryType categoryType; - final List methods; - - const ControllerMethodCategory({ - required this.categoryType, - required this.methods, - }); - - /// The unique identifier derived from categoryType.name - String get id => categoryType.name; - - /// The display name derived from categoryType.displayName - String get name => categoryType.displayName; - - /// The icon derived from categoryType.icon - IconData get icon => categoryType.icon; -} - -/// Registry of all controller methods organized by category -class ControllerMethodsRegistry { - static ControllerMethodsRegistry? _instance; - - ControllerMethodsRegistry._(); - - static ControllerMethodsRegistry get instance { - _instance ??= ControllerMethodsRegistry._(); - return _instance!; - } - - late final List _categories = _buildAllCategories(); - - List get categories => _categories; - - /// Get all methods across all categories - List get allMethods { - final methods = []; - for (final category in _categories) { - methods.addAll(category.methods); - } - return methods; - } - - /// Find a method by its ID - ControllerMethodEntry? findMethodById(String id) { - for (final category in _categories) { - for (final method in category.methods) { - if (method.id == id) return method; - } - } - return null; - } - - /// Find a method by its name - ControllerMethodEntry? findMethodByName(String name) { - for (final category in _categories) { - for (final method in category.methods) { - if (method.name == name) return method; - } - } - return null; - } - - /// Get methods filtered by search query - List searchMethods(String query) { - if (query.isEmpty) return allMethods; - final lowerQuery = query.toLowerCase(); - return allMethods - .where( - (m) => - m.name.toLowerCase().contains(lowerQuery) || - m.description.toLowerCase().contains(lowerQuery), - ) - .toList(); - } - - /// Get categories filtered by search query - List searchCategories(String query) { - if (query.isEmpty) return _categories; - final lowerQuery = query.toLowerCase(); - return _categories - .map((category) { - final filteredMethods = category.methods - .where( - (m) => - m.name.toLowerCase().contains(lowerQuery) || - m.description.toLowerCase().contains(lowerQuery), - ) - .toList(); - return ControllerMethodCategory( - categoryType: category.categoryType, - methods: filteredMethods, - ); - }) - .where((category) => category.methods.isNotEmpty) - .toList(); - } - - List _buildAllCategories() { - return [ - _buildNavigationCategory(), - _buildPageInfoCategory(), - _buildJavaScriptCategory(), - _buildJavaScriptHandlersCategory(), - _buildUserScriptsCategory(), - _buildScrollingCategory(), - _buildZoomCategory(), - _buildSettingsCategory(), - _buildScreenshotPrintCategory(), - _buildCacheHistoryCategory(), - _buildPauseResumeCategory(), - _buildWebMessagingCategory(), - _buildMediaCategory(), - _buildCameraMicCategory(), - _buildSecurityCategory(), - _buildSaveRestoreCategory(), - _buildMiscCategory(), - ]; - } - - // ============================================================ - // NAVIGATION & LOADING CATEGORY - // ============================================================ - ControllerMethodCategory _buildNavigationCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.navigation, - methods: [ - ControllerMethodEntry( - description: 'Loads the given URL', - methodEnum: PlatformInAppWebViewControllerMethod.loadUrl, - parameters: { - 'url': 'https://example.com', - 'method': 'GET', - 'headers': {}, - 'body': const ParameterValueHint( - null, - ParameterValueType.bytes, - ), - }, - requiredParameters: ['url'], - execute: (controller, params) async { - final url = params['url']?.toString() ?? ''; - final method = params['method']?.toString(); - final headers = (params['headers'] as Map?)?.map( - (key, value) => MapEntry(key.toString(), value), - ); - final body = extractParam(params['body']); - - await controller.loadUrl( - urlRequest: URLRequest( - url: WebUri(url), - method: method?.isNotEmpty == true ? method : null, - headers: headers?.cast(), - body: body, - ), - ); - return 'URL loaded successfully'; - }, - ), - ControllerMethodEntry( - description: 'Loads URL using POST method', - methodEnum: PlatformInAppWebViewControllerMethod.postUrl, - parameters: { - 'url': 'https://httpbin.org/post', - 'postData': const ParameterValueHint( - null, - ParameterValueType.bytes, - ), - }, - requiredParameters: ['url', 'postData'], - execute: (controller, params) async { - final url = params['url']?.toString() ?? ''; - Uint8List? postData = extractParam(params['postData']); - // Also handle string input by converting to bytes - if (postData == null) { - final postDataParam = params['postData']; - if (postDataParam is String && postDataParam.isNotEmpty) { - postData = Uint8List.fromList(postDataParam.codeUnits); - } - } - await controller.postUrl( - url: WebUri(url), - postData: postData ?? Uint8List(0), - ); - return 'POST request sent with ${postData?.length ?? 0} bytes'; - }, - ), - ControllerMethodEntry( - description: 'Loads HTML data string', - methodEnum: PlatformInAppWebViewControllerMethod.loadData, - parameters: { - 'data': '

Test HTML

', - 'mimeType': 'text/html', - 'encoding': 'utf-8', - 'baseUrl': '', - 'historyUrl': '', - }, - requiredParameters: ['data'], - execute: (controller, params) async { - final data = params['data']?.toString() ?? ''; - final mimeType = params['mimeType']?.toString(); - final encoding = params['encoding']?.toString(); - final baseUrl = params['baseUrl']?.toString(); - final historyUrl = params['historyUrl']?.toString(); - - await controller.loadData( - data: data, - mimeType: mimeType?.isNotEmpty == true ? mimeType! : 'text/html', - encoding: encoding?.isNotEmpty == true ? encoding! : 'utf-8', - baseUrl: baseUrl?.isNotEmpty == true ? WebUri(baseUrl!) : null, - historyUrl: historyUrl?.isNotEmpty == true - ? WebUri(historyUrl!) - : null, - ); - return 'HTML data loaded'; - }, - ), - ControllerMethodEntry( - description: 'Loads a file from assets', - methodEnum: PlatformInAppWebViewControllerMethod.loadFile, - parameters: {'assetFilePath': 'assets/index.html'}, - requiredParameters: ['assetFilePath'], - execute: (controller, params) async { - final path = params['assetFilePath']?.toString() ?? ''; - await controller.loadFile(assetFilePath: path); - return 'File loaded from assets'; - }, - ), - ControllerMethodEntry( - description: 'Reloads the current page', - methodEnum: PlatformInAppWebViewControllerMethod.reload, - execute: (controller, params) async { - await controller.reload(); - return 'Page reloaded'; - }, - ), - ControllerMethodEntry( - description: 'Reloads bypassing cache', - methodEnum: PlatformInAppWebViewControllerMethod.reloadFromOrigin, - execute: (controller, params) async { - await controller.reloadFromOrigin(); - return 'Page reloaded from origin'; - }, - ), - ControllerMethodEntry( - description: 'Navigates back in history', - methodEnum: PlatformInAppWebViewControllerMethod.goBack, - execute: (controller, params) async { - await controller.goBack(); - return 'Navigated back'; - }, - ), - ControllerMethodEntry( - description: 'Navigates forward in history', - methodEnum: PlatformInAppWebViewControllerMethod.goForward, - execute: (controller, params) async { - await controller.goForward(); - return 'Navigated forward'; - }, - ), - ControllerMethodEntry( - description: 'Navigates by steps', - methodEnum: PlatformInAppWebViewControllerMethod.goBackOrForward, - parameters: {'steps': -1}, - requiredParameters: ['steps'], - execute: (controller, params) async { - final steps = (params['steps'] as num?)?.toInt() ?? -1; - await controller.goBackOrForward(steps: steps); - return 'Navigated by steps'; - }, - ), - ControllerMethodEntry( - description: 'Checks if can go back', - methodEnum: PlatformInAppWebViewControllerMethod.canGoBack, - execute: (controller, params) async { - return await controller.canGoBack(); - }, - ), - ControllerMethodEntry( - description: 'Checks if can go forward', - methodEnum: PlatformInAppWebViewControllerMethod.canGoForward, - execute: (controller, params) async { - return await controller.canGoForward(); - }, - ), - ControllerMethodEntry( - description: 'Checks if can navigate by steps', - methodEnum: PlatformInAppWebViewControllerMethod.canGoBackOrForward, - parameters: {'steps': -1}, - requiredParameters: ['steps'], - execute: (controller, params) async { - final steps = (params['steps'] as num?)?.toInt() ?? -1; - return await controller.canGoBackOrForward(steps: steps); - }, - ), - ControllerMethodEntry( - description: 'Checks if page is loading', - methodEnum: PlatformInAppWebViewControllerMethod.isLoading, - execute: (controller, params) async { - return await controller.isLoading(); - }, - ), - ControllerMethodEntry( - description: 'Stops page loading', - methodEnum: PlatformInAppWebViewControllerMethod.stopLoading, - execute: (controller, params) async { - await controller.stopLoading(); - return 'Loading stopped'; - }, - ), - ], - ); - } - - // ============================================================ - // PAGE INFO CATEGORY - // ============================================================ - ControllerMethodCategory _buildPageInfoCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.pageInfo, - methods: [ - ControllerMethodEntry( - description: 'Gets current page URL', - methodEnum: PlatformInAppWebViewControllerMethod.getUrl, - execute: (controller, params) async { - return (await controller.getUrl())?.toString() ?? 'No URL'; - }, - ), - ControllerMethodEntry( - description: 'Gets current page title', - methodEnum: PlatformInAppWebViewControllerMethod.getTitle, - execute: (controller, params) async { - return await controller.getTitle() ?? 'No title'; - }, - ), - ControllerMethodEntry( - description: 'Gets page load progress', - methodEnum: PlatformInAppWebViewControllerMethod.getProgress, - execute: (controller, params) async { - return await controller.getProgress(); - }, - ), - ControllerMethodEntry( - description: 'Gets page HTML source', - methodEnum: PlatformInAppWebViewControllerMethod.getHtml, - execute: (controller, params) async { - final html = await controller.getHtml(); - if (html != null && html.length > 500) { - return '${html.substring(0, 500)}...'; - } - return html ?? 'No HTML'; - }, - ), - ControllerMethodEntry( - description: 'Gets page favicons', - methodEnum: PlatformInAppWebViewControllerMethod.getFavicons, - execute: (controller, params) async { - final favicons = await controller.getFavicons(); - return 'Found ${favicons.length} favicons'; - }, - ), - ControllerMethodEntry( - description: 'Gets original URL before redirects', - methodEnum: PlatformInAppWebViewControllerMethod.getOriginalUrl, - execute: (controller, params) async { - return (await controller.getOriginalUrl())?.toString() ?? 'No URL'; - }, - ), - ControllerMethodEntry( - description: 'Gets selected text', - methodEnum: PlatformInAppWebViewControllerMethod.getSelectedText, - execute: (controller, params) async { - return await controller.getSelectedText() ?? 'No selection'; - }, - ), - ControllerMethodEntry( - description: 'Gets hit test result', - methodEnum: PlatformInAppWebViewControllerMethod.getHitTestResult, - execute: (controller, params) async { - final result = await controller.getHitTestResult(); - return result?.type.toString() ?? 'No hit test result'; - }, - ), - ControllerMethodEntry( - description: 'Gets meta tags from page', - methodEnum: PlatformInAppWebViewControllerMethod.getMetaTags, - execute: (controller, params) async { - final tags = await controller.getMetaTags(); - return 'Found ${tags.length} meta tags'; - }, - ), - ControllerMethodEntry( - description: 'Gets meta theme color', - methodEnum: PlatformInAppWebViewControllerMethod.getMetaThemeColor, - execute: (controller, params) async { - final color = await controller.getMetaThemeColor(); - return color?.toString() ?? 'No theme color'; - }, - ), - ControllerMethodEntry( - description: 'Gets SSL certificate info and X509 data', - methodEnum: PlatformInAppWebViewControllerMethod.getCertificate, - execute: (controller, params) async { - final cert = await controller.getCertificate(); - if (cert == null) return {'error': 'No certificate available'}; - return cert.toMap(); - }, - ), - ControllerMethodEntry( - description: 'Gets navigation history', - methodEnum: - PlatformInAppWebViewControllerMethod.getCopyBackForwardList, - execute: (controller, params) async { - final history = await controller.getCopyBackForwardList(); - return 'History: ${history?.list?.length ?? 0} items, current: ${history?.currentIndex}'; - }, - ), - ], - ); - } - - // ============================================================ - // JAVASCRIPT CATEGORY - // ============================================================ - ControllerMethodCategory _buildJavaScriptCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.javascript, - methods: [ - ControllerMethodEntry( - description: 'Executes JavaScript code', - methodEnum: PlatformInAppWebViewControllerMethod.evaluateJavascript, - parameters: {'source': 'document.title'}, - requiredParameters: ['source'], - execute: (controller, params) async { - return await controller.evaluateJavascript( - source: params['source']?.toString() ?? '', - ); - }, - ), - ControllerMethodEntry( - description: 'Calls async JavaScript function', - methodEnum: PlatformInAppWebViewControllerMethod.callAsyncJavaScript, - parameters: { - 'functionBody': 'return await Promise.resolve("async result");', - 'arguments': {}, - }, - requiredParameters: ['functionBody'], - execute: (controller, params) async { - final arguments = params['arguments'] as Map?; - final result = await controller.callAsyncJavaScript( - functionBody: params['functionBody']?.toString() ?? '', - arguments: arguments?.cast() ?? const {}, - ); - return result?.value ?? 'No result'; - }, - ), - ControllerMethodEntry( - description: 'Injects JS file from URL', - methodEnum: - PlatformInAppWebViewControllerMethod.injectJavascriptFileFromUrl, - parameters: { - 'urlFile': 'https://code.jquery.com/jquery-3.7.1.min.js', - }, - requiredParameters: ['urlFile'], - execute: (controller, params) async { - await controller.injectJavascriptFileFromUrl( - urlFile: WebUri(params['urlFile']?.toString() ?? ''), - ); - return 'JavaScript file injected'; - }, - ), - ControllerMethodEntry( - description: 'Injects CSS code', - methodEnum: PlatformInAppWebViewControllerMethod.injectCSSCode, - parameters: { - 'source': 'body { background-color: #f0f0f0 !important; }', - }, - requiredParameters: ['source'], - execute: (controller, params) async { - await controller.injectCSSCode( - source: params['source']?.toString() ?? '', - ); - return 'CSS code injected'; - }, - ), - ControllerMethodEntry( - description: 'Injects CSS file from URL', - methodEnum: PlatformInAppWebViewControllerMethod.injectCSSFileFromUrl, - parameters: { - 'urlFile': - 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css', - }, - requiredParameters: ['urlFile'], - execute: (controller, params) async { - await controller.injectCSSFileFromUrl( - urlFile: WebUri(params['urlFile']?.toString() ?? ''), - ); - return 'CSS file injected'; - }, - ), - ], - ); - } - - // ============================================================ - // JAVASCRIPT HANDLERS CATEGORY - // ============================================================ - ControllerMethodCategory _buildJavaScriptHandlersCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.jsHandlers, - methods: [ - ControllerMethodEntry( - description: 'Adds a JavaScript handler', - methodEnum: PlatformInAppWebViewControllerMethod.addJavaScriptHandler, - parameters: {'handlerName': 'testHandler'}, - requiredParameters: ['handlerName'], - execute: (controller, params) async { - final handlerName = params['handlerName']?.toString() ?? ''; - controller.addJavaScriptHandler( - handlerName: handlerName, - callback: (args) { - return {'received': args}; - }, - ); - return 'Handler "$handlerName" added'; - }, - ), - ControllerMethodEntry( - description: 'Removes a JavaScript handler', - methodEnum: - PlatformInAppWebViewControllerMethod.removeJavaScriptHandler, - parameters: {'handlerName': 'testHandler'}, - requiredParameters: ['handlerName'], - execute: (controller, params) async { - final removed = controller.removeJavaScriptHandler( - handlerName: params['handlerName']?.toString() ?? '', - ); - return removed != null ? 'Handler removed' : 'Handler not found'; - }, - ), - ControllerMethodEntry( - description: 'Checks if handler exists', - methodEnum: PlatformInAppWebViewControllerMethod.hasJavaScriptHandler, - parameters: {'handlerName': 'testHandler'}, - requiredParameters: ['handlerName'], - execute: (controller, params) async { - return controller.hasJavaScriptHandler( - handlerName: params['handlerName']?.toString() ?? '', - ); - }, - ), - ], - ); - } - - // ============================================================ - // USER SCRIPTS CATEGORY - // ============================================================ - ControllerMethodCategory _buildUserScriptsCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.userScripts, - methods: [ - ControllerMethodEntry( - description: 'Adds a user script', - methodEnum: PlatformInAppWebViewControllerMethod.addUserScript, - parameters: { - 'source': 'console.log("User script executed");', - 'injectionTime': - EnumParameterValueHint.fromIterable( - UserScriptInjectionTime.AT_DOCUMENT_END, - _safeEnumValues(() => UserScriptInjectionTime.values), - ), - 'groupName': 'testGroup', - }, - requiredParameters: ['source'], - execute: (controller, params) async { - final injectionTimeParam = params['injectionTime']; - final injectionTime = injectionTimeParam is UserScriptInjectionTime - ? injectionTimeParam - : _parseUserScriptInjectionTime(injectionTimeParam?.toString()); - await controller.addUserScript( - userScript: UserScript( - source: params['source']?.toString() ?? '', - injectionTime: injectionTime, - groupName: params['groupName']?.toString(), - ), - ); - return 'User script added'; - }, - ), - ControllerMethodEntry( - description: 'Removes all user scripts', - methodEnum: PlatformInAppWebViewControllerMethod.removeAllUserScripts, - execute: (controller, params) async { - await controller.removeAllUserScripts(); - return 'All user scripts removed'; - }, - ), - ], - ); - } - - // ============================================================ - // SCROLLING CATEGORY - // ============================================================ - ControllerMethodCategory _buildScrollingCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.scrolling, - methods: [ - ControllerMethodEntry( - description: 'Scrolls to position', - methodEnum: PlatformInAppWebViewControllerMethod.scrollTo, - parameters: {'x': 0, 'y': 100, 'animated': true}, - execute: (controller, params) async { - final x = (params['x'] as num?)?.toInt() ?? 0; - final y = (params['y'] as num?)?.toInt() ?? 0; - final animated = params['animated'] as bool? ?? true; - await controller.scrollTo(x: x, y: y, animated: animated); - return 'Scrolled to ($x, $y)'; - }, - ), - ControllerMethodEntry( - description: 'Scrolls by offset', - methodEnum: PlatformInAppWebViewControllerMethod.scrollBy, - parameters: {'x': 0, 'y': 50, 'animated': true}, - execute: (controller, params) async { - final x = (params['x'] as num?)?.toInt() ?? 0; - final y = (params['y'] as num?)?.toInt() ?? 0; - final animated = params['animated'] as bool? ?? true; - await controller.scrollBy(x: x, y: y, animated: animated); - return 'Scrolled by ($x, $y)'; - }, - ), - ControllerMethodEntry( - description: 'Gets horizontal scroll position', - methodEnum: PlatformInAppWebViewControllerMethod.getScrollX, - execute: (controller, params) async { - return await controller.getScrollX(); - }, - ), - ControllerMethodEntry( - description: 'Gets vertical scroll position', - methodEnum: PlatformInAppWebViewControllerMethod.getScrollY, - execute: (controller, params) async { - return await controller.getScrollY(); - }, - ), - ControllerMethodEntry( - description: 'Gets content height', - methodEnum: PlatformInAppWebViewControllerMethod.getContentHeight, - execute: (controller, params) async { - return await controller.getContentHeight(); - }, - ), - ControllerMethodEntry( - description: 'Gets content width', - methodEnum: PlatformInAppWebViewControllerMethod.getContentWidth, - execute: (controller, params) async { - return await controller.getContentWidth(); - }, - ), - ], - ); - } - - // ============================================================ - // ZOOM CATEGORY - // ============================================================ - ControllerMethodCategory _buildZoomCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.zoom, - methods: [ - ControllerMethodEntry( - description: 'Zooms by factor', - methodEnum: PlatformInAppWebViewControllerMethod.zoomBy, - parameters: {'zoomFactor': 1.5, 'animated': true}, - requiredParameters: ['zoomFactor'], - execute: (controller, params) async { - final zoomFactor = - (params['zoomFactor'] as num?)?.toDouble() ?? 1.0; - final animated = params['animated'] as bool? ?? true; - await controller.zoomBy(zoomFactor: zoomFactor, animated: animated); - return 'Zoomed to ${zoomFactor}x'; - }, - ), - ControllerMethodEntry( - description: 'Zooms in', - methodEnum: PlatformInAppWebViewControllerMethod.zoomIn, - execute: (controller, params) async { - return await controller.zoomIn(); - }, - ), - ControllerMethodEntry( - description: 'Zooms out', - methodEnum: PlatformInAppWebViewControllerMethod.zoomOut, - execute: (controller, params) async { - return await controller.zoomOut(); - }, - ), - ControllerMethodEntry( - description: 'Gets current zoom scale', - methodEnum: PlatformInAppWebViewControllerMethod.getZoomScale, - execute: (controller, params) async { - return await controller.getZoomScale(); - }, - ), - ], - ); - } - - // ============================================================ - // SETTINGS CATEGORY - // ============================================================ - ControllerMethodCategory _buildSettingsCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.settings, - methods: [ - ControllerMethodEntry( - description: 'Gets WebView settings', - methodEnum: PlatformInAppWebViewControllerMethod.getSettings, - execute: (controller, params) async { - final settings = await controller.getSettings(); - return 'JS enabled: ${settings?.javaScriptEnabled}'; - }, - ), - ControllerMethodEntry( - description: 'Requests focus for WebView', - methodEnum: PlatformInAppWebViewControllerMethod.requestFocus, - execute: (controller, params) async { - return await controller.requestFocus(); - }, - ), - ControllerMethodEntry( - description: 'Clears focus from WebView', - methodEnum: PlatformInAppWebViewControllerMethod.clearFocus, - execute: (controller, params) async { - await controller.clearFocus(); - return 'Focus cleared'; - }, - ), - ], - ); - } - - // ============================================================ - // SCREENSHOT & PRINT CATEGORY - // ============================================================ - ControllerMethodCategory _buildScreenshotPrintCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.screenshotPrint, - methods: [ - ControllerMethodEntry( - description: 'Takes a screenshot', - methodEnum: PlatformInAppWebViewControllerMethod.takeScreenshot, - parameters: { - 'compressFormat': - EnumParameterValueHint.fromIterable( - CompressFormat.PNG, - _safeEnumValues(() => CompressFormat.values), - ), - 'quality': 100, - 'snapshotWidth': const ParameterValueHint( - null, - ParameterValueType.number, - ), - }, - execute: (controller, params) async { - final compressFormatParam = params['compressFormat']; - final compressFormat = compressFormatParam is CompressFormat - ? compressFormatParam - : CompressFormat.PNG; - final quality = (params['quality'] as num?)?.toInt() ?? 100; - final snapshotWidth = extractParam( - params['snapshotWidth'], - )?.toDouble(); - - final screenshot = await controller.takeScreenshot( - screenshotConfiguration: ScreenshotConfiguration( - compressFormat: compressFormat, - quality: quality, - snapshotWidth: snapshotWidth, - ), - ); - if (screenshot != null) { - return 'Screenshot taken: ${screenshot.length} bytes'; - } - return 'Screenshot failed'; - }, - ), - ControllerMethodEntry( - description: 'Prints current page', - methodEnum: PlatformInAppWebViewControllerMethod.printCurrentPage, - execute: (controller, params) async { - final printJob = await controller.printCurrentPage(); - return printJob != null - ? 'Print dialog opened' - : 'Print not available'; - }, - ), - ControllerMethodEntry( - description: 'Creates PDF from page', - methodEnum: PlatformInAppWebViewControllerMethod.createPdf, - execute: (controller, params) async { - final pdf = await controller.createPdf(); - if (pdf != null) { - return 'PDF created: ${pdf.length} bytes'; - } - return 'PDF creation failed'; - }, - ), - ], - ); - } - - // ============================================================ - // CACHE & HISTORY CATEGORY - // ============================================================ - ControllerMethodCategory _buildCacheHistoryCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.cacheHistory, - methods: [ - ControllerMethodEntry( - description: 'Clears navigation history', - methodEnum: PlatformInAppWebViewControllerMethod.clearHistory, - execute: (controller, params) async { - await controller.clearHistory(); - return 'History cleared'; - }, - ), - ControllerMethodEntry( - description: 'Clears form data', - methodEnum: PlatformInAppWebViewControllerMethod.clearFormData, - execute: (controller, params) async { - await controller.clearFormData(); - return 'Form data cleared'; - }, - ), - ControllerMethodEntry( - description: 'Clears SSL preferences', - methodEnum: PlatformInAppWebViewControllerMethod.clearSslPreferences, - execute: (controller, params) async { - await controller.clearSslPreferences(); - return 'SSL preferences cleared'; - }, - ), - ], - ); - } - - // ============================================================ - // PAUSE & RESUME CATEGORY - // ============================================================ - ControllerMethodCategory _buildPauseResumeCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.pauseResume, - methods: [ - ControllerMethodEntry( - description: 'Pauses WebView', - methodEnum: PlatformInAppWebViewControllerMethod.pause, - execute: (controller, params) async { - await controller.pause(); - return 'WebView paused'; - }, - ), - ControllerMethodEntry( - description: 'Resumes WebView', - methodEnum: PlatformInAppWebViewControllerMethod.resume, - execute: (controller, params) async { - await controller.resume(); - return 'WebView resumed'; - }, - ), - ControllerMethodEntry( - description: 'Pauses JavaScript timers', - methodEnum: PlatformInAppWebViewControllerMethod.pauseTimers, - execute: (controller, params) async { - await controller.pauseTimers(); - return 'Timers paused'; - }, - ), - ControllerMethodEntry( - description: 'Resumes JavaScript timers', - methodEnum: PlatformInAppWebViewControllerMethod.resumeTimers, - execute: (controller, params) async { - await controller.resumeTimers(); - return 'Timers resumed'; - }, - ), - ], - ); - } - - // ============================================================ - // WEB MESSAGING CATEGORY - // ============================================================ - ControllerMethodCategory _buildWebMessagingCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.webMessaging, - methods: [ - ControllerMethodEntry( - description: 'Creates a web message channel', - methodEnum: - PlatformInAppWebViewControllerMethod.createWebMessageChannel, - execute: (controller, params) async { - final channel = await controller.createWebMessageChannel(); - return channel != null - ? 'Channel created' - : 'Channel creation failed'; - }, - ), - ControllerMethodEntry( - description: 'Posts a web message', - methodEnum: PlatformInAppWebViewControllerMethod.postWebMessage, - parameters: {'message': 'Hello from Flutter', 'targetOrigin': '*'}, - requiredParameters: ['message'], - execute: (controller, params) async { - final targetOrigin = params['targetOrigin']?.toString(); - await controller.postWebMessage( - message: WebMessage(data: params['message']?.toString()), - targetOrigin: WebUri( - targetOrigin?.isNotEmpty == true ? targetOrigin! : '*', - ), - ); - return 'Message posted'; - }, - ), - ], - ); - } - - // ============================================================ - // MEDIA CATEGORY - // ============================================================ - ControllerMethodCategory _buildMediaCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.media, - methods: [ - ControllerMethodEntry( - description: 'Checks if in fullscreen', - methodEnum: PlatformInAppWebViewControllerMethod.isInFullscreen, - execute: (controller, params) async { - return await controller.isInFullscreen(); - }, - ), - ControllerMethodEntry( - description: 'Pauses all media', - methodEnum: - PlatformInAppWebViewControllerMethod.pauseAllMediaPlayback, - execute: (controller, params) async { - await controller.pauseAllMediaPlayback(); - return 'Media paused'; - }, - ), - ControllerMethodEntry( - description: 'Checks if playing audio', - methodEnum: PlatformInAppWebViewControllerMethod.isPlayingAudio, - execute: (controller, params) async { - return await controller.isPlayingAudio(); - }, - ), - ControllerMethodEntry( - description: 'Checks if muted', - methodEnum: PlatformInAppWebViewControllerMethod.isMuted, - execute: (controller, params) async { - return await controller.isMuted(); - }, - ), - ControllerMethodEntry( - description: 'Sets mute state', - methodEnum: PlatformInAppWebViewControllerMethod.setMuted, - parameters: {'muted': true}, - execute: (controller, params) async { - await controller.setMuted(muted: params['muted'] as bool? ?? true); - return 'Muted'; - }, - ), - ], - ); - } - - // ============================================================ - // CAMERA & MICROPHONE CATEGORY - // ============================================================ - ControllerMethodCategory _buildCameraMicCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.cameraMic, - methods: [ - ControllerMethodEntry( - description: 'Gets camera capture state', - methodEnum: - PlatformInAppWebViewControllerMethod.getCameraCaptureState, - execute: (controller, params) async { - final state = await controller.getCameraCaptureState(); - return state?.toString() ?? 'Unknown state'; - }, - ), - ControllerMethodEntry( - description: 'Gets microphone capture state', - methodEnum: - PlatformInAppWebViewControllerMethod.getMicrophoneCaptureState, - execute: (controller, params) async { - final state = await controller.getMicrophoneCaptureState(); - return state?.toString() ?? 'Unknown state'; - }, - ), - ], - ); - } - - // ============================================================ - // SECURITY CATEGORY - // ============================================================ - ControllerMethodCategory _buildSecurityCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.security, - methods: [ - ControllerMethodEntry( - description: 'Checks if secure context', - methodEnum: PlatformInAppWebViewControllerMethod.isSecureContext, - execute: (controller, params) async { - return await controller.isSecureContext(); - }, - ), - ControllerMethodEntry( - description: 'Checks if only secure content', - methodEnum: PlatformInAppWebViewControllerMethod.hasOnlySecureContent, - execute: (controller, params) async { - return await controller.hasOnlySecureContent(); - }, - ), - ], - ); - } - - // ============================================================ - // SAVE & RESTORE CATEGORY - // ============================================================ - ControllerMethodCategory _buildSaveRestoreCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.saveRestore, - methods: [ - ControllerMethodEntry( - description: 'Saves WebView state', - methodEnum: PlatformInAppWebViewControllerMethod.saveState, - execute: (controller, params) async { - final state = await controller.saveState(); - return state != null - ? 'State saved: ${state.length} bytes' - : 'Save failed'; - }, - ), - ControllerMethodEntry( - description: 'Creates web archive data', - methodEnum: PlatformInAppWebViewControllerMethod.createWebArchiveData, - execute: (controller, params) async { - final data = await controller.createWebArchiveData(); - return data != null ? 'Archive: ${data.length} bytes' : 'Failed'; - }, - ), - ], - ); - } - - // ============================================================ - // MISC CATEGORY - // ============================================================ - ControllerMethodCategory _buildMiscCategory() { - return ControllerMethodCategory( - categoryType: ControllerMethodCategoryType.misc, - methods: [ - ControllerMethodEntry( - description: 'Gets the WebView ID', - methodEnum: PlatformInAppWebViewControllerMethod.getViewId, - execute: (controller, params) async { - return controller.getViewId(); - }, - ), - ControllerMethodEntry( - description: 'Starts Safe Browsing', - methodEnum: PlatformInAppWebViewControllerMethod.startSafeBrowsing, - execute: (controller, params) async { - return await controller.startSafeBrowsing(); - }, - ), - ControllerMethodEntry( - description: 'Opens DevTools', - methodEnum: PlatformInAppWebViewControllerMethod.openDevTools, - execute: (controller, params) async { - await controller.openDevTools(); - return 'DevTools opened'; - }, - ), - ], - ); - } - - static UserScriptInjectionTime _parseUserScriptInjectionTime(String? value) { - if (value == null || value.isEmpty) { - return UserScriptInjectionTime.AT_DOCUMENT_END; - } - return UserScriptInjectionTime.values.firstWhere( - (entry) => entry.name().toLowerCase() == value.toLowerCase(), - orElse: () => UserScriptInjectionTime.AT_DOCUMENT_END, - ); - } -} diff --git a/flutter_inappwebview/example/lib/utils/environment_settings_definitions.dart b/flutter_inappwebview/example/lib/utils/environment_settings_definitions.dart deleted file mode 100644 index 1c592290b1..0000000000 --- a/flutter_inappwebview/example/lib/utils/environment_settings_definitions.dart +++ /dev/null @@ -1,197 +0,0 @@ -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/models/environment_setting_definition.dart'; - -List _safeEnumValues(Iterable Function() getter) { - try { - return getter().toList(); - } catch (_) { - return []; - } -} - -/// Get all environment setting definitions organized by category. -Map> -getEnvironmentSettingDefinitions() { - return { - 'General': [ - EnvironmentSettingDefinition( - name: 'Browser Executable Folder', - description: - 'Path to the folder containing the WebView2 browser executable', - type: EnvironmentSettingType.string, - hint: 'C:\\Program Files (x86)\\Microsoft\\Edge WebView2\\...', - property: WebViewEnvironmentSettingsProperty.browserExecutableFolder, - ), - EnvironmentSettingDefinition( - name: 'User Data Folder', - description: 'Path to the user data folder for WebView2 profile', - type: EnvironmentSettingType.string, - hint: 'C:\\Users\\...\\AppData\\Local\\...', - property: WebViewEnvironmentSettingsProperty.userDataFolder, - ), - EnvironmentSettingDefinition( - name: 'Additional Browser Arguments', - description: 'Additional command line arguments for the browser', - type: EnvironmentSettingType.string, - hint: '--disable-gpu --enable-logging', - property: WebViewEnvironmentSettingsProperty.additionalBrowserArguments, - ), - EnvironmentSettingDefinition( - name: 'Target Compatible Browser Version', - description: 'Minimum WebView2 version required', - type: EnvironmentSettingType.string, - hint: '100.0.0.0', - property: - WebViewEnvironmentSettingsProperty.targetCompatibleBrowserVersion, - ), - ], - 'Release Channel': [ - EnvironmentSettingDefinition( - name: 'Channel Search Kind', - description: 'How to search for WebView2 runtime', - type: EnvironmentSettingType.enumeration, - enumValues: _safeEnumValues(() => EnvironmentChannelSearchKind.values), - property: WebViewEnvironmentSettingsProperty.channelSearchKind, - ), - EnvironmentSettingDefinition( - name: 'Release Channels', - description: 'Which release channels to consider', - type: EnvironmentSettingType.enumeration, - enumValues: _safeEnumValues(() => EnvironmentReleaseChannels.values), - property: WebViewEnvironmentSettingsProperty.releaseChannels, - ), - ], - 'Localization': [ - EnvironmentSettingDefinition( - name: 'Language', - description: 'Default language for the WebView', - type: EnvironmentSettingType.string, - hint: 'en-US', - property: WebViewEnvironmentSettingsProperty.language, - ), - EnvironmentSettingDefinition( - name: 'Preferred Languages', - description: 'List of preferred languages', - type: EnvironmentSettingType.stringList, - hint: 'en-US, fr-FR, de-DE', - property: WebViewEnvironmentSettingsProperty.preferredLanguages, - ), - EnvironmentSettingDefinition( - name: 'Time Zone Override', - description: 'Override the default time zone', - type: EnvironmentSettingType.string, - hint: 'America/New_York', - property: WebViewEnvironmentSettingsProperty.timeZoneOverride, - ), - ], - 'Spellcheck': [ - EnvironmentSettingDefinition( - name: 'Spell Checking Enabled', - description: 'Enable spell checking', - type: EnvironmentSettingType.boolean, - defaultValue: false, - property: WebViewEnvironmentSettingsProperty.spellCheckingEnabled, - ), - EnvironmentSettingDefinition( - name: 'Spell Checking Languages', - description: 'Languages for spell checking', - type: EnvironmentSettingType.stringList, - hint: 'en_US, fr_FR', - property: WebViewEnvironmentSettingsProperty.spellCheckingLanguages, - ), - ], - 'Extensions': [ - EnvironmentSettingDefinition( - name: 'Browser Extensions Enabled', - description: 'Enable browser extensions support', - type: EnvironmentSettingType.boolean, - defaultValue: false, - property: - WebViewEnvironmentSettingsProperty.areBrowserExtensionsEnabled, - ), - EnvironmentSettingDefinition( - name: 'Web Process Extensions Directory', - description: 'Path to web process extensions', - type: EnvironmentSettingType.string, - hint: '/path/to/extensions', - property: - WebViewEnvironmentSettingsProperty.webProcessExtensionsDirectory, - ), - ], - 'Security & Privacy': [ - EnvironmentSettingDefinition( - name: 'Allow SSO with OS Account', - description: 'Allow single sign-on using the OS primary account (AAD)', - type: EnvironmentSettingType.boolean, - defaultValue: false, - property: WebViewEnvironmentSettingsProperty - .allowSingleSignOnUsingOSPrimaryAccount, - ), - EnvironmentSettingDefinition( - name: 'Enable Tracking Prevention', - description: 'Enable tracking prevention features', - type: EnvironmentSettingType.boolean, - defaultValue: true, - property: WebViewEnvironmentSettingsProperty.enableTrackingPrevention, - ), - EnvironmentSettingDefinition( - name: 'Exclusive User Data Folder Access', - description: 'Ensure exclusive access to the user data folder', - type: EnvironmentSettingType.boolean, - defaultValue: false, - property: - WebViewEnvironmentSettingsProperty.exclusiveUserDataFolderAccess, - ), - EnvironmentSettingDefinition( - name: 'Sandbox Paths', - description: 'Paths for sandbox isolation', - type: EnvironmentSettingType.stringList, - hint: '/path/to/sandbox', - property: WebViewEnvironmentSettingsProperty.sandboxPaths, - ), - ], - 'Automation & Debugging': [ - EnvironmentSettingDefinition( - name: 'Automation Allowed', - description: 'Allow WebDriver automation', - type: EnvironmentSettingType.boolean, - defaultValue: false, - property: WebViewEnvironmentSettingsProperty.automationAllowed, - ), - EnvironmentSettingDefinition( - name: 'Custom Crash Reporting', - description: 'Enable custom crash reporting', - type: EnvironmentSettingType.boolean, - defaultValue: false, - property: - WebViewEnvironmentSettingsProperty.isCustomCrashReportingEnabled, - ), - ], - 'Appearance': [ - EnvironmentSettingDefinition( - name: 'Scrollbar Style', - description: 'Style of scrollbars in the WebView', - type: EnvironmentSettingType.enumeration, - enumValues: _safeEnumValues(() => EnvironmentScrollbarStyle.values), - property: WebViewEnvironmentSettingsProperty.scrollbarStyle, - ), - ], - 'Cache': [ - EnvironmentSettingDefinition( - name: 'Cache Model', - description: 'Caching strategy for the WebView', - type: EnvironmentSettingType.enumeration, - enumValues: _safeEnumValues(() => CacheModel.values), - property: WebViewEnvironmentSettingsProperty.cacheModel, - ), - ], - 'Custom Schemes': [ - EnvironmentSettingDefinition( - name: 'Custom Scheme Registrations', - description: 'Register custom URL schemes', - type: EnvironmentSettingType.customSchemeRegistrations, - property: WebViewEnvironmentSettingsProperty.customSchemeRegistrations, - ), - ], - }; -} diff --git a/flutter_inappwebview/example/lib/utils/parameter_dialog_utils.dart b/flutter_inappwebview/example/lib/utils/parameter_dialog_utils.dart deleted file mode 100644 index 8472bbcf61..0000000000 --- a/flutter_inappwebview/example/lib/utils/parameter_dialog_utils.dart +++ /dev/null @@ -1,116 +0,0 @@ -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:flutter/material.dart'; - -class ParameterDialogUtils { - static Map deepCloneMap(Map input) { - return input.map((key, value) => MapEntry(key, deepCloneValue(value))); - } - - static dynamic deepCloneValue(dynamic value) { - if (value is Map) { - return value.map((key, nested) => MapEntry(key, deepCloneValue(nested))); - } - if (value is List) { - return value.map(deepCloneValue).toList(); - } - if (value is Uint8List) { - return Uint8List.fromList(value); - } - if (value is DateTime) { - return DateTime.fromMillisecondsSinceEpoch(value.millisecondsSinceEpoch); - } - if (value is Color) { - return Color(value.value); - } - return value; - } - - static Uint8List? parseBytes(String input) { - final normalized = input.trim(); - if (normalized.isEmpty) return null; - - String? base64Payload; - if (normalized.startsWith('base64:')) { - base64Payload = normalized.substring('base64:'.length).trim(); - } else if (normalized.startsWith('data:')) { - final base64Marker = ';base64,'; - final markerIndex = normalized.indexOf(base64Marker); - if (markerIndex != -1) { - base64Payload = normalized.substring(markerIndex + base64Marker.length); - } - } - - if (base64Payload != null) { - try { - return Uint8List.fromList(base64.decode(base64Payload)); - } catch (_) { - return null; - } - } - - return Uint8List.fromList(utf8.encode(normalized)); - } - - static num? parseNumber(String input) { - final normalized = input.trim(); - if (normalized.isEmpty) return null; - return num.tryParse(normalized); - } - - static dynamic getValueAtPath(dynamic root, List path) { - dynamic current = root; - for (final segment in path) { - if (segment is int) { - if (current is List && segment < current.length) { - current = current[segment]; - } else { - return null; - } - } else { - if (current is Map && current.containsKey(segment)) { - current = current[segment]; - } else { - return null; - } - } - } - return current; - } - - static void setValueAtPath(dynamic root, List path, dynamic value) { - if (path.isEmpty) return; - - dynamic current = root; - for (var i = 0; i < path.length - 1; i++) { - final segment = path[i]; - if (segment is int) { - if (current is List) { - if (segment >= current.length) { - current.length = segment + 1; - } - current = current[segment]; - } else { - return; - } - } else { - if (current is Map) { - current = current[segment]; - } else { - return; - } - } - } - - final last = path.last; - if (last is int && current is List) { - if (last >= current.length) { - current.length = last + 1; - } - current[last] = value; - } else if (last is String && current is Map) { - current[last] = value; - } - } -} diff --git a/flutter_inappwebview/example/lib/utils/platform_utils.dart b/flutter_inappwebview/example/lib/utils/platform_utils.dart deleted file mode 100644 index 711b8cf451..0000000000 --- a/flutter_inappwebview/example/lib/utils/platform_utils.dart +++ /dev/null @@ -1,118 +0,0 @@ -import 'dart:io' show Platform; - -import 'package:flutter/foundation.dart' show kIsWeb; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; - -/// Utility class for platform detection and information. -class PlatformUtils { - /// Gets the name of the current platform. - static String getPlatformName() { - if (kIsWeb) { - return 'Web'; - } - if (Platform.isAndroid) { - return 'Android'; - } - if (Platform.isIOS) { - return 'iOS'; - } - if (Platform.isMacOS) { - return 'macOS'; - } - if (Platform.isWindows) { - return 'Windows'; - } - if (Platform.isLinux) { - return 'Linux'; - } - return 'Unknown'; - } - - /// Gets the current platform as a [SupportedPlatform] enum value. - /// Returns null if the current platform is not recognized. - static SupportedPlatform? getCurrentPlatform() { - if (kIsWeb) { - return SupportedPlatform.web; - } - if (Platform.isAndroid) { - return SupportedPlatform.android; - } - if (Platform.isIOS) { - return SupportedPlatform.ios; - } - if (Platform.isMacOS) { - return SupportedPlatform.macos; - } - if (Platform.isWindows) { - return SupportedPlatform.windows; - } - if (Platform.isLinux) { - return SupportedPlatform.linux; - } - return null; - } - - /// Gets the Flutter SDK version. - /// Note: This is a placeholder. In production, you might use - /// package_info_plus or similar to get actual version info. - static String getFlutterVersion() { - return FlutterVersion.version != null - ? FlutterVersion.version! + ' (' + (FlutterVersion.channel ?? '') + ')' - : 'Flutter SDK'; - } - - /// Gets the Dart SDK version. - static String getDartVersion() { - return FlutterVersion.dartVersion ?? - (!kIsWeb ? Platform.version : 'Dart SDK'); - } - - /// Returns true if running on web platform. - static bool isWebPlatform() { - return kIsWeb; - } - - /// Returns true if running on mobile platform (Android or iOS). - static bool isMobilePlatform() { - if (kIsWeb) return false; - return Platform.isAndroid || Platform.isIOS; - } - - /// Returns true if running on desktop platform (Windows, macOS, or Linux). - static bool isDesktopPlatform() { - if (kIsWeb) return false; - return Platform.isWindows || Platform.isMacOS || Platform.isLinux; - } - - /// Gets an appropriate icon for the current platform. - static IconData getPlatformIcon() { - if (kIsWeb) { - return Icons.language; - } - if (!kIsWeb) { - if (Platform.isAndroid) { - return Icons.android; - } - if (Platform.isIOS) { - return Icons.phone_iphone; - } - if (Platform.isMacOS) { - return Icons.laptop_mac; - } - if (Platform.isWindows) { - return Icons.desktop_windows; - } - if (Platform.isLinux) { - return Icons.computer; - } - } - return Icons.devices; - } - - /// Gets a short platform identifier (lowercase). - static String getPlatformIdentifier() { - return getPlatformName().toLowerCase(); - } -} diff --git a/flutter_inappwebview/example/lib/utils/responsive_utils.dart b/flutter_inappwebview/example/lib/utils/responsive_utils.dart deleted file mode 100644 index 8fcf5d51ce..0000000000 --- a/flutter_inappwebview/example/lib/utils/responsive_utils.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:flutter/widgets.dart'; - -/// Breakpoints used for responsive layouts in the example app. -enum ResponsiveBreakpoint { mobile, tablet, desktop } - -/// Shared breakpoint helpers for responsive layouts. -class ResponsiveBreakpoints { - static const double tabletMinWidth = 600; - static const double tabletMaxWidth = 900; - - static ResponsiveBreakpoint fromWidth(double width) { - if (width < tabletMinWidth) { - return ResponsiveBreakpoint.mobile; - } - if (width <= tabletMaxWidth) { - return ResponsiveBreakpoint.tablet; - } - return ResponsiveBreakpoint.desktop; - } - - static bool isMobileWidth(double width) => - fromWidth(width) == ResponsiveBreakpoint.mobile; - - static bool isTabletWidth(double width) => - fromWidth(width) == ResponsiveBreakpoint.tablet; - - static bool isDesktopWidth(double width) => - fromWidth(width) == ResponsiveBreakpoint.desktop; -} - -/// Convenience getters for responsive checks from a [BuildContext]. -extension ResponsiveBuildContext on BuildContext { - double get screenWidth => MediaQuery.sizeOf(this).width; - - ResponsiveBreakpoint get breakpoint => - ResponsiveBreakpoints.fromWidth(screenWidth); - - bool get isMobile => breakpoint == ResponsiveBreakpoint.mobile; - - bool get isTablet => breakpoint == ResponsiveBreakpoint.tablet; - - bool get isDesktop => breakpoint == ResponsiveBreakpoint.desktop; -} diff --git a/flutter_inappwebview/example/lib/utils/settings_defaults.dart b/flutter_inappwebview/example/lib/utils/settings_defaults.dart deleted file mode 100644 index 3cc5c0d12f..0000000000 --- a/flutter_inappwebview/example/lib/utils/settings_defaults.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; - -InAppWebViewSettings defaultInAppWebViewSettings() { - return InAppWebViewSettings(); -} - -WebViewEnvironmentSettings defaultWebViewEnvironmentSettings() { - return WebViewEnvironmentSettings(); -} - -Map defaultInAppWebViewSettingsMap() { - return defaultInAppWebViewSettings().toMap( - enumMethod: EnumMethod.nativeValue, - ); -} - -Map defaultWebViewEnvironmentSettingsMap() { - return defaultWebViewEnvironmentSettings().toMap( - enumMethod: EnumMethod.nativeValue, - ); -} diff --git a/flutter_inappwebview/example/lib/utils/settings_definitions.dart b/flutter_inappwebview/example/lib/utils/settings_definitions.dart deleted file mode 100644 index a226701b18..0000000000 --- a/flutter_inappwebview/example/lib/utils/settings_definitions.dart +++ /dev/null @@ -1,456 +0,0 @@ -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/models/setting_definition.dart'; - -List _safeEnumValues(Iterable Function() getter) { - try { - return getter().toList(); - } catch (_) { - return []; - } -} - -/// Get all setting definitions organized by category. -Map> getSettingDefinitions() { - return { - 'General': [ - SettingDefinition( - name: 'JavaScript Enabled', - description: 'Enable JavaScript execution in the WebView', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.javaScriptEnabled, - ), - SettingDefinition( - name: 'User Agent', - description: 'Custom user-agent string for the WebView', - type: SettingType.string, - defaultValue: '', - property: InAppWebViewSettingsProperty.userAgent, - ), - SettingDefinition( - name: 'Application Name for User Agent', - description: 'Append to the existing user-agent', - type: SettingType.string, - defaultValue: '', - property: InAppWebViewSettingsProperty.applicationNameForUserAgent, - ), - SettingDefinition( - name: 'Cache Enabled', - description: 'Enable browser caching', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.cacheEnabled, - ), - SettingDefinition( - name: 'Incognito Mode', - description: 'Open browser in incognito/private mode', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.incognito, - ), - SettingDefinition( - name: 'Support Zoom', - description: 'Enable zoom gestures and controls', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.supportZoom, - ), - ], - 'Layout': [ - SettingDefinition( - name: 'Use Wide ViewPort', - description: 'Enable support for HTML viewport meta tag', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.useWideViewPort, - ), - SettingDefinition( - name: 'Load With Overview Mode', - description: 'Zoom out content to fit on screen', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.loadWithOverviewMode, - ), - SettingDefinition( - name: 'Minimum Font Size', - description: 'Minimum font size in pixels', - type: SettingType.integer, - defaultValue: 8, - property: InAppWebViewSettingsProperty.minimumFontSize, - ), - SettingDefinition( - name: 'Default Font Size', - description: 'Default font size in pixels', - type: SettingType.integer, - defaultValue: 16, - property: InAppWebViewSettingsProperty.defaultFontSize, - ), - SettingDefinition( - name: 'Default Text Encoding', - description: 'Default text encoding for HTML pages', - type: SettingType.string, - defaultValue: 'UTF-8', - property: InAppWebViewSettingsProperty.defaultTextEncodingName, - ), - ], - 'Content': [ - SettingDefinition( - name: 'Allow Content Access', - description: 'Enable content URL access', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.allowContentAccess, - ), - SettingDefinition( - name: 'Allow File Access', - description: 'Enable file system access', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.allowFileAccess, - ), - SettingDefinition( - name: 'Allow File Access From File URLs', - description: 'Allow file:// URLs to access other file:// URLs', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.allowFileAccessFromFileURLs, - ), - SettingDefinition( - name: 'Allow Universal Access From File URLs', - description: 'Allow file:// URLs to access any origin', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.allowUniversalAccessFromFileURLs, - ), - SettingDefinition( - name: 'Block Network Images', - description: 'Block loading images from the network', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.blockNetworkImage, - ), - SettingDefinition( - name: 'Block Network Loads', - description: 'Block all network resource loading', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.blockNetworkLoads, - ), - ], - 'Media': [ - SettingDefinition( - name: 'Media Requires User Gesture', - description: 'Require user interaction to play media', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.mediaPlaybackRequiresUserGesture, - ), - SettingDefinition( - name: 'Allows Inline Media Playback', - description: 'Allow HTML5 media to play inline', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.allowsInlineMediaPlayback, - ), - SettingDefinition( - name: 'Allows AirPlay', - description: 'Allow AirPlay for media playback', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.allowsAirPlayForMediaPlayback, - ), - SettingDefinition( - name: 'Allows Picture-in-Picture', - description: 'Allow videos to play in picture-in-picture', - type: SettingType.boolean, - defaultValue: true, - property: - InAppWebViewSettingsProperty.allowsPictureInPictureMediaPlayback, - ), - SettingDefinition( - name: 'Auto Adjust Scroll Indicator Insets', - description: 'Automatically adjust scroll indicator insets', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty - .automaticallyAdjustsScrollIndicatorInsets, - ), - ], - 'JavaScript': [ - SettingDefinition( - name: 'JS Can Open Windows', - description: 'Allow JavaScript to open windows automatically', - type: SettingType.boolean, - defaultValue: false, - property: - InAppWebViewSettingsProperty.javaScriptCanOpenWindowsAutomatically, - ), - SettingDefinition( - name: 'JavaScript Bridge Enabled', - description: 'Enable the JavaScript bridge', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.javaScriptBridgeEnabled, - ), - SettingDefinition( - name: 'JS Bridge Main Frame Only', - description: 'Restrict JavaScript bridge to main frame', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.javaScriptBridgeForMainFrameOnly, - ), - ], - 'Security': [ - SettingDefinition( - name: 'Mixed Content Mode', - description: 'How to handle mixed HTTP/HTTPS content', - type: SettingType.enumeration, - defaultValue: null, - enumValues: _safeEnumValues(() => MixedContentMode.values), - property: InAppWebViewSettingsProperty.mixedContentMode, - ), - SettingDefinition( - name: 'Use Should Intercept Request', - description: 'Enable request interception events', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.useShouldInterceptRequest, - ), - SettingDefinition( - name: 'Use Should Override URL Loading', - description: 'Enable URL loading override events', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.useShouldOverrideUrlLoading, - ), - SettingDefinition( - name: 'Use On Load Resource', - description: 'Enable resource loading events', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.useOnLoadResource, - ), - SettingDefinition( - name: 'Fraudulent Website Warning', - description: 'Show warnings for suspected phishing/malware', - type: SettingType.boolean, - defaultValue: true, - property: - InAppWebViewSettingsProperty.isFraudulentWebsiteWarningEnabled, - ), - SettingDefinition( - name: 'Safe Browsing', - description: 'Enable Google Safe Browsing', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.safeBrowsingEnabled, - ), - ], - 'Cache': [ - SettingDefinition( - name: 'Cache Mode', - description: 'Override the way the cache is used', - type: SettingType.enumeration, - defaultValue: CacheMode.LOAD_DEFAULT.toNativeValue(), - enumValues: _safeEnumValues(() => CacheMode.values), - property: InAppWebViewSettingsProperty.cacheMode, - ), - ], - 'Appearance': [ - SettingDefinition( - name: 'Transparent Background', - description: 'Make the WebView background transparent', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.transparentBackground, - ), - SettingDefinition( - name: 'Vertical Scroll Bar', - description: 'Show vertical scroll bar', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.verticalScrollBarEnabled, - ), - SettingDefinition( - name: 'Horizontal Scroll Bar', - description: 'Show horizontal scroll bar', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.horizontalScrollBarEnabled, - ), - SettingDefinition( - name: 'Scrollbar Fading', - description: 'Fade scrollbars when not scrolling', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.scrollbarFadingEnabled, - ), - SettingDefinition( - name: 'Disable Vertical Scroll', - description: 'Disable vertical scrolling', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.disableVerticalScroll, - ), - SettingDefinition( - name: 'Disable Horizontal Scroll', - description: 'Disable horizontal scrolling', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.disableHorizontalScroll, - ), - SettingDefinition( - name: 'Disable Context Menu', - description: 'Disable the long-press context menu', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.disableContextMenu, - ), - ], - 'Navigation': [ - SettingDefinition( - name: 'Back/Forward Gestures', - description: 'Enable swipe gestures for navigation', - type: SettingType.boolean, - defaultValue: true, - property: - InAppWebViewSettingsProperty.allowsBackForwardNavigationGestures, - ), - ], - 'Rendering': [ - SettingDefinition( - name: 'Suppress Incremental Rendering', - description: 'Wait until content is fully loaded before rendering', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.suppressesIncrementalRendering, - ), - SettingDefinition( - name: 'Hardware Acceleration', - description: 'Enable hardware acceleration', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.hardwareAcceleration, - ), - SettingDefinition( - name: 'Hybrid Composition', - description: 'Use Flutter Hybrid Composition', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.useHybridComposition, - ), - ], - 'Zoom': [ - SettingDefinition( - name: 'Ignore Viewport Scale Limits', - description: 'Override user-scalable viewport setting', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.ignoresViewportScaleLimits, - ), - SettingDefinition( - name: 'Built-In Zoom Controls', - description: 'Use built-in zoom controls', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.builtInZoomControls, - ), - SettingDefinition( - name: 'Display Zoom Controls', - description: 'Show on-screen zoom controls', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.displayZoomControls, - ), - SettingDefinition( - name: 'Pinch Zoom', - description: 'Enable pinch-to-zoom gesture', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.pinchZoomEnabled, - ), - ], - 'Interaction': [ - SettingDefinition( - name: 'Link Preview', - description: 'Show link previews on long press', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.allowsLinkPreview, - ), - ], - 'Storage': [ - SettingDefinition( - name: 'Third-Party Cookies', - description: 'Allow third-party cookies', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.thirdPartyCookiesEnabled, - ), - SettingDefinition( - name: 'DOM Storage', - description: 'Enable DOM local storage', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.domStorageEnabled, - ), - SettingDefinition( - name: 'Database', - description: 'Enable database storage API', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.databaseEnabled, - ), - ], - 'APIs': [ - SettingDefinition( - name: 'Geolocation', - description: 'Enable Geolocation API', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.geolocationEnabled, - ), - ], - 'Forms': [ - SettingDefinition( - name: 'General Autofill', - description: 'Enable autofill for forms', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.generalAutofillEnabled, - ), - SettingDefinition( - name: 'Password Autosave', - description: 'Enable password autosave', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.passwordAutosaveEnabled, - ), - ], - 'UI': [ - SettingDefinition( - name: 'Status Bar', - description: 'Show status bar', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.statusBarEnabled, - ), - SettingDefinition( - name: 'Browser Accelerator Keys', - description: 'Enable browser keyboard shortcuts', - type: SettingType.boolean, - defaultValue: true, - property: InAppWebViewSettingsProperty.browserAcceleratorKeysEnabled, - ), - ], - 'Developer': [ - SettingDefinition( - name: 'Inspectable', - description: 'Allow Web Inspector/DevTools', - type: SettingType.boolean, - defaultValue: false, - property: InAppWebViewSettingsProperty.isInspectable, - ), - ], - }; -} diff --git a/flutter_inappwebview/example/lib/utils/support_checker.dart b/flutter_inappwebview/example/lib/utils/support_checker.dart deleted file mode 100644 index 515bd35be0..0000000000 --- a/flutter_inappwebview/example/lib/utils/support_checker.dart +++ /dev/null @@ -1,3188 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; - -/// Represents a platform for API support checking. -enum SupportedPlatform { - android, - ios, - macos, - web, - windows, - linux; - - String get displayName { - switch (this) { - case SupportedPlatform.android: - return 'Android'; - case SupportedPlatform.ios: - return 'iOS'; - case SupportedPlatform.macos: - return 'macOS'; - case SupportedPlatform.web: - return 'Web'; - case SupportedPlatform.windows: - return 'Windows'; - case SupportedPlatform.linux: - return 'Linux'; - } - } - - IconData get icon { - switch (this) { - case SupportedPlatform.android: - return Icons.android; - case SupportedPlatform.ios: - return Icons.phone_iphone; - case SupportedPlatform.macos: - return Icons.laptop_mac; - case SupportedPlatform.web: - return Icons.language; - case SupportedPlatform.windows: - return Icons.desktop_windows; - case SupportedPlatform.linux: - return Icons.computer; - } - } - - Color get color { - switch (this) { - case SupportedPlatform.android: - return Colors.green.shade600; - case SupportedPlatform.ios: - return Colors.grey.shade700; - case SupportedPlatform.macos: - return Colors.blueGrey.shade600; - case SupportedPlatform.web: - return Colors.blue.shade600; - case SupportedPlatform.windows: - return Colors.lightBlue.shade600; - case SupportedPlatform.linux: - return Colors.orange.shade700; - } - } - - TargetPlatform? get targetPlatform { - switch (this) { - case SupportedPlatform.android: - return TargetPlatform.android; - case SupportedPlatform.ios: - return TargetPlatform.iOS; - case SupportedPlatform.macos: - return TargetPlatform.macOS; - case SupportedPlatform.windows: - return TargetPlatform.windows; - case SupportedPlatform.linux: - return TargetPlatform.linux; - case SupportedPlatform.web: - return null; // Web doesn't have a TargetPlatform - } - } -} - -/// Helper utilities for support checks across platforms. -class SupportCheckHelper { - /// Maps [SupportedPlatform] to a [TargetPlatform] when possible. - static TargetPlatform? targetPlatformFor(SupportedPlatform platform) { - return platform.targetPlatform; - } - - /// Checks class support for a specific [SupportedPlatform]. - static bool isClassSupportedForPlatform({ - required SupportedPlatform platform, - required bool Function({TargetPlatform? platform}) checker, - }) { - if (platform == SupportedPlatform.web) { - return checker(platform: null); - } - return checker(platform: targetPlatformFor(platform)); - } - - /// Checks method support for a specific [SupportedPlatform]. - static bool isMethodSupportedForPlatform({ - required SupportedPlatform platform, - required T method, - required bool Function(T method, {TargetPlatform? platform}) checker, - }) { - if (platform == SupportedPlatform.web) { - return checker(method, platform: null); - } - return checker(method, platform: targetPlatformFor(platform)); - } - - /// Checks property support for a specific [SupportedPlatform]. - static bool isPropertySupportedForPlatform({ - required SupportedPlatform platform, - required dynamic property, - required bool Function(dynamic property, {TargetPlatform? platform}) - checker, - }) { - if (platform == SupportedPlatform.web) { - return checker(property, platform: null); - } - return checker(property, platform: targetPlatformFor(platform)); - } - - /// Returns all supported platforms for a given class checker. - static Set supportedPlatformsForClass({ - required bool Function({TargetPlatform? platform}) checker, - }) { - return SupportedPlatform.values - .where( - (platform) => - isClassSupportedForPlatform(platform: platform, checker: checker), - ) - .toSet(); - } - - /// Returns all supported platforms for a given method checker. - static Set supportedPlatformsForMethod({ - required T method, - required bool Function(T method, {TargetPlatform? platform}) checker, - }) { - return SupportedPlatform.values - .where( - (platform) => isMethodSupportedForPlatform( - platform: platform, - method: method, - checker: checker, - ), - ) - .toSet(); - } - - /// Returns all supported platforms for a given property checker. - static Set supportedPlatformsForProperty({ - required dynamic property, - required bool Function(dynamic property, {TargetPlatform? platform}) - checker, - }) { - return SupportedPlatform.values - .where( - (platform) => isPropertySupportedForPlatform( - platform: platform, - property: property, - checker: checker, - ), - ) - .toSet(); - } -} - -/// Definition of an API method with platform support information. -class ApiMethodDefinition { - final String name; - final String signature; - final String description; - final String className; - final bool isStatic; - final bool isDeprecated; - final String? category; - - const ApiMethodDefinition({ - required this.name, - this.signature = '', - this.description = '', - required this.className, - this.isStatic = false, - this.isDeprecated = false, - this.category, - }); - - /// Returns the supported platforms for this method using runtime checks. - Set get supportedPlatforms => - SupportChecker.getSupportedPlatformsForMethod(className, name); - - bool isSupported(SupportedPlatform platform) => - supportedPlatforms.contains(platform); -} - -/// Definition of an API event with platform support information. -class ApiEventDefinition { - final String name; - final String signature; - final String description; - final String className; - final String? category; - - const ApiEventDefinition({ - required this.name, - this.signature = '', - this.description = '', - required this.className, - this.category, - }); - - /// Returns the supported platforms for this event using runtime checks. - Set get supportedPlatforms => - SupportChecker.getSupportedPlatformsForEvent(className, name); - - bool isSupported(SupportedPlatform platform) => - supportedPlatforms.contains(platform); -} - -/// Definition of an API class with its methods and events. -class ApiClassDefinition { - final String className; - final String description; - final List methods; - final List events; - final bool Function()? isClassSupported; - - const ApiClassDefinition({ - required this.className, - this.description = '', - this.methods = const [], - this.events = const [], - this.isClassSupported, - }); - - int get totalApis => methods.length + events.length; - - int methodCountForPlatform(SupportedPlatform platform) => - methods.where((m) => m.isSupported(platform)).length; - - int eventCountForPlatform(SupportedPlatform platform) => - events.where((e) => e.isSupported(platform)).length; -} - -/// Summary of API support statistics. -class SupportSummary { - final int totalMethods; - final int totalEvents; - final Map methodsPerPlatform; - final Map eventsPerPlatform; - - const SupportSummary({ - required this.totalMethods, - required this.totalEvents, - required this.methodsPerPlatform, - required this.eventsPerPlatform, - }); - - int get totalApis => totalMethods + totalEvents; - - int totalApisForPlatform(SupportedPlatform platform) => - (methodsPerPlatform[platform] ?? 0) + (eventsPerPlatform[platform] ?? 0); -} - -typedef _MethodSupportResolver = - bool Function(String methodName, SupportedPlatform platform); - -typedef _PropertySupportResolver = - bool Function(String propertyName, SupportedPlatform platform); - -/// Utility class that provides comprehensive API support information. -class SupportChecker { - // All supported platforms - static const allPlatforms = { - SupportedPlatform.android, - SupportedPlatform.ios, - SupportedPlatform.macos, - SupportedPlatform.web, - SupportedPlatform.windows, - SupportedPlatform.linux, - }; - - // Mobile platforms - static const mobilePlatforms = { - SupportedPlatform.android, - SupportedPlatform.ios, - }; - - // Native platforms (non-web) - static const nativePlatforms = { - SupportedPlatform.android, - SupportedPlatform.ios, - SupportedPlatform.macos, - SupportedPlatform.windows, - SupportedPlatform.linux, - }; - - // Desktop platforms - static const desktopPlatforms = { - SupportedPlatform.macos, - SupportedPlatform.windows, - SupportedPlatform.linux, - }; - - // Apple platforms - static const applePlatforms = { - SupportedPlatform.ios, - SupportedPlatform.macos, - }; - - static String _enumName(Object? value) { - if (value is Enum) return value.name; - return value.toString().split('.').last; - } - - static String classNameOf(Type type) => type.toString(); - - static String eventClassNameOf(Type type) => '${classNameOf(type)} Events'; - - static Set get registeredClassNames => { - ..._classSupportResolvers.keys, - ..._methodSupportResolvers.keys, - ..._eventSupportResolvers.keys, - }; - - static _MethodSupportResolver _buildMethodResolver({ - required List values, - required bool Function(T method, {TargetPlatform? platform}) checker, - }) { - final methodByName = {for (final value in values) _enumName(value): value}; - return (String methodName, SupportedPlatform platform) { - final resolved = methodByName[methodName]; - if (resolved == null) return false; - return SupportCheckHelper.isMethodSupportedForPlatform( - platform: platform, - method: resolved, - checker: checker, - ); - }; - } - - static _PropertySupportResolver _buildPropertyResolver({ - required List values, - required bool Function(dynamic property, {TargetPlatform? platform}) - checker, - Map nameOverrides = const {}, - }) { - final propertyByName = { - for (final value in values) _enumName(value): value, - }; - return (String propertyName, SupportedPlatform platform) { - final resolvedName = nameOverrides[propertyName] ?? propertyName; - final resolved = propertyByName[resolvedName]; - if (resolved == null) return false; - return SupportCheckHelper.isPropertySupportedForPlatform( - platform: platform, - property: resolved, - checker: checker, - ); - }; - } - - static final Map - _classSupportResolvers = { - classNameOf(InAppWebViewController): - InAppWebViewController.isClassSupported, - eventClassNameOf(InAppWebView): InAppWebView.isClassSupported, - classNameOf(HeadlessInAppWebView): HeadlessInAppWebView.isClassSupported, - classNameOf(InAppBrowser): InAppBrowser.isClassSupported, - classNameOf(ChromeSafariBrowser): ChromeSafariBrowser.isClassSupported, - classNameOf(CookieManager): CookieManager.isClassSupported, - classNameOf(WebStorage): WebStorage.isClassSupported, - classNameOf(FindInteractionController): - FindInteractionController.isClassSupported, - classNameOf(PullToRefreshController): - PullToRefreshController.isClassSupported, - classNameOf(PrintJobController): PrintJobController.isClassSupported, - classNameOf(WebAuthenticationSession): - WebAuthenticationSession.isClassSupported, - classNameOf(ServiceWorkerController): - ServiceWorkerController.isClassSupported, - classNameOf(ProxyController): ProxyController.isClassSupported, - classNameOf(TracingController): TracingController.isClassSupported, - classNameOf(HttpAuthCredentialDatabase): - HttpAuthCredentialDatabase.isClassSupported, - classNameOf(WebViewEnvironment): WebViewEnvironment.isClassSupported, - classNameOf(ProcessGlobalConfig): ProcessGlobalConfig.isClassSupported, - classNameOf(WebMessageChannel): WebMessageChannel.isClassSupported, - }; - - static final Map _methodSupportResolvers = { - classNameOf(InAppWebViewController): _buildMethodResolver( - values: PlatformInAppWebViewControllerMethod.values, - checker: InAppWebViewController.isMethodSupported, - ), - classNameOf(HeadlessInAppWebView): _buildMethodResolver( - values: PlatformHeadlessInAppWebViewMethod.values, - checker: HeadlessInAppWebView.isMethodSupported, - ), - classNameOf(InAppBrowser): _buildMethodResolver( - values: PlatformInAppBrowserMethod.values, - checker: InAppBrowser.isMethodSupported, - ), - classNameOf(ChromeSafariBrowser): _buildMethodResolver( - values: PlatformChromeSafariBrowserMethod.values, - checker: ChromeSafariBrowser.isMethodSupported, - ), - classNameOf(CookieManager): _buildMethodResolver( - values: PlatformCookieManagerMethod.values, - checker: CookieManager.isMethodSupported, - ), - classNameOf(WebStorage): _buildMethodResolver( - values: PlatformLocalStorageMethod.values, - checker: LocalStorage.isMethodSupported, - ), - classNameOf(FindInteractionController): _buildMethodResolver( - values: PlatformFindInteractionControllerMethod.values, - checker: FindInteractionController.isMethodSupported, - ), - classNameOf(PullToRefreshController): _buildMethodResolver( - values: PlatformPullToRefreshControllerMethod.values, - checker: PullToRefreshController.isMethodSupported, - ), - classNameOf(PrintJobController): _buildMethodResolver( - values: PlatformPrintJobControllerMethod.values, - checker: PrintJobController.isMethodSupported, - ), - classNameOf(WebAuthenticationSession): _buildMethodResolver( - values: PlatformWebAuthenticationSessionMethod.values, - checker: WebAuthenticationSession.isMethodSupported, - ), - classNameOf(ServiceWorkerController): _buildMethodResolver( - values: PlatformServiceWorkerControllerMethod.values, - checker: ServiceWorkerController.isMethodSupported, - ), - classNameOf(ProxyController): _buildMethodResolver( - values: PlatformProxyControllerMethod.values, - checker: ProxyController.isMethodSupported, - ), - classNameOf(TracingController): _buildMethodResolver( - values: PlatformTracingControllerMethod.values, - checker: TracingController.isMethodSupported, - ), - classNameOf(HttpAuthCredentialDatabase): _buildMethodResolver( - values: PlatformHttpAuthCredentialDatabaseMethod.values, - checker: HttpAuthCredentialDatabase.isMethodSupported, - ), - classNameOf(WebViewEnvironment): _buildMethodResolver( - values: PlatformWebViewEnvironmentMethod.values, - checker: WebViewEnvironment.isMethodSupported, - ), - classNameOf(ProcessGlobalConfig): _buildMethodResolver( - values: PlatformProcessGlobalConfigMethod.values, - checker: ProcessGlobalConfig.isMethodSupported, - ), - classNameOf(WebMessageChannel): _buildMethodResolver( - values: PlatformWebMessageChannelMethod.values, - checker: WebMessageChannel.isMethodSupported, - ), - }; - - static final Map _eventSupportResolvers = { - eventClassNameOf(InAppWebView): _buildPropertyResolver( - values: PlatformWebViewCreationParamsProperty.values, - checker: InAppWebView.isPropertySupported, - ), - classNameOf(FindInteractionController): _buildPropertyResolver( - values: PlatformFindInteractionControllerCreationParamsProperty.values, - checker: (property, {platform}) => - FindInteractionController.isPropertySupported( - property as PlatformFindInteractionControllerCreationParamsProperty, - platform: platform, - ), - ), - }; - - /// Get all API definitions organized by class. - static List getAllApiDefinitions() { - return [ - _getInAppWebViewControllerDefinition(), - _getInAppWebViewEventsDefinition(), - _getHeadlessInAppWebViewDefinition(), - _getInAppBrowserDefinition(), - _getChromeSafariBrowserDefinition(), - _getCookieManagerDefinition(), - _getWebStorageDefinition(), - _getFindInteractionControllerDefinition(), - _getPullToRefreshControllerDefinition(), - _getPrintJobControllerDefinition(), - _getWebAuthenticationSessionDefinition(), - _getServiceWorkerControllerDefinition(), - _getProxyControllerDefinition(), - _getTracingControllerDefinition(), - _getHttpAuthCredentialDatabaseDefinition(), - _getWebViewEnvironmentDefinition(), - _getProcessGlobalConfigDefinition(), - _getWebMessageChannelDefinition(), - ]; - } - - /// Check if a specific method is supported on current platform. - static bool isMethodSupported(String className, String methodName) { - final currentPlatform = _getCurrentPlatform(); - if (currentPlatform == null) return false; - return isMethodSupportedForPlatform(className, methodName, currentPlatform); - } - - /// Check if a specific method is supported on a target platform. - static bool isMethodSupportedForPlatform( - String className, - String methodName, - SupportedPlatform platform, - ) { - final resolver = _methodSupportResolvers[className]; - if (resolver != null) { - return resolver(methodName, platform); - } - - final definitions = getAllApiDefinitions(); - final classDef = definitions.cast().firstWhere( - (c) => c?.className == className, - orElse: () => null, - ); - if (classDef == null) return false; - - final method = classDef.methods.cast().firstWhere( - (m) => m?.name == methodName, - orElse: () => null, - ); - if (method == null) return false; - - return method.isSupported(platform); - } - - /// Check if a specific event is supported on current platform. - static bool isEventSupported(String className, String eventName) { - final currentPlatform = _getCurrentPlatform(); - if (currentPlatform == null) return false; - return isEventSupportedForPlatform(className, eventName, currentPlatform); - } - - /// Check if a specific event is supported on a target platform. - static bool isEventSupportedForPlatform( - String className, - String eventName, - SupportedPlatform platform, - ) { - final resolver = _eventSupportResolvers[className]; - if (resolver != null) { - return resolver(eventName, platform); - } - - final definitions = getAllApiDefinitions(); - final classDef = definitions.cast().firstWhere( - (c) => c?.className == className, - orElse: () => null, - ); - if (classDef == null) return false; - - final event = classDef.events.cast().firstWhere( - (e) => e?.name == eventName, - orElse: () => null, - ); - if (event == null) return false; - - return event.isSupported(platform); - } - - /// Returns supported platforms for a given class. - static Set getSupportedPlatformsForClass( - String className, - ) { - final resolver = _classSupportResolvers[className]; - if (resolver != null) { - return SupportCheckHelper.supportedPlatformsForClass(checker: resolver); - } - - final definitions = getAllApiDefinitions(); - final classDef = definitions.cast().firstWhere( - (c) => c?.className == className, - orElse: () => null, - ); - if (classDef == null) return {}; - - final supported = {}; - if (classDef.isClassSupported != null) { - final currentPlatform = _getCurrentPlatform(); - if (currentPlatform != null && classDef.isClassSupported!()) { - supported.add(currentPlatform); - } - } - - for (final platform in SupportedPlatform.values) { - if (classDef.methods.any((m) => m.isSupported(platform)) || - classDef.events.any((e) => e.isSupported(platform))) { - supported.add(platform); - } - } - return supported; - } - - /// Returns supported platforms for a specific method. - static Set getSupportedPlatformsForMethod( - String className, - String methodName, - ) { - final resolver = _methodSupportResolvers[className]; - if (resolver != null) { - return SupportedPlatform.values - .where((p) => resolver(methodName, p)) - .toSet(); - } - // No resolver registered for this class - return {}; - } - - /// Returns supported platforms for a specific event. - static Set getSupportedPlatformsForEvent( - String className, - String eventName, - ) { - final resolver = _eventSupportResolvers[className]; - if (resolver != null) { - return SupportedPlatform.values - .where((p) => resolver(eventName, p)) - .toSet(); - } - // No resolver registered for this class - return {}; - } - - /// Get support summary statistics. - static SupportSummary getSupportSummary() { - final definitions = getAllApiDefinitions(); - - int totalMethods = 0; - int totalEvents = 0; - final methodsPerPlatform = {}; - final eventsPerPlatform = {}; - - for (final platform in SupportedPlatform.values) { - methodsPerPlatform[platform] = 0; - eventsPerPlatform[platform] = 0; - } - - for (final classDef in definitions) { - totalMethods += classDef.methods.length; - totalEvents += classDef.events.length; - - for (final method in classDef.methods) { - final supported = getSupportedPlatformsForMethod( - classDef.className, - method.name, - ); - for (final platform in supported) { - methodsPerPlatform[platform] = methodsPerPlatform[platform]! + 1; - } - } - - for (final event in classDef.events) { - final supported = getSupportedPlatformsForEvent( - classDef.className, - event.name, - ); - for (final platform in supported) { - eventsPerPlatform[platform] = eventsPerPlatform[platform]! + 1; - } - } - } - - return SupportSummary( - totalMethods: totalMethods, - totalEvents: totalEvents, - methodsPerPlatform: methodsPerPlatform, - eventsPerPlatform: eventsPerPlatform, - ); - } - - static SupportedPlatform? _getCurrentPlatform() { - if (kIsWeb) return SupportedPlatform.web; - switch (defaultTargetPlatform) { - case TargetPlatform.android: - return SupportedPlatform.android; - case TargetPlatform.iOS: - return SupportedPlatform.ios; - case TargetPlatform.macOS: - return SupportedPlatform.macos; - case TargetPlatform.windows: - return SupportedPlatform.windows; - case TargetPlatform.linux: - return SupportedPlatform.linux; - default: - return null; - } - } - - // ==================== - // API Class Definitions - // ==================== - - static ApiClassDefinition _getInAppWebViewControllerDefinition() { - final className = classNameOf(InAppWebViewController); - return ApiClassDefinition( - className: className, - description: 'Controls an ${InAppWebView} instance.', - isClassSupported: () => InAppWebViewController.isClassSupported(), - methods: [ - // Navigation methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.loadUrl.name, - signature: 'Future loadUrl({required URLRequest urlRequest})', - description: 'Loads the given URL with optional headers.', - className: className, - category: 'Navigation', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.postUrl.name, - signature: - 'Future postUrl({required WebUri url, required Uint8List postData})', - description: 'Loads the URL with POST data.', - className: className, - category: 'Navigation', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.loadData.name, - signature: 'Future loadData({required String data, ...})', - description: 'Loads HTML data directly into the WebView.', - className: className, - category: 'Navigation', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.loadFile.name, - signature: 'Future loadFile({required String assetFilePath})', - description: 'Loads a file from the asset bundle.', - className: className, - category: 'Navigation', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.reload.name, - signature: 'Future reload()', - description: 'Reloads the current page.', - className: className, - category: 'Navigation', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.reloadFromOrigin.name, - signature: 'Future reloadFromOrigin()', - description: - 'Reloads the current page, performing end-to-end validation.', - className: className, - category: 'Navigation', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.goBack.name, - signature: 'Future goBack()', - description: 'Goes back in the history of the WebView.', - className: className, - category: 'Navigation', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.goForward.name, - signature: 'Future goForward()', - description: 'Goes forward in the history of the WebView.', - className: className, - category: 'Navigation', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.goBackOrForward.name, - signature: 'Future goBackOrForward({required int steps})', - description: 'Goes to the history item at the given offset.', - className: className, - category: 'Navigation', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.goTo.name, - signature: 'Future goTo({required WebHistoryItem historyItem})', - description: 'Goes to the specified history item.', - className: className, - category: 'Navigation', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.canGoBack.name, - signature: 'Future canGoBack()', - description: 'Returns whether the WebView can go back in history.', - className: className, - category: 'Navigation', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.canGoForward.name, - signature: 'Future canGoForward()', - description: 'Returns whether the WebView can go forward in history.', - className: className, - category: 'Navigation', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.canGoBackOrForward.name, - signature: 'Future canGoBackOrForward({required int steps})', - description: - 'Returns whether the WebView can go to the specified offset.', - className: className, - category: 'Navigation', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.isLoading.name, - signature: 'Future isLoading()', - description: 'Returns whether the WebView is currently loading.', - className: className, - category: 'Navigation', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.stopLoading.name, - signature: 'Future stopLoading()', - description: 'Stops the current page load.', - className: className, - category: 'Navigation', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.loadSimulatedRequest.name, - signature: - 'Future loadSimulatedRequest({required URLRequest urlRequest, ...})', - description: - 'Navigates to a requested URL with simulated response data.', - className: className, - category: 'Navigation', - ), - - // Page Info methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getUrl.name, - signature: 'Future getUrl()', - description: 'Gets the current URL of the WebView.', - className: className, - category: 'Page Info', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getTitle.name, - signature: 'Future getTitle()', - description: 'Gets the title of the current page.', - className: className, - category: 'Page Info', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getProgress.name, - signature: 'Future getProgress()', - description: 'Gets the current loading progress.', - className: className, - category: 'Page Info', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getHtml.name, - signature: 'Future getHtml()', - description: 'Gets the HTML content of the current page.', - className: className, - category: 'Page Info', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getFavicons.name, - signature: 'Future> getFavicons()', - description: 'Gets the favicons of the current page.', - className: className, - category: 'Page Info', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getOriginalUrl.name, - signature: 'Future getOriginalUrl()', - description: 'Gets the original URL before redirects.', - className: className, - category: 'Page Info', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getSelectedText.name, - signature: 'Future getSelectedText()', - description: 'Gets the currently selected text.', - className: className, - category: 'Page Info', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getHitTestResult.name, - signature: - 'Future<${InAppWebViewHitTestResult}?> ${PlatformInAppWebViewControllerMethod.getHitTestResult.name}()', - description: 'Gets a hit test result for the last tap.', - className: className, - category: 'Page Info', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getMetaTags.name, - signature: 'Future> getMetaTags()', - description: 'Gets all meta tags of the current page.', - className: className, - category: 'Page Info', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getMetaThemeColor.name, - signature: 'Future getMetaThemeColor()', - description: 'Gets the meta theme color of the page.', - className: className, - category: 'Page Info', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getCertificate.name, - signature: 'Future getCertificate()', - description: 'Gets the SSL certificate for the main resource.', - className: className, - category: 'Page Info', - ), - ApiMethodDefinition( - name: - PlatformInAppWebViewControllerMethod.getCopyBackForwardList.name, - signature: 'Future getCopyBackForwardList()', - description: 'Gets a copy of the back/forward list.', - className: className, - category: 'Page Info', - ), - - // JavaScript methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.evaluateJavascript.name, - signature: - 'Future evaluateJavascript({required String source, ...})', - description: 'Evaluates JavaScript code and returns the result.', - className: className, - category: 'JavaScript', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.callAsyncJavaScript.name, - signature: - 'Future callAsyncJavaScript({...})', - description: 'Calls a JavaScript function asynchronously.', - className: className, - category: 'JavaScript', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .injectJavascriptFileFromUrl - .name, - signature: - 'Future injectJavascriptFileFromUrl({required WebUri urlFile, ...})', - description: 'Injects a JavaScript file from a URL.', - className: className, - category: 'JavaScript', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .injectJavascriptFileFromAsset - .name, - signature: - 'Future injectJavascriptFileFromAsset({required String assetFilePath})', - description: 'Injects a JavaScript file from assets.', - className: className, - category: 'JavaScript', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.injectCSSCode.name, - signature: 'Future injectCSSCode({required String source})', - description: 'Injects CSS code into the page.', - className: className, - category: 'JavaScript', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.injectCSSFileFromUrl.name, - signature: - 'Future injectCSSFileFromUrl({required WebUri urlFile, ...})', - description: 'Injects a CSS file from a URL.', - className: className, - category: 'JavaScript', - ), - ApiMethodDefinition( - name: - PlatformInAppWebViewControllerMethod.injectCSSFileFromAsset.name, - signature: - 'Future injectCSSFileFromAsset({required String assetFilePath})', - description: 'Injects a CSS file from assets.', - className: className, - category: 'JavaScript', - ), - - // JavaScript Handler methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.addJavaScriptHandler.name, - signature: - 'void addJavaScriptHandler({required String handlerName, ...})', - description: 'Adds a handler for JavaScript to call.', - className: className, - category: 'Handlers', - ), - ApiMethodDefinition( - name: - PlatformInAppWebViewControllerMethod.removeJavaScriptHandler.name, - signature: - 'JavaScriptHandlerCallback? removeJavaScriptHandler({required String handlerName})', - description: 'Removes a JavaScript handler.', - className: className, - category: 'Handlers', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.hasJavaScriptHandler.name, - signature: 'bool hasJavaScriptHandler({required String handlerName})', - description: 'Checks if a JavaScript handler exists.', - className: className, - category: 'Handlers', - ), - - // User Scripts methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.addUserScript.name, - signature: - 'Future addUserScript({required UserScript userScript})', - description: 'Adds a user script to the WebView.', - className: className, - category: 'User Scripts', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.removeUserScript.name, - signature: - 'Future removeUserScript({required UserScript userScript})', - description: 'Removes a user script.', - className: className, - category: 'User Scripts', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .removeUserScriptsByGroupName - .name, - signature: - 'Future removeUserScriptsByGroupName({required String groupName})', - description: 'Removes user scripts by group name.', - className: className, - category: 'User Scripts', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.removeAllUserScripts.name, - signature: 'Future removeAllUserScripts()', - description: 'Removes all user scripts.', - className: className, - category: 'User Scripts', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.hasUserScript.name, - signature: 'bool hasUserScript({required UserScript userScript})', - description: 'Checks if a user script exists.', - className: className, - category: 'User Scripts', - ), - - // Scrolling methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.scrollTo.name, - signature: - 'Future scrollTo({required int x, required int y, bool animated})', - description: 'Scrolls the WebView to the specified position.', - className: className, - category: 'Scrolling', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.scrollBy.name, - signature: - 'Future scrollBy({required int x, required int y, bool animated})', - description: 'Scrolls the WebView by the specified amount.', - className: className, - category: 'Scrolling', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getScrollX.name, - signature: 'Future getScrollX()', - description: 'Gets the current horizontal scroll position.', - className: className, - category: 'Scrolling', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getScrollY.name, - signature: 'Future getScrollY()', - description: 'Gets the current vertical scroll position.', - className: className, - category: 'Scrolling', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getContentHeight.name, - signature: 'Future getContentHeight()', - description: 'Gets the height of the HTML content.', - className: className, - category: 'Scrolling', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getContentWidth.name, - signature: 'Future getContentWidth()', - description: 'Gets the width of the HTML content.', - className: className, - category: 'Scrolling', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.canScrollVertically.name, - signature: 'Future canScrollVertically()', - description: 'Checks if the WebView can scroll vertically.', - className: className, - category: 'Scrolling', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.canScrollHorizontally.name, - signature: 'Future canScrollHorizontally()', - description: 'Checks if the WebView can scroll horizontally.', - className: className, - category: 'Scrolling', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.pageDown.name, - signature: 'Future pageDown({required bool bottom})', - description: 'Scrolls down by half or full page.', - className: className, - category: 'Scrolling', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.pageUp.name, - signature: 'Future pageUp({required bool top})', - description: 'Scrolls up by half or full page.', - className: className, - category: 'Scrolling', - ), - - // Zoom methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.zoomBy.name, - signature: 'Future zoomBy({required double zoomFactor, ...})', - description: 'Zooms by the specified factor.', - className: className, - category: 'Zoom', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.zoomIn.name, - signature: 'Future zoomIn()', - description: 'Zooms in by a standard amount.', - className: className, - category: 'Zoom', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.zoomOut.name, - signature: 'Future zoomOut()', - description: 'Zooms out by a standard amount.', - className: className, - category: 'Zoom', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getZoomScale.name, - signature: 'Future getZoomScale()', - description: 'Gets the current zoom scale.', - className: className, - category: 'Zoom', - ), - - // Settings methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.setSettings.name, - signature: - 'Future ${PlatformInAppWebViewControllerMethod.setSettings.name}({required ${InAppWebViewSettings} settings})', - description: 'Updates the WebView settings.', - className: className, - category: 'Settings', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getSettings.name, - signature: - 'Future<${InAppWebViewSettings}?> ${PlatformInAppWebViewControllerMethod.getSettings.name}()', - description: 'Gets the current WebView settings.', - className: className, - category: 'Settings', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.setContextMenu.name, - signature: 'Future setContextMenu(ContextMenu? contextMenu)', - description: 'Sets the context menu.', - className: className, - category: 'Settings', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.requestFocus.name, - signature: 'Future requestFocus()', - description: 'Requests focus for the WebView.', - className: className, - category: 'Settings', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.clearFocus.name, - signature: 'Future clearFocus()', - description: 'Clears focus from the WebView.', - className: className, - category: 'Settings', - ), - - // Screenshot methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.takeScreenshot.name, - signature: - 'Future takeScreenshot({ScreenshotConfiguration? screenshotConfiguration})', - description: 'Takes a screenshot of the WebView.', - className: className, - category: 'Screenshot', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.printCurrentPage.name, - signature: - 'Future<${PrintJobController}?> ${PlatformInAppWebViewControllerMethod.printCurrentPage.name}({${PrintJobSettings}? settings})', - description: 'Prints the current page.', - className: className, - category: 'Screenshot', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.createPdf.name, - signature: - 'Future createPdf({PdfConfiguration? pdfConfiguration})', - description: 'Creates a PDF from the current page.', - className: className, - category: 'Screenshot', - ), - - // Cache methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.clearHistory.name, - signature: 'Future clearHistory()', - description: 'Clears the WebView history.', - className: className, - category: 'Cache', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.clearFormData.name, - signature: 'Future clearFormData()', - description: 'Clears form data.', - className: className, - category: 'Cache', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.clearSslPreferences.name, - signature: 'Future clearSslPreferences()', - description: 'Clears SSL preferences.', - className: className, - category: 'Cache', - ), - - // Pause/Resume methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.pause.name, - signature: 'Future pause()', - description: 'Pauses the WebView.', - className: className, - category: 'Pause/Resume', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.resume.name, - signature: 'Future resume()', - description: 'Resumes the WebView.', - className: className, - category: 'Pause/Resume', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.pauseTimers.name, - signature: 'Future pauseTimers()', - description: 'Pauses all layout, parsing, and JavaScript timers.', - className: className, - category: 'Pause/Resume', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.resumeTimers.name, - signature: 'Future resumeTimers()', - description: 'Resumes all layout, parsing, and JavaScript timers.', - className: className, - category: 'Pause/Resume', - ), - - // Web Messaging methods - ApiMethodDefinition( - name: - PlatformInAppWebViewControllerMethod.createWebMessageChannel.name, - signature: - 'Future<${WebMessageChannel}?> ${PlatformInAppWebViewControllerMethod.createWebMessageChannel.name}()', - description: 'Creates a message channel for communication.', - className: className, - category: 'Web Messaging', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.postWebMessage.name, - signature: - 'Future ${PlatformInAppWebViewControllerMethod.postWebMessage.name}({required ${WebMessage} message, ...})', - description: 'Posts a message to the WebView.', - className: className, - category: 'Web Messaging', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.addWebMessageListener.name, - signature: - 'Future ${PlatformInAppWebViewControllerMethod.addWebMessageListener.name}(${WebMessageListener} webMessageListener)', - description: 'Adds a listener for web messages.', - className: className, - category: 'Web Messaging', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.hasWebMessageListener.name, - signature: - 'bool hasWebMessageListener({required String jsObjectName})', - description: 'Checks if a web message listener exists.', - className: className, - category: 'Web Messaging', - ), - - // Media methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.isInFullscreen.name, - signature: 'Future isInFullscreen()', - description: 'Returns whether the WebView is in fullscreen mode.', - className: className, - category: 'Media', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.pauseAllMediaPlayback.name, - signature: 'Future pauseAllMediaPlayback()', - description: 'Pauses all media playback.', - className: className, - category: 'Media', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .setAllMediaPlaybackSuspended - .name, - signature: - 'Future setAllMediaPlaybackSuspended({required bool suspended})', - description: 'Suspends or resumes all media playback.', - className: className, - category: 'Media', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .closeAllMediaPresentations - .name, - signature: 'Future closeAllMediaPresentations()', - description: 'Closes all media presentations.', - className: className, - category: 'Media', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .requestMediaPlaybackState - .name, - signature: 'Future requestMediaPlaybackState()', - description: 'Gets the current media playback state.', - className: className, - category: 'Media', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.isPlayingAudio.name, - signature: 'Future isPlayingAudio()', - description: 'Checks if audio is currently playing.', - className: className, - category: 'Media', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.isMuted.name, - signature: 'Future isMuted()', - description: 'Checks if audio is muted.', - className: className, - category: 'Media', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.setMuted.name, - signature: 'Future setMuted({required bool muted})', - description: 'Sets the muted state.', - className: className, - category: 'Media', - ), - - // Camera/Mic methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getCameraCaptureState.name, - signature: 'Future getCameraCaptureState()', - description: 'Gets the camera capture state.', - className: className, - category: 'Camera/Mic', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.setCameraCaptureState.name, - signature: - 'Future setCameraCaptureState({required MediaCaptureState state})', - description: 'Sets the camera capture state.', - className: className, - category: 'Camera/Mic', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .getMicrophoneCaptureState - .name, - signature: 'Future getMicrophoneCaptureState()', - description: 'Gets the microphone capture state.', - className: className, - category: 'Camera/Mic', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .setMicrophoneCaptureState - .name, - signature: - 'Future setMicrophoneCaptureState({required MediaCaptureState state})', - description: 'Sets the microphone capture state.', - className: className, - category: 'Camera/Mic', - ), - - // Security methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.isSecureContext.name, - signature: 'Future isSecureContext()', - description: 'Checks if the current context is secure (HTTPS).', - className: className, - category: 'Security', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.hasOnlySecureContent.name, - signature: 'Future hasOnlySecureContent()', - description: 'Checks if the page has only secure content.', - className: className, - category: 'Security', - ), - - // Android-specific methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.startSafeBrowsing.name, - signature: 'Future startSafeBrowsing()', - description: 'Starts the Safe Browsing initialization.', - className: className, - category: 'Android', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.saveWebArchive.name, - signature: - 'Future saveWebArchive({required String basename, ...})', - description: 'Saves the current page as a web archive.', - className: className, - category: 'Android', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.requestFocusNodeHref.name, - signature: - 'Future requestFocusNodeHref()', - description: 'Requests the URL of the focused anchor.', - className: className, - category: 'Android', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.requestImageRef.name, - signature: 'Future requestImageRef()', - description: 'Requests the URL of the focused image.', - className: className, - category: 'Android', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.saveState.name, - signature: 'Future saveState()', - description: 'Saves the WebView state to a bundle.', - className: className, - category: 'Android', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.restoreState.name, - signature: 'Future restoreState({required Uint8List state})', - description: 'Restores the WebView state from a bundle.', - className: className, - category: 'Android', - ), - - // iOS/macOS-specific methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.createWebArchiveData.name, - signature: 'Future createWebArchiveData()', - description: 'Creates a web archive of the current page.', - className: className, - category: 'iOS/macOS', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.terminateWebProcess.name, - signature: 'Future terminateWebProcess()', - description: 'Terminates the web content process.', - className: className, - category: 'iOS/macOS', - ), - - // Windows-specific methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.openDevTools.name, - signature: 'Future openDevTools()', - description: 'Opens the browser DevTools.', - className: className, - category: 'Windows', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .callDevToolsProtocolMethod - .name, - signature: - 'Future callDevToolsProtocolMethod({required String methodName, ...})', - description: 'Calls a DevTools Protocol method.', - className: className, - category: 'Windows', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .addDevToolsProtocolEventListener - .name, - signature: - 'Future addDevToolsProtocolEventListener({required String eventName, ...})', - description: 'Adds a DevTools Protocol event listener.', - className: className, - category: 'Windows', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .removeDevToolsProtocolEventListener - .name, - signature: - 'Future removeDevToolsProtocolEventListener({required String eventName})', - description: 'Removes a DevTools Protocol event listener.', - className: className, - category: 'Windows', - ), - - // Web-specific methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getIFrameId.name, - signature: 'Future getIFrameId()', - description: 'Gets the iframe ID on web platform.', - className: className, - category: 'Web', - ), - - // Other methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getViewId.name, - signature: 'int getViewId()', - description: 'Gets the view ID of the WebView.', - className: className, - category: 'Other', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.dispose.name, - signature: 'void dispose()', - description: 'Disposes the controller and releases resources.', - className: className, - category: 'Other', - ), - - // Static methods - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getDefaultUserAgent.name, - signature: 'static Future getDefaultUserAgent()', - description: 'Gets the default User-Agent string.', - className: className, - isStatic: true, - category: 'Static', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .clearClientCertPreferences - .name, - signature: 'static Future clearClientCertPreferences()', - description: 'Clears the client certificate preferences.', - className: className, - isStatic: true, - category: 'Static', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .getSafeBrowsingPrivacyPolicyUrl - .name, - signature: 'static Future getSafeBrowsingPrivacyPolicyUrl()', - description: 'Gets the Safe Browsing privacy policy URL.', - className: className, - isStatic: true, - category: 'Static', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .setSafeBrowsingAllowlist - .name, - signature: - 'static Future setSafeBrowsingAllowlist({required List hosts})', - description: 'Sets the Safe Browsing allowlist.', - className: className, - isStatic: true, - category: 'Static', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .getCurrentWebViewPackage - .name, - signature: - 'static Future getCurrentWebViewPackage()', - description: 'Gets the current WebView package info.', - className: className, - isStatic: true, - category: 'Static', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .setWebContentsDebuggingEnabled - .name, - signature: - 'static Future setWebContentsDebuggingEnabled(bool debuggingEnabled)', - description: 'Enables or disables debugging.', - className: className, - isStatic: true, - category: 'Static', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.getVariationsHeader.name, - signature: 'static Future getVariationsHeader()', - description: 'Gets the variations header.', - className: className, - isStatic: true, - category: 'Static', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.isMultiProcessEnabled.name, - signature: 'static Future isMultiProcessEnabled()', - description: 'Checks if multi-process is enabled.', - className: className, - isStatic: true, - category: 'Static', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.disableWebView.name, - signature: 'static Future disableWebView()', - description: 'Disables the WebView.', - className: className, - isStatic: true, - category: 'Static', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.handlesURLScheme.name, - signature: 'static Future handlesURLScheme(String urlScheme)', - description: 'Checks if the WebView handles a URL scheme.', - className: className, - isStatic: true, - category: 'Static', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.disposeKeepAlive.name, - signature: - 'static Future disposeKeepAlive(${InAppWebViewKeepAlive} keepAlive)', - description: 'Disposes a keep-alive instance.', - className: className, - isStatic: true, - category: 'Static', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod.clearAllCache.name, - signature: - 'static Future clearAllCache({bool includeDiskFiles = true})', - description: 'Clears all WebView caches.', - className: className, - isStatic: true, - category: 'Static', - ), - ApiMethodDefinition( - name: PlatformInAppWebViewControllerMethod - .enableSlowWholeDocumentDraw - .name, - signature: 'static Future enableSlowWholeDocumentDraw()', - description: 'Enables slow whole document draw.', - className: className, - isStatic: true, - category: 'Static', - ), - ApiMethodDefinition( - name: - PlatformInAppWebViewControllerMethod.setJavaScriptBridgeName.name, - signature: - 'static Future setJavaScriptBridgeName(String bridgeName)', - description: 'Sets the JavaScript bridge name.', - className: className, - isStatic: true, - category: 'Static', - ), - ApiMethodDefinition( - name: - PlatformInAppWebViewControllerMethod.getJavaScriptBridgeName.name, - signature: 'static Future getJavaScriptBridgeName()', - description: 'Gets the JavaScript bridge name.', - className: className, - isStatic: true, - category: 'Static', - ), - ], - ); - } - - static ApiClassDefinition _getInAppWebViewEventsDefinition() { - final className = eventClassNameOf(InAppWebView); - return ApiClassDefinition( - className: className, - description: 'Events fired by ${InAppWebView}.', - events: [ - // Core events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onWebViewCreated.name, - description: 'Called when the WebView is created.', - className: className, - category: 'Core', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onLoadStart.name, - description: 'Called when a page starts loading.', - className: className, - category: 'Core', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onLoadStop.name, - description: 'Called when a page finishes loading.', - className: className, - category: 'Core', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onLoadError.name, - description: 'Called when a page fails to load.', - className: className, - category: 'Core', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onLoadHttpError.name, - description: 'Called when an HTTP error is received.', - className: className, - category: 'Core', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onProgressChanged.name, - description: 'Called when the loading progress changes.', - className: className, - category: 'Core', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onConsoleMessage.name, - description: 'Called when a console message is received.', - className: className, - category: 'Core', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onTitleChanged.name, - description: 'Called when the page title changes.', - className: className, - category: 'Core', - ), - ApiEventDefinition( - name: - PlatformWebViewCreationParamsProperty.onUpdateVisitedHistory.name, - description: 'Called when the visited history is updated.', - className: className, - category: 'Core', - ), - - // Navigation events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .shouldOverrideUrlLoading - .name, - description: 'Called to handle URL navigation requests.', - className: className, - category: 'Navigation', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onNavigationResponse.name, - description: 'Called when receiving a navigation response.', - className: className, - category: 'Navigation', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .shouldAllowDeprecatedTLS - .name, - description: 'Called to check if deprecated TLS should be allowed.', - className: className, - category: 'Navigation', - ), - - // Window events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onCreateWindow.name, - description: 'Called when a new window is requested.', - className: className, - category: 'Window', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onCloseWindow.name, - description: 'Called when a window should be closed.', - className: className, - category: 'Window', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onWindowFocus.name, - description: 'Called when the window receives focus.', - className: className, - category: 'Window', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onWindowBlur.name, - description: 'Called when the window loses focus.', - className: className, - category: 'Window', - ), - - // JS Dialog events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onJsAlert.name, - description: 'Called when a JavaScript alert is shown.', - className: className, - category: 'JS Dialogs', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onJsConfirm.name, - description: 'Called when a JavaScript confirm is shown.', - className: className, - category: 'JS Dialogs', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onJsPrompt.name, - description: 'Called when a JavaScript prompt is shown.', - className: className, - category: 'JS Dialogs', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onJsBeforeUnload.name, - description: 'Called before the page is unloaded.', - className: className, - category: 'JS Dialogs', - ), - - // Authentication events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .onReceivedHttpAuthRequest - .name, - description: 'Called for HTTP authentication requests.', - className: className, - category: 'Authentication', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .onReceivedServerTrustAuthRequest - .name, - description: 'Called for server trust authentication.', - className: className, - category: 'Authentication', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .onReceivedClientCertRequest - .name, - description: 'Called when a client certificate is requested.', - className: className, - category: 'Authentication', - ), - - // Network events - ApiEventDefinition( - name: - PlatformWebViewCreationParamsProperty.shouldInterceptRequest.name, - description: 'Called to intercept resource requests.', - className: className, - category: 'Network', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onLoadResource.name, - description: 'Called when a resource is loaded.', - className: className, - category: 'Network', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .onLoadResourceWithCustomScheme - .name, - description: 'Called when loading a custom scheme resource.', - className: className, - category: 'Network', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onReceivedError.name, - description: 'Called when a resource load error occurs.', - className: className, - category: 'Network', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onReceivedHttpError.name, - description: 'Called when an HTTP error occurs.', - className: className, - category: 'Network', - ), - - // Download events - ApiEventDefinition( - name: - PlatformWebViewCreationParamsProperty.onDownloadStartRequest.name, - description: 'Called when a download is requested.', - className: className, - category: 'Download', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onDownloadStarting.name, - description: 'Called when a download is starting.', - className: className, - category: 'Download', - ), - - // Scroll events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onScrollChanged.name, - description: 'Called when the scroll position changes.', - className: className, - category: 'Scroll', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onOverScrolled.name, - description: 'Called when the WebView is over-scrolled.', - className: className, - category: 'Scroll', - ), - - // Zoom events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onZoomScaleChanged.name, - description: 'Called when the zoom scale changes.', - className: className, - category: 'Zoom', - ), - - // Print events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onPrintRequest.name, - description: 'Called when a print request is made.', - className: className, - category: 'Print', - ), - - // Fullscreen events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onEnterFullscreen.name, - description: 'Called when entering fullscreen mode.', - className: className, - category: 'Fullscreen', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onExitFullscreen.name, - description: 'Called when exiting fullscreen mode.', - className: className, - category: 'Fullscreen', - ), - - // Permission events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onPermissionRequest.name, - description: 'Called when a permission is requested.', - className: className, - category: 'Permission', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .onPermissionRequestCanceled - .name, - description: 'Called when a permission request is canceled.', - className: className, - category: 'Permission', - ), - - // Touch/Gesture events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .onLongPressHitTestResult - .name, - description: 'Called on a long press.', - className: className, - category: 'Touch', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .onGeolocationPermissionsShowPrompt - .name, - description: 'Called when requesting geolocation permission.', - className: className, - category: 'Permission', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .onGeolocationPermissionsHidePrompt - .name, - description: 'Called when hiding geolocation permission prompt.', - className: className, - category: 'Permission', - ), - - // Render Process events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onRenderProcessGone.name, - description: 'Called when the render process terminates.', - className: className, - category: 'Render Process', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .onRenderProcessResponsive - .name, - description: 'Called when the render process becomes responsive.', - className: className, - category: 'Render Process', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .onRenderProcessUnresponsive - .name, - description: 'Called when the render process becomes unresponsive.', - className: className, - category: 'Render Process', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .onWebContentProcessDidTerminate - .name, - description: 'Called when the web content process terminates.', - className: className, - category: 'Render Process', - ), - - // Form events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onFormResubmission.name, - description: 'Called when a form is resubmitted.', - className: className, - category: 'Form', - ), - - // Icon events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onReceivedIcon.name, - description: 'Called when a favicon is received.', - className: className, - category: 'Icon', - ), - ApiEventDefinition( - name: - PlatformWebViewCreationParamsProperty.onReceivedTouchIconUrl.name, - description: 'Called when a touch icon URL is received.', - className: className, - category: 'Icon', - ), - - // Safe Browsing events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onSafeBrowsingHit.name, - description: 'Called when Safe Browsing detects a threat.', - className: className, - category: 'Safe Browsing', - ), - - // iOS/macOS events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .onDidReceiveServerRedirectForProvisionalNavigation - .name, - description: 'Called when a server redirect is received.', - className: className, - category: 'iOS/macOS', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .onCameraCaptureStateChanged - .name, - description: 'Called when camera capture state changes.', - className: className, - category: 'iOS/macOS', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .onMicrophoneCaptureStateChanged - .name, - description: 'Called when microphone capture state changes.', - className: className, - category: 'iOS/macOS', - ), - - // Windows events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onProcessFailed.name, - description: 'Called when a process failure occurs.', - className: className, - category: 'Windows', - ), - - // Other events - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onPageCommitVisible.name, - description: 'Called when the page becomes visible.', - className: className, - category: 'Other', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onContentSizeChanged.name, - description: 'Called when the content size changes.', - className: className, - category: 'Other', - ), - ApiEventDefinition( - name: - PlatformWebViewCreationParamsProperty.onAjaxReadyStateChange.name, - description: 'Called when an AJAX ready state changes.', - className: className, - category: 'Other', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty.onAjaxProgress.name, - description: 'Called for AJAX progress updates.', - className: className, - category: 'Other', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .shouldInterceptAjaxRequest - .name, - description: 'Called to intercept AJAX requests.', - className: className, - category: 'Other', - ), - ApiEventDefinition( - name: PlatformWebViewCreationParamsProperty - .shouldInterceptFetchRequest - .name, - description: 'Called to intercept fetch requests.', - className: className, - category: 'Other', - ), - ], - ); - } - - static ApiClassDefinition _getHeadlessInAppWebViewDefinition() { - final className = classNameOf(HeadlessInAppWebView); - return ApiClassDefinition( - className: className, - description: 'A WebView that runs without UI.', - isClassSupported: () => HeadlessInAppWebView.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: PlatformHeadlessInAppWebViewMethod.run.name, - signature: 'Future run()', - description: 'Runs the headless WebView.', - className: className, - ), - ApiMethodDefinition( - name: PlatformHeadlessInAppWebViewMethod.isRunning.name, - signature: 'Future isRunning()', - description: 'Checks if the WebView is running.', - className: className, - ), - ApiMethodDefinition( - name: PlatformHeadlessInAppWebViewMethod.setSize.name, - signature: 'Future setSize(Size size)', - description: 'Sets the WebView size.', - className: className, - ), - ApiMethodDefinition( - name: PlatformHeadlessInAppWebViewMethod.getSize.name, - signature: 'Future getSize()', - description: 'Gets the WebView size.', - className: className, - ), - ApiMethodDefinition( - name: PlatformHeadlessInAppWebViewMethod.dispose.name, - signature: 'Future dispose()', - description: 'Disposes the headless WebView.', - className: className, - ), - ], - ); - } - - static ApiClassDefinition _getInAppBrowserDefinition() { - final className = classNameOf(InAppBrowser); - return ApiClassDefinition( - className: className, - description: 'A full-screen in-app browser.', - isClassSupported: () => InAppBrowser.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: PlatformInAppBrowserMethod.openUrlRequest.name, - signature: - 'Future openUrlRequest({required URLRequest urlRequest, ...})', - description: 'Opens a URL in the browser.', - className: className, - ), - ApiMethodDefinition( - name: PlatformInAppBrowserMethod.openFile.name, - signature: - 'Future openFile({required String assetFilePath, ...})', - description: 'Opens a file from assets.', - className: className, - ), - ApiMethodDefinition( - name: PlatformInAppBrowserMethod.openData.name, - signature: 'Future openData({required String data, ...})', - description: 'Opens HTML data.', - className: className, - ), - ApiMethodDefinition( - name: PlatformInAppBrowserMethod.openWithSystemBrowser.name, - signature: - 'static Future openWithSystemBrowser({required WebUri url})', - description: 'Opens a URL in the system browser.', - className: className, - isStatic: true, - ), - ApiMethodDefinition( - name: PlatformInAppBrowserMethod.show.name, - signature: 'Future show()', - description: 'Shows the browser.', - className: className, - ), - ApiMethodDefinition( - name: PlatformInAppBrowserMethod.hide.name, - signature: 'Future hide()', - description: 'Hides the browser.', - className: className, - ), - ApiMethodDefinition( - name: PlatformInAppBrowserMethod.close.name, - signature: 'Future close()', - description: 'Closes the browser.', - className: className, - ), - ApiMethodDefinition( - name: PlatformInAppBrowserMethod.isHidden.name, - signature: 'Future isHidden()', - description: 'Checks if the browser is hidden.', - className: className, - ), - ApiMethodDefinition( - name: PlatformInAppBrowserMethod.setSettings.name, - signature: - 'Future ${PlatformInAppBrowserMethod.setSettings.name}({required ${InAppBrowserClassSettings} settings})', - description: 'Sets the browser settings.', - className: className, - ), - ApiMethodDefinition( - name: PlatformInAppBrowserMethod.getSettings.name, - signature: - 'Future<${InAppBrowserClassSettings}?> ${PlatformInAppBrowserMethod.getSettings.name}()', - description: 'Gets the browser settings.', - className: className, - ), - ApiMethodDefinition( - name: PlatformInAppBrowserMethod.isOpened.name, - signature: 'bool isOpened()', - description: 'Checks if the browser is opened.', - className: className, - ), - ], - events: [ - ApiEventDefinition( - name: PlatformInAppBrowserEventsMethod.onBrowserCreated.name, - description: 'Called when the browser is created.', - className: className, - ), - ApiEventDefinition( - name: PlatformInAppBrowserEventsMethod.onExit.name, - description: 'Called when the browser exits.', - className: className, - ), - ApiEventDefinition( - name: PlatformInAppBrowserEventsMethod.onMainWindowWillClose.name, - description: 'Called when the main window will close.', - className: className, - ), - ], - ); - } - - static ApiClassDefinition _getChromeSafariBrowserDefinition() { - final className = classNameOf(ChromeSafariBrowser); - return ApiClassDefinition( - className: className, - description: - 'A browser using Chrome Custom Tabs or SFSafariViewController.', - isClassSupported: () => ChromeSafariBrowser.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.open.name, - signature: 'Future open({WebUri? url, ...})', - description: 'Opens a URL in the browser.', - className: className, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.launchUrl.name, - signature: 'Future launchUrl({required WebUri url, ...})', - description: 'Launches a URL.', - className: className, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.mayLaunchUrl.name, - signature: 'Future mayLaunchUrl({WebUri? url, ...})', - description: 'Hints to the browser to start loading a URL.', - className: className, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.validateRelationship.name, - signature: - 'Future validateRelationship({required CustomTabsRelationType relation, ...})', - description: 'Validates a relationship.', - className: className, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.close.name, - signature: 'Future close()', - description: 'Closes the browser.', - className: className, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.isOpened.name, - signature: 'bool isOpened()', - description: 'Checks if the browser is opened.', - className: className, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.isAvailable.name, - signature: 'static Future isAvailable()', - description: 'Checks if the browser is available.', - className: className, - isStatic: true, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.getMaxToolbarItems.name, - signature: 'static Future getMaxToolbarItems()', - description: 'Gets the maximum toolbar items.', - className: className, - isStatic: true, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.getPackageName.name, - signature: - 'static Future getPackageName({List? packages, ...})', - description: 'Gets the package name for Custom Tabs.', - className: className, - isStatic: true, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.clearWebsiteData.name, - signature: 'static Future clearWebsiteData()', - description: 'Clears website data.', - className: className, - isStatic: true, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.prewarmConnections.name, - signature: - 'static Future prewarmConnections({required List urls})', - description: 'Prewarms connections.', - className: className, - isStatic: true, - ), - ApiMethodDefinition( - name: - PlatformChromeSafariBrowserMethod.invalidatePrewarmingToken.name, - signature: - 'static Future invalidatePrewarmingToken({required PrewarmingToken prewarmingToken})', - description: 'Invalidates a prewarming token.', - className: className, - isStatic: true, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.setActionButton.name, - signature: - 'Future ${PlatformChromeSafariBrowserMethod.setActionButton.name}(${ChromeSafariBrowserActionButton} actionButton)', - description: 'Sets an action button.', - className: className, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.updateActionButton.name, - signature: - 'Future updateActionButton({required Uint8List icon, required String description})', - description: 'Updates the action button.', - className: className, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.setSecondaryToolbar.name, - signature: - 'Future ${PlatformChromeSafariBrowserMethod.setSecondaryToolbar.name}(${ChromeSafariBrowserSecondaryToolbar} secondaryToolbar)', - description: 'Sets a secondary toolbar.', - className: className, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.updateSecondaryToolbar.name, - signature: - 'Future ${PlatformChromeSafariBrowserMethod.updateSecondaryToolbar.name}(${ChromeSafariBrowserSecondaryToolbar} secondaryToolbar)', - description: 'Updates the secondary toolbar.', - className: className, - ), - ApiMethodDefinition( - name: - PlatformChromeSafariBrowserMethod.requestPostMessageChannel.name, - signature: - 'Future requestPostMessageChannel({required WebUri sourceOrigin, ...})', - description: 'Requests a post message channel.', - className: className, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod.postMessage.name, - signature: - 'Future postMessage({required String message})', - description: 'Posts a message.', - className: className, - ), - ApiMethodDefinition( - name: PlatformChromeSafariBrowserMethod - .isEngagementSignalsApiAvailable - .name, - signature: 'Future isEngagementSignalsApiAvailable()', - description: 'Checks if engagement signals API is available.', - className: className, - ), - ], - events: [ - ApiEventDefinition( - name: PlatformChromeSafariBrowserEventsMethod.onOpened.name, - description: 'Called when the browser is opened.', - className: className, - ), - ApiEventDefinition( - name: PlatformChromeSafariBrowserEventsMethod.onClosed.name, - description: 'Called when the browser is closed.', - className: className, - ), - ApiEventDefinition( - name: PlatformChromeSafariBrowserEventsMethod - .onCompletedInitialLoad - .name, - description: 'Called when the initial load completes.', - className: className, - ), - ApiEventDefinition( - name: PlatformChromeSafariBrowserEventsMethod - .onInitialLoadDidRedirect - .name, - description: 'Called when the initial load redirects.', - className: className, - ), - ApiEventDefinition( - name: - PlatformChromeSafariBrowserEventsMethod.onWillOpenInBrowser.name, - description: 'Called when opening in the browser.', - className: className, - ), - ApiEventDefinition( - name: PlatformChromeSafariBrowserEventsMethod.onNavigationEvent.name, - description: 'Called on navigation events.', - className: className, - ), - ApiEventDefinition( - name: PlatformChromeSafariBrowserEventsMethod.onServiceConnected.name, - description: 'Called when the service connects.', - className: className, - ), - ApiEventDefinition( - name: PlatformChromeSafariBrowserEventsMethod - .onRelationshipValidationResult - .name, - description: 'Called with relationship validation results.', - className: className, - ), - ApiEventDefinition( - name: PlatformChromeSafariBrowserEventsMethod - .onMessageChannelReady - .name, - description: 'Called when the message channel is ready.', - className: className, - ), - ApiEventDefinition( - name: PlatformChromeSafariBrowserEventsMethod.onPostMessage.name, - description: 'Called when a post message is received.', - className: className, - ), - ApiEventDefinition( - name: PlatformChromeSafariBrowserEventsMethod - .onVerticalScrollEvent - .name, - description: 'Called on vertical scroll events.', - className: className, - ), - ApiEventDefinition( - name: PlatformChromeSafariBrowserEventsMethod - .onGreatestScrollPercentageIncreased - .name, - description: 'Called when the greatest scroll percentage increases.', - className: className, - ), - ApiEventDefinition( - name: PlatformChromeSafariBrowserEventsMethod.onSessionEnded.name, - description: 'Called when the session ends.', - className: className, - ), - ], - ); - } - - static ApiClassDefinition _getCookieManagerDefinition() { - final className = classNameOf(CookieManager); - return ApiClassDefinition( - className: className, - description: 'Manages cookies for WebViews.', - isClassSupported: () => CookieManager.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: PlatformCookieManagerMethod.setCookie.name, - signature: - 'Future setCookie({required WebUri url, required String name, required String value, ...})', - description: 'Sets a cookie.', - className: className, - ), - ApiMethodDefinition( - name: PlatformCookieManagerMethod.getCookies.name, - signature: 'Future> getCookies({required WebUri url})', - description: 'Gets all cookies for a URL.', - className: className, - ), - ApiMethodDefinition( - name: PlatformCookieManagerMethod.getCookie.name, - signature: - 'Future getCookie({required WebUri url, required String name})', - description: 'Gets a specific cookie.', - className: className, - ), - ApiMethodDefinition( - name: PlatformCookieManagerMethod.deleteCookie.name, - signature: - 'Future deleteCookie({required WebUri url, required String name, ...})', - description: 'Deletes a cookie.', - className: className, - ), - ApiMethodDefinition( - name: PlatformCookieManagerMethod.deleteCookies.name, - signature: - 'Future deleteCookies({required WebUri url, String? domain, String? path})', - description: 'Deletes cookies for a URL.', - className: className, - ), - ApiMethodDefinition( - name: PlatformCookieManagerMethod.deleteAllCookies.name, - signature: 'Future deleteAllCookies()', - description: 'Deletes all cookies.', - className: className, - ), - ApiMethodDefinition( - name: PlatformCookieManagerMethod.removeSessionCookies.name, - signature: 'Future removeSessionCookies()', - description: 'Removes all session cookies.', - className: className, - ), - ApiMethodDefinition( - name: PlatformCookieManagerMethod.flush.name, - signature: 'Future flush()', - description: 'Flushes cookies to persistent storage.', - className: className, - ), - ApiMethodDefinition( - name: PlatformCookieManagerMethod.getAllCookies.name, - signature: 'Future> getAllCookies()', - description: 'Gets all cookies.', - className: className, - ), - ], - ); - } - - static ApiClassDefinition _getWebStorageDefinition() { - final className = classNameOf(WebStorage); - return ApiClassDefinition( - className: className, - description: 'Manages ${LocalStorage} and ${SessionStorage}.', - isClassSupported: () => WebStorage.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: PlatformLocalStorageMethod.length.name, - signature: 'Future length()', - description: 'Gets the number of items.', - className: className, - ), - ApiMethodDefinition( - name: PlatformLocalStorageMethod.setItem.name, - signature: - 'Future setItem({required String key, required dynamic value})', - description: 'Sets an item.', - className: className, - ), - ApiMethodDefinition( - name: PlatformLocalStorageMethod.getItem.name, - signature: 'Future getItem({required String key})', - description: 'Gets an item.', - className: className, - ), - ApiMethodDefinition( - name: PlatformLocalStorageMethod.removeItem.name, - signature: 'Future removeItem({required String key})', - description: 'Removes an item.', - className: className, - ), - ApiMethodDefinition( - name: PlatformLocalStorageMethod.getItems.name, - signature: - 'Future> ${PlatformLocalStorageMethod.getItems.name}()', - description: 'Gets all items.', - className: className, - ), - ApiMethodDefinition( - name: PlatformLocalStorageMethod.clear.name, - signature: 'Future clear()', - description: 'Clears all items.', - className: className, - ), - ApiMethodDefinition( - name: PlatformLocalStorageMethod.key.name, - signature: 'Future key({required int index})', - description: 'Gets the key at an index.', - className: className, - ), - ], - ); - } - - static ApiClassDefinition _getFindInteractionControllerDefinition() { - final className = classNameOf(FindInteractionController); - return ApiClassDefinition( - className: className, - description: 'Controls find-in-page functionality.', - isClassSupported: () => FindInteractionController.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: PlatformFindInteractionControllerMethod.findAll.name, - signature: 'Future findAll({String? find})', - description: 'Finds all occurrences.', - className: className, - ), - ApiMethodDefinition( - name: PlatformFindInteractionControllerMethod.findNext.name, - signature: 'Future findNext({bool forward = true})', - description: 'Finds the next occurrence.', - className: className, - ), - ApiMethodDefinition( - name: PlatformFindInteractionControllerMethod.clearMatches.name, - signature: 'Future clearMatches()', - description: 'Clears all matches.', - className: className, - ), - ApiMethodDefinition( - name: PlatformFindInteractionControllerMethod.setSearchText.name, - signature: 'Future setSearchText(String? searchText)', - description: 'Sets the search text.', - className: className, - ), - ApiMethodDefinition( - name: PlatformFindInteractionControllerMethod.getSearchText.name, - signature: 'Future getSearchText()', - description: 'Gets the search text.', - className: className, - ), - ApiMethodDefinition( - name: PlatformFindInteractionControllerMethod - .isFindNavigatorVisible - .name, - signature: 'Future isFindNavigatorVisible()', - description: 'Checks if the find navigator is visible.', - className: className, - ), - ApiMethodDefinition( - name: - PlatformFindInteractionControllerMethod.presentFindNavigator.name, - signature: 'Future presentFindNavigator()', - description: 'Presents the find navigator.', - className: className, - ), - ApiMethodDefinition( - name: - PlatformFindInteractionControllerMethod.dismissFindNavigator.name, - signature: 'Future dismissFindNavigator()', - description: 'Dismisses the find navigator.', - className: className, - ), - ApiMethodDefinition( - name: - PlatformFindInteractionControllerMethod.getActiveFindSession.name, - signature: 'Future getActiveFindSession()', - description: 'Gets the active find session.', - className: className, - ), - ApiMethodDefinition( - name: PlatformFindInteractionControllerMethod.dispose.name, - signature: 'void dispose()', - description: 'Disposes the controller.', - className: className, - ), - ], - events: [ - ApiEventDefinition( - name: PlatformFindInteractionControllerCreationParamsProperty - .onFindResultReceived - .name, - description: 'Called when find results are received.', - className: className, - ), - ], - ); - } - - static ApiClassDefinition _getPullToRefreshControllerDefinition() { - final className = classNameOf(PullToRefreshController); - return ApiClassDefinition( - className: className, - description: 'Controls pull-to-refresh functionality.', - isClassSupported: () => PullToRefreshController.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: PlatformPullToRefreshControllerMethod.setEnabled.name, - signature: 'Future setEnabled(bool enabled)', - description: 'Enables or disables pull-to-refresh.', - className: className, - ), - ApiMethodDefinition( - name: PlatformPullToRefreshControllerMethod.isEnabled.name, - signature: 'Future isEnabled()', - description: 'Checks if pull-to-refresh is enabled.', - className: className, - ), - ApiMethodDefinition( - name: PlatformPullToRefreshControllerMethod.beginRefreshing.name, - signature: 'Future beginRefreshing()', - description: 'Starts the refresh animation.', - className: className, - ), - ApiMethodDefinition( - name: PlatformPullToRefreshControllerMethod.endRefreshing.name, - signature: 'Future endRefreshing()', - description: 'Stops the refresh animation.', - className: className, - ), - ApiMethodDefinition( - name: PlatformPullToRefreshControllerMethod.isRefreshing.name, - signature: 'Future isRefreshing()', - description: 'Checks if currently refreshing.', - className: className, - ), - ApiMethodDefinition( - name: PlatformPullToRefreshControllerMethod.setColor.name, - signature: 'Future setColor(Color color)', - description: 'Sets the indicator color.', - className: className, - ), - ApiMethodDefinition( - name: PlatformPullToRefreshControllerMethod.setBackgroundColor.name, - signature: 'Future setBackgroundColor(Color color)', - description: 'Sets the background color.', - className: className, - ), - ApiMethodDefinition( - name: PlatformPullToRefreshControllerMethod - .setDistanceToTriggerSync - .name, - signature: - 'Future setDistanceToTriggerSync(double distanceToTrigger)', - description: 'Sets the distance to trigger refresh.', - className: className, - ), - ApiMethodDefinition( - name: PlatformPullToRefreshControllerMethod.setSlingshotDistance.name, - signature: - 'Future setSlingshotDistance(double slingshotDistance)', - description: 'Sets the slingshot distance.', - className: className, - ), - ApiMethodDefinition( - name: PlatformPullToRefreshControllerMethod - .getDefaultSlingshotDistance - .name, - signature: 'Future getDefaultSlingshotDistance()', - description: 'Gets the default slingshot distance.', - className: className, - ), - ApiMethodDefinition( - name: PlatformPullToRefreshControllerMethod.setIndicatorSize.name, - signature: 'Future setIndicatorSize(PullToRefreshSize size)', - description: 'Sets the indicator size.', - className: className, - ), - ApiMethodDefinition( - name: PlatformPullToRefreshControllerMethod.dispose.name, - signature: 'void dispose()', - description: 'Disposes the controller.', - className: className, - ), - ], - events: [ - ApiEventDefinition( - name: PlatformPullToRefreshControllerCreationParamsProperty - .onRefresh - .name, - description: 'Called when a refresh is triggered.', - className: className, - ), - ], - ); - } - - static ApiClassDefinition _getPrintJobControllerDefinition() { - final className = classNameOf(PrintJobController); - return ApiClassDefinition( - className: className, - description: 'Controls print jobs.', - isClassSupported: () => PrintJobController.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: PlatformPrintJobControllerMethod.cancel.name, - signature: 'Future cancel()', - description: 'Cancels the print job.', - className: className, - ), - ApiMethodDefinition( - name: PlatformPrintJobControllerMethod.restart.name, - signature: 'Future restart()', - description: 'Restarts the print job.', - className: className, - ), - ApiMethodDefinition( - name: PlatformPrintJobControllerMethod.dismiss.name, - signature: 'Future dismiss({bool animated = true})', - description: 'Dismisses the print interface.', - className: className, - ), - ApiMethodDefinition( - name: PlatformPrintJobControllerMethod.getInfo.name, - signature: 'Future getInfo()', - description: 'Gets the print job info.', - className: className, - ), - ], - events: [ - ApiEventDefinition( - name: PlatformPrintJobControllerProperty.onComplete.name, - description: 'Called when the print job completes.', - className: className, - ), - ], - ); - } - - static ApiClassDefinition _getWebAuthenticationSessionDefinition() { - final className = classNameOf(WebAuthenticationSession); - return ApiClassDefinition( - className: className, - description: 'Handles web authentication sessions.', - isClassSupported: () => WebAuthenticationSession.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: PlatformWebAuthenticationSessionMethod.create.name, - signature: - 'static Future<${WebAuthenticationSession}> ${PlatformWebAuthenticationSessionMethod.create.name}({...})', - description: 'Creates a new authentication session.', - className: className, - isStatic: true, - ), - ApiMethodDefinition( - name: PlatformWebAuthenticationSessionMethod.canStart.name, - signature: 'Future canStart()', - description: 'Checks if the session can start.', - className: className, - ), - ApiMethodDefinition( - name: PlatformWebAuthenticationSessionMethod.start.name, - signature: 'Future start()', - description: 'Starts the authentication session.', - className: className, - ), - ApiMethodDefinition( - name: PlatformWebAuthenticationSessionMethod.cancel.name, - signature: 'Future cancel()', - description: 'Cancels the session.', - className: className, - ), - ApiMethodDefinition( - name: PlatformWebAuthenticationSessionMethod.dispose.name, - signature: 'Future dispose()', - description: 'Disposes the session.', - className: className, - ), - ApiMethodDefinition( - name: PlatformWebAuthenticationSessionMethod.isAvailable.name, - signature: 'static Future isAvailable()', - description: 'Checks if web authentication is available.', - className: className, - isStatic: true, - ), - ], - events: [ - ApiEventDefinition( - name: PlatformWebAuthenticationSessionProperty.onComplete.name, - description: 'Called when authentication completes.', - className: className, - ), - ], - ); - } - - static ApiClassDefinition _getServiceWorkerControllerDefinition() { - final className = classNameOf(ServiceWorkerController); - return ApiClassDefinition( - className: className, - description: 'Controls service workers.', - isClassSupported: () => ServiceWorkerController.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: - PlatformServiceWorkerControllerMethod.setServiceWorkerClient.name, - signature: - 'Future setServiceWorkerClient(ServiceWorkerClient? value)', - description: 'Sets the service worker client.', - className: className, - ), - ApiMethodDefinition( - name: - PlatformServiceWorkerControllerMethod.getAllowContentAccess.name, - signature: 'Future getAllowContentAccess()', - description: 'Gets allow content access setting.', - className: className, - ), - ApiMethodDefinition( - name: - PlatformServiceWorkerControllerMethod.setAllowContentAccess.name, - signature: 'Future setAllowContentAccess(bool allow)', - description: 'Sets allow content access setting.', - className: className, - ), - ApiMethodDefinition( - name: PlatformServiceWorkerControllerMethod.getAllowFileAccess.name, - signature: 'Future getAllowFileAccess()', - description: 'Gets allow file access setting.', - className: className, - ), - ApiMethodDefinition( - name: PlatformServiceWorkerControllerMethod.setAllowFileAccess.name, - signature: 'Future setAllowFileAccess(bool allow)', - description: 'Sets allow file access setting.', - className: className, - ), - ApiMethodDefinition( - name: PlatformServiceWorkerControllerMethod.getBlockNetworkLoads.name, - signature: 'Future getBlockNetworkLoads()', - description: 'Gets block network loads setting.', - className: className, - ), - ApiMethodDefinition( - name: PlatformServiceWorkerControllerMethod.setBlockNetworkLoads.name, - signature: 'Future setBlockNetworkLoads(bool block)', - description: 'Sets block network loads setting.', - className: className, - ), - ], - events: [ - ApiEventDefinition( - name: ServiceWorkerClientProperty.shouldInterceptRequest.name, - description: 'Called to intercept service worker requests.', - className: className, - ), - ], - ); - } - - static ApiClassDefinition _getProxyControllerDefinition() { - final className = classNameOf(ProxyController); - return ApiClassDefinition( - className: className, - description: 'Controls proxy settings.', - isClassSupported: () => ProxyController.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: PlatformProxyControllerMethod.setProxyOverride.name, - signature: - 'Future setProxyOverride({required ProxySettings settings})', - description: 'Sets the proxy override.', - className: className, - ), - ApiMethodDefinition( - name: PlatformProxyControllerMethod.clearProxyOverride.name, - signature: 'Future clearProxyOverride()', - description: 'Clears the proxy override.', - className: className, - ), - ], - ); - } - - static ApiClassDefinition _getTracingControllerDefinition() { - final className = classNameOf(TracingController); - return ApiClassDefinition( - className: className, - description: 'Controls tracing.', - isClassSupported: () => TracingController.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: PlatformTracingControllerMethod.start.name, - signature: 'Future start({required TracingSettings settings})', - description: 'Starts tracing.', - className: className, - ), - ApiMethodDefinition( - name: PlatformTracingControllerMethod.stop.name, - signature: 'Future stop({String? filePath})', - description: 'Stops tracing.', - className: className, - ), - ApiMethodDefinition( - name: PlatformTracingControllerMethod.isTracing.name, - signature: 'Future isTracing()', - description: 'Checks if tracing is active.', - className: className, - ), - ], - ); - } - - static ApiClassDefinition _getHttpAuthCredentialDatabaseDefinition() { - final className = classNameOf(HttpAuthCredentialDatabase); - return ApiClassDefinition( - className: className, - description: 'Manages HTTP authentication credentials.', - isClassSupported: () => HttpAuthCredentialDatabase.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: PlatformHttpAuthCredentialDatabaseMethod - .getAllAuthCredentials - .name, - signature: - 'Future> getAllAuthCredentials()', - description: 'Gets all stored credentials.', - className: className, - ), - ApiMethodDefinition( - name: PlatformHttpAuthCredentialDatabaseMethod - .getHttpAuthCredentials - .name, - signature: - 'Future> getHttpAuthCredentials({...})', - description: 'Gets credentials for a protection space.', - className: className, - ), - ApiMethodDefinition( - name: PlatformHttpAuthCredentialDatabaseMethod - .setHttpAuthCredential - .name, - signature: 'Future setHttpAuthCredential({...})', - description: 'Sets a credential.', - className: className, - ), - ApiMethodDefinition( - name: PlatformHttpAuthCredentialDatabaseMethod - .removeHttpAuthCredential - .name, - signature: 'Future removeHttpAuthCredential({...})', - description: 'Removes a credential.', - className: className, - ), - ApiMethodDefinition( - name: PlatformHttpAuthCredentialDatabaseMethod - .removeHttpAuthCredentials - .name, - signature: 'Future removeHttpAuthCredentials({...})', - description: 'Removes all credentials for a protection space.', - className: className, - ), - ApiMethodDefinition( - name: PlatformHttpAuthCredentialDatabaseMethod - .clearAllAuthCredentials - .name, - signature: 'Future clearAllAuthCredentials()', - description: 'Clears all credentials.', - className: className, - ), - ], - ); - } - - static ApiClassDefinition _getWebViewEnvironmentDefinition() { - final className = classNameOf(WebViewEnvironment); - return ApiClassDefinition( - className: className, - description: 'WebView2 environment for Windows.', - isClassSupported: () => WebViewEnvironment.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: PlatformWebViewEnvironmentMethod.create.name, - signature: - 'static Future<${WebViewEnvironment}> ${PlatformWebViewEnvironmentMethod.create.name}({...})', - description: 'Creates a WebView environment.', - className: className, - isStatic: true, - ), - ApiMethodDefinition( - name: PlatformWebViewEnvironmentMethod.getAvailableVersion.name, - signature: - 'static Future getAvailableVersion({String? browserExecutableFolder})', - description: 'Gets the available WebView2 version.', - className: className, - isStatic: true, - ), - ApiMethodDefinition( - name: PlatformWebViewEnvironmentMethod.getProcessInfos.name, - signature: 'Future> getProcessInfos()', - description: 'Gets running process information.', - className: className, - ), - ApiMethodDefinition( - name: PlatformWebViewEnvironmentMethod.compareBrowserVersions.name, - signature: 'static Future compareBrowserVersions({...})', - description: 'Compares browser versions.', - className: className, - isStatic: true, - ), - ApiMethodDefinition( - name: PlatformWebViewEnvironmentMethod.dispose.name, - signature: 'Future dispose()', - description: 'Disposes the environment.', - className: className, - ), - ], - events: [ - ApiEventDefinition( - name: PlatformWebViewEnvironmentProperty.onBrowserProcessExited.name, - description: 'Called when the browser process exits.', - className: className, - ), - ApiEventDefinition( - name: PlatformWebViewEnvironmentProperty.onProcessInfosChanged.name, - description: 'Called when process info changes.', - className: className, - ), - ApiEventDefinition( - name: PlatformWebViewEnvironmentProperty - .onNewBrowserVersionAvailable - .name, - description: 'Called when a new browser version is available.', - className: className, - ), - ], - ); - } - - static ApiClassDefinition _getProcessGlobalConfigDefinition() { - final className = classNameOf(ProcessGlobalConfig); - return ApiClassDefinition( - className: className, - description: 'Global process configuration for Android.', - isClassSupported: () => ProcessGlobalConfig.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: PlatformProcessGlobalConfigMethod.apply.name, - signature: - 'Future ${PlatformProcessGlobalConfigMethod.apply.name}({required ${ProcessGlobalConfigSettings} settings})', - description: 'Applies global configuration settings.', - className: className, - ), - ], - ); - } - - static ApiClassDefinition _getWebMessageChannelDefinition() { - final className = classNameOf(WebMessageChannel); - return ApiClassDefinition( - className: className, - description: 'HTML5 message channel for two-way communication.', - isClassSupported: () => WebMessageChannel.isClassSupported(), - methods: [ - ApiMethodDefinition( - name: PlatformWebMessageChannelMethod.dispose.name, - signature: 'void dispose()', - description: 'Disposes the channel.', - className: className, - ), - ], - ); - } -} diff --git a/flutter_inappwebview/example/lib/utils/test_registry.dart b/flutter_inappwebview/example/lib/utils/test_registry.dart deleted file mode 100644 index 82184f7e1b..0000000000 --- a/flutter_inappwebview/example/lib/utils/test_registry.dart +++ /dev/null @@ -1,466 +0,0 @@ -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import '../models/test_case.dart'; -import '../models/test_result.dart'; -import '../utils/constants.dart'; -import '../utils/support_checker.dart'; - -/// Central registry for all test cases in the testing interface. -class TestRegistry { - static final Map> _testsByCategory = {}; - - /// Registers a test case in the registry. - static void register(TestCase testCase) { - _testsByCategory.putIfAbsent(testCase.category, () => []); - _testsByCategory[testCase.category]!.add(testCase); - } - - /// Retrieves all tests for a given category. - static List getTestsByCategory(TestCategory category) { - return List.unmodifiable(_testsByCategory[category] ?? []); - } - - /// Retrieves all registered tests across all categories. - static List getAllTests() { - final allTests = []; - for (final tests in _testsByCategory.values) { - allTests.addAll(tests); - } - return List.unmodifiable(allTests); - } - - /// Retrieves a specific test by its ID. - static TestCase? getTestById(String id) { - for (final tests in _testsByCategory.values) { - try { - return tests.firstWhere((test) => test.id == id); - } catch (e) { - continue; - } - } - return null; - } - - /// Clears all registered tests (useful for testing). - static void clear() { - _testsByCategory.clear(); - } - - /// Initializes the registry with sample test cases. - static void init() { - clear(); - - // Navigation Tests - register( - TestCase( - id: 'nav_load_url', - title: 'Load URL', - description: 'Load a URL in the WebView', - category: TestCategory.navigation, - complexity: TestComplexity.quick, - supportedPlatforms: _getPlatformsForMethod( - PlatformInAppWebViewControllerMethod.loadUrl.name, - ), - execute: () async { - try { - // This would be called with an actual controller in real scenario - return TestResult( - passed: true, - message: 'URL loaded successfully', - duration: const Duration(milliseconds: 100), - ); - } catch (e) { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: false, - message: 'Failed: ${e.toString()}', - ); - } - }, - ), - ); - - register( - TestCase( - id: 'nav_get_url', - title: 'Get Current URL', - description: 'Retrieve the current URL from the WebView', - category: TestCategory.navigation, - complexity: TestComplexity.quick, - supportedPlatforms: _getPlatformsForMethod( - PlatformInAppWebViewControllerMethod.getUrl.name, - ), - execute: () async { - try { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: true, - message: 'Current URL retrieved', - ); - } catch (e) { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: false, - message: 'Failed: ${e.toString()}', - ); - } - }, - ), - ); - - register( - TestCase( - id: 'nav_go_back', - title: 'Go Back', - description: 'Navigate back in WebView history', - category: TestCategory.navigation, - complexity: TestComplexity.quick, - supportedPlatforms: _getPlatformsForMethod( - PlatformInAppWebViewControllerMethod.goBack.name, - ), - execute: () async { - try { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: true, - message: 'Navigated back successfully', - ); - } catch (e) { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: false, - message: 'Failed: ${e.toString()}', - ); - } - }, - ), - ); - - register( - TestCase( - id: 'nav_reload', - title: 'Reload Page', - description: 'Reload the current page', - category: TestCategory.navigation, - complexity: TestComplexity.quick, - supportedPlatforms: _getPlatformsForMethod( - PlatformInAppWebViewControllerMethod.reload.name, - ), - execute: () async { - try { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: true, - message: 'URL loaded successfully', - ); - } catch (e) { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: false, - message: 'Failed: ${e.toString()}', - ); - } - }, - ), - ); - - // JavaScript Tests - register( - TestCase( - id: 'js_evaluate', - title: 'Evaluate JavaScript', - description: 'Execute JavaScript code and retrieve result', - category: TestCategory.javascript, - complexity: TestComplexity.quick, - supportedPlatforms: _getPlatformsForMethod( - PlatformInAppWebViewControllerMethod.evaluateJavascript.name, - ), - execute: () async { - try { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: true, - message: 'JavaScript evaluated: 1 + 1 = 2', - ); - } catch (e) { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: false, - message: 'Failed: ${e.toString()}', - ); - } - }, - ), - ); - - register( - TestCase( - id: 'js_handler', - title: 'JavaScript Handler', - description: 'Add and test JavaScript message handler', - category: TestCategory.javascript, - complexity: TestComplexity.medium, - supportedPlatforms: _getPlatformsForMethod( - PlatformInAppWebViewControllerMethod.addJavaScriptHandler.name, - ), - execute: () async { - try { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: true, - message: 'Handler added successfully', - ); - } catch (e) { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: false, - message: 'Failed: ${e.toString()}', - ); - } - }, - ), - ); - - // Content Tests - register( - TestCase( - id: 'content_get_title', - title: 'Get Page Title', - description: 'Retrieve the title of the current page', - category: TestCategory.content, - complexity: TestComplexity.quick, - supportedPlatforms: _getPlatformsForMethod( - PlatformInAppWebViewControllerMethod.getTitle.name, - ), - execute: () async { - try { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: true, - message: 'Page title retrieved', - ); - } catch (e) { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: false, - message: 'Failed: ${e.toString()}', - ); - } - }, - ), - ); - - register( - TestCase( - id: 'content_get_html', - title: 'Get HTML Content', - description: 'Retrieve the HTML content of the current page', - category: TestCategory.content, - complexity: TestComplexity.medium, - supportedPlatforms: _getPlatformsForMethod( - PlatformInAppWebViewControllerMethod.getHtml.name, - ), - execute: () async { - try { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: true, - message: 'HTML content retrieved', - ); - } catch (e) { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: false, - message: 'Failed: ${e.toString()}', - ); - } - }, - ), - ); - - // Storage Tests - register( - TestCase( - id: 'storage_set_cookie', - title: 'Set Cookie', - description: 'Set a cookie for a URL', - category: TestCategory.storage, - complexity: TestComplexity.quick, - supportedPlatforms: _getPlatformsForClass(CookieManager), - execute: () async { - try { - await CookieManager.instance().setCookie( - url: WebUri('https://flutter.dev'), - name: 'test_cookie', - value: 'test_value', - ); - return TestResult( - duration: const Duration(milliseconds: 100), - passed: true, - message: 'Cookie set successfully', - ); - } catch (e) { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: false, - message: 'Failed: ${e.toString()}', - ); - } - }, - ), - ); - - register( - TestCase( - id: 'storage_get_cookies', - title: 'Get Cookies', - description: 'Retrieve cookies for a URL', - category: TestCategory.storage, - complexity: TestComplexity.quick, - supportedPlatforms: _getPlatformsForClass(CookieManager), - execute: () async { - try { - final cookies = await CookieManager.instance().getCookies( - url: WebUri('https://flutter.dev'), - ); - return TestResult( - duration: const Duration(milliseconds: 100), - passed: true, - message: 'Retrieved ${cookies.length} cookies', - ); - } catch (e) { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: false, - message: 'Failed: ${e.toString()}', - ); - } - }, - ), - ); - - // Advanced Tests - register( - TestCase( - id: 'advanced_screenshot', - title: 'Take Screenshot', - description: 'Capture a screenshot of the WebView', - category: TestCategory.advanced, - complexity: TestComplexity.medium, - supportedPlatforms: _getPlatformsForMethod( - PlatformInAppWebViewControllerMethod.takeScreenshot.name, - ), - execute: () async { - try { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: true, - message: 'Screenshot captured', - ); - } catch (e) { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: false, - message: 'Failed: ${e.toString()}', - ); - } - }, - ), - ); - - register( - TestCase( - id: 'advanced_print', - title: 'Print Page', - description: 'Print the current page', - category: TestCategory.advanced, - complexity: TestComplexity.long, - supportedPlatforms: _getPlatformsForMethod( - PlatformInAppWebViewControllerMethod.printCurrentPage.name, - ), - execute: () async { - try { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: true, - message: 'Print initiated', - ); - } catch (e) { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: false, - message: 'Failed: ${e.toString()}', - ); - } - }, - ), - ); - - // Browser Tests - register( - TestCase( - id: 'browser_open_inapp', - title: 'Open ${InAppBrowser}', - description: 'Open URL in ${InAppBrowser}', - category: TestCategory.browsers, - complexity: TestComplexity.medium, - supportedPlatforms: _getPlatformsForClass(InAppBrowser), - execute: () async { - try { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: true, - message: '${InAppBrowser} opened', - ); - } catch (e) { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: false, - message: 'Failed: ${e.toString()}', - ); - } - }, - ), - ); - - register( - TestCase( - id: 'browser_chrome_safari', - title: 'Open Chrome/Safari Browser', - description: 'Open URL in ${ChromeSafariBrowser}', - category: TestCategory.browsers, - complexity: TestComplexity.medium, - supportedPlatforms: _getPlatformsForClass(ChromeSafariBrowser), - execute: () async { - try { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: true, - message: 'Browser opened', - ); - } catch (e) { - return TestResult( - duration: const Duration(milliseconds: 100), - passed: false, - message: 'Failed: ${e.toString()}', - ); - } - }, - ), - ); - } - - /// Helper to get supported platforms for a method. - static List _getPlatformsForMethod(String methodName) { - return SupportChecker.getSupportedPlatformsForMethod( - SupportChecker.classNameOf(InAppWebViewController), - methodName, - ).map((p) => p.name).toList(); - } - - /// Helper to get supported platforms for a class. - static List _getPlatformsForClass(Type classType) { - return SupportChecker.getSupportedPlatformsForClass( - SupportChecker.classNameOf(classType), - ).map((p) => p.name).toList(); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/common/app_drawer.dart b/flutter_inappwebview/example/lib/widgets/common/app_drawer.dart deleted file mode 100644 index bc80f87e40..0000000000 --- a/flutter_inappwebview/example/lib/widgets/common/app_drawer.dart +++ /dev/null @@ -1,103 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/models/navigation_section.dart'; -import 'package:flutter_inappwebview_example/utils/responsive_utils.dart'; -import 'package:pointer_interceptor/pointer_interceptor.dart'; - -class AppDrawer extends StatelessWidget { - AppDrawer({super.key, List? sections}) - : sections = sections ?? defaultNavigationSections; - - final List sections; - - @override - Widget build(BuildContext context) { - final isMobile = context.isMobile; - return PointerInterceptor( - child: Drawer( - child: ListView( - padding: EdgeInsets.zero, - children: _buildChildren(context, isMobile), - ), - ), - ); - } - - List _buildChildren(BuildContext context, bool isMobile) { - final headerTitleSize = isMobile ? 22.0 : 24.0; - final headerSubtitleSize = isMobile ? 12.0 : 14.0; - final sectionTitleSize = isMobile ? 11.0 : 12.0; - final itemTitleSize = isMobile ? 13.0 : 14.0; - final tilePadding = EdgeInsets.symmetric(horizontal: 16); - final tileVerticalPadding = 8.0; - final children = [ - DrawerHeader( - decoration: const BoxDecoration(color: Colors.blue), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - '$InAppWebView', - style: TextStyle( - color: Colors.white, - fontSize: headerTitleSize, - fontWeight: FontWeight.bold, - ), - ), - Text( - 'Test Suite', - style: TextStyle( - color: Colors.white70, - fontSize: headerSubtitleSize, - ), - ), - ], - ), - ), - ]; - - for (var i = 0; i < sections.length; i++) { - final section = sections[i]; - if (i > 0) { - children.add(const Divider()); - } - if (section.title != null) { - children.add( - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - child: Text( - section.title!, - style: TextStyle( - color: Colors.grey.shade600, - fontSize: sectionTitleSize, - fontWeight: FontWeight.bold, - ), - ), - ), - ); - } - for (final item in section.items) { - children.add( - ListTile( - contentPadding: tilePadding, - minVerticalPadding: tileVerticalPadding, - title: Text(item.title, style: TextStyle(fontSize: itemTitleSize)), - leading: Icon(item.icon), - onTap: () => _navigateTo(context, item), - ), - ); - } - } - - return children; - } - - void _navigateTo(BuildContext context, NavigationItem item) { - if (item.useReplacement) { - Navigator.pushReplacementNamed(context, item.routeName); - return; - } - Navigator.pushNamed(context, item.routeName); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/common/appbar_loading_indicator.dart b/flutter_inappwebview/example/lib/widgets/common/appbar_loading_indicator.dart deleted file mode 100644 index 4268b8baf2..0000000000 --- a/flutter_inappwebview/example/lib/widgets/common/appbar_loading_indicator.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:flutter/material.dart'; - -/// An AppBar loading indicator for use in the actions section. -/// -/// Shows a small circular progress indicator when loading is true, -/// otherwise shows nothing. -class AppBarLoadingIndicator extends StatelessWidget { - /// Whether to show the loading indicator. - final bool isLoading; - - const AppBarLoadingIndicator({super.key, required this.isLoading}); - - @override - Widget build(BuildContext context) { - if (!isLoading) return const SizedBox.shrink(); - - return const Padding( - padding: EdgeInsets.all(16), - child: SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white), - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/common/empty_state.dart b/flutter_inappwebview/example/lib/widgets/common/empty_state.dart deleted file mode 100644 index fbdfd16935..0000000000 --- a/flutter_inappwebview/example/lib/widgets/common/empty_state.dart +++ /dev/null @@ -1,103 +0,0 @@ -import 'package:flutter/material.dart'; - -/// A widget displaying an empty state with an icon, title, and description. -/// -/// Used across multiple screens (CookieManagerScreen, HttpAuthScreen, -/// WebStorageScreen, CategoryScreen) to provide consistent empty state UI. -class EmptyState extends StatelessWidget { - /// The icon to display at the top of the empty state. - final IconData icon; - - /// The main title text. - final String title; - - /// An optional description providing additional context. - final String? description; - - /// The size of the icon. - final double iconSize; - - /// Optional action button to display below the description. - final Widget? action; - - const EmptyState({ - super.key, - required this.icon, - required this.title, - this.description, - this.iconSize = 64, - this.action, - }); - - @override - Widget build(BuildContext context) { - return Center( - child: Padding( - padding: const EdgeInsets.all(32), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(icon, size: iconSize, color: Colors.grey.shade400), - const SizedBox(height: 16), - Text( - title, - textAlign: TextAlign.center, - style: TextStyle(fontSize: 16, color: Colors.grey.shade600), - ), - if (description != null) ...[ - const SizedBox(height: 8), - Text( - description!, - textAlign: TextAlign.center, - style: TextStyle(fontSize: 12, color: Colors.grey.shade500), - ), - ], - if (action != null) ...[const SizedBox(height: 16), action!], - ], - ), - ), - ); - } -} - -/// An empty state wrapped in a Card. -/// -/// Useful when the empty state needs to be displayed within a card-based layout. -class EmptyStateCard extends StatelessWidget { - /// The icon to display at the top of the empty state. - final IconData icon; - - /// The main title text. - final String title; - - /// An optional description providing additional context. - final String? description; - - /// The size of the icon. - final double iconSize; - - /// Optional action button to display below the description. - final Widget? action; - - const EmptyStateCard({ - super.key, - required this.icon, - required this.title, - this.description, - this.iconSize = 64, - this.action, - }); - - @override - Widget build(BuildContext context) { - return Card( - child: EmptyState( - icon: icon, - title: title, - description: description, - iconSize: iconSize, - action: action, - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/common/event_log_card.dart b/flutter_inappwebview/example/lib/widgets/common/event_log_card.dart deleted file mode 100644 index 6dc8ae65f6..0000000000 --- a/flutter_inappwebview/example/lib/widgets/common/event_log_card.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; - -/// A card displaying a scrollable event log. -/// -/// Used in screens like ControllersScreen, InAppBrowserScreen, and WebViewTesterScreen -/// to display a log of recent events. -class EventLogCard extends StatelessWidget { - /// Maximum number of events to display. - final int maxEvents; - - /// Height of the event log container. - final double height; - - /// Optional title for the card. Defaults to 'Event Log'. - final String title; - - const EventLogCard({ - super.key, - this.maxEvents = 15, - this.height = 150, - this.title = 'Event Log', - }); - - @override - Widget build(BuildContext context) { - return Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - title, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - TextButton( - onPressed: () => context.read().clear(), - child: const Text('Clear'), - ), - ], - ), - const SizedBox(height: 8), - Consumer( - builder: (context, provider, _) { - final events = provider.events.reversed - .take(maxEvents) - .toList(); - if (events.isEmpty) { - return Container( - padding: const EdgeInsets.all(16), - child: const Center( - child: Text( - 'No events yet', - style: TextStyle(color: Colors.grey), - ), - ), - ); - } - return Container( - height: height, - decoration: BoxDecoration( - color: Colors.grey.shade100, - borderRadius: BorderRadius.circular(8), - ), - child: ListView.builder( - itemCount: events.length, - itemBuilder: (context, index) { - final event = events[index]; - return ListTile( - dense: true, - title: Text( - event.message, - style: const TextStyle(fontSize: 12), - ), - subtitle: Text( - event.data?.toString() ?? '', - style: TextStyle( - fontSize: 10, - color: Colors.grey.shade600, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - leading: Text( - '${event.timestamp.hour}:${event.timestamp.minute.toString().padLeft(2, '0')}:${event.timestamp.second.toString().padLeft(2, '0')}', - style: TextStyle( - fontSize: 10, - color: Colors.grey.shade500, - ), - ), - ); - }, - ), - ); - }, - ), - ], - ), - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/common/method_card.dart b/flutter_inappwebview/example/lib/widgets/common/method_card.dart deleted file mode 100644 index 4fd5684bec..0000000000 --- a/flutter_inappwebview/example/lib/widgets/common/method_card.dart +++ /dev/null @@ -1,261 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; -import 'package:flutter_inappwebview_example/utils/responsive_utils.dart'; -import 'package:flutter_inappwebview_example/widgets/common/support_badge.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_result_history.dart'; - -/// A card displaying a method with its description, platform support badges, -/// result history, and a run button. -/// -/// Used across multiple screens (CookieManagerScreen, HttpAuthScreen, -/// WebStorageScreen, InAppBrowserScreen, etc.) to provide a consistent -/// method testing UI. -class MethodCard extends StatelessWidget { - /// The name of the method to display. - final String methodName; - - /// A description of what the method does. - final String description; - - /// The set of platforms that support this method. - /// If null or empty, no support badges are shown. - final Set? supportedPlatforms; - - /// The result history entries to display. - final List? historyEntries; - - /// The currently selected history index. - final int? selectedHistoryIndex; - - /// Called when the user selects a history entry. - final ValueChanged? onHistorySelected; - - /// Called when the run button is pressed. If null, the button is disabled. - final VoidCallback? onRun; - - /// Whether to show a loading state on the run button. - final bool isLoading; - - /// Optional trailing widget to use instead of the default run button. - final Widget? trailing; - - /// Optional title to use for the history section. - final String? historyTitle; - - /// Optional leading widget (e.g., check icon for selected state). - final Widget? leading; - - /// Optional background color for the card. - final Color? backgroundColor; - - /// Optional extra content to display below the main content. - /// Useful for parameter configuration sections. - final Widget? extraContent; - - /// Whether to hide the trailing widget entirely. - final bool hideTrailing; - - const MethodCard({ - super.key, - required this.methodName, - required this.description, - this.supportedPlatforms, - this.historyEntries, - this.selectedHistoryIndex, - this.onHistorySelected, - this.onRun, - this.isLoading = false, - this.trailing, - this.historyTitle, - this.leading, - this.backgroundColor, - this.extraContent, - this.hideTrailing = false, - }); - - @override - Widget build(BuildContext context) { - final isMobile = context.isMobile; - final entries = historyEntries ?? const []; - final platforms = supportedPlatforms ?? const {}; - final buttonStyle = isMobile - ? ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - minimumSize: const Size(0, 40), - textStyle: const TextStyle( - inherit: false, - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ) - : null; - - Widget? trailingWidget; - if (!hideTrailing) { - trailingWidget = - trailing ?? - ElevatedButton( - key: const Key('method-card-run-button'), - style: buttonStyle, - onPressed: !isLoading ? onRun : null, - child: const Text('Run'), - ); - } - - return Card( - margin: const EdgeInsets.only(bottom: 8), - color: backgroundColor, - child: ListTile( - contentPadding: EdgeInsets.symmetric( - horizontal: isMobile ? 12 : 16, - vertical: isMobile ? 6 : 8, - ), - leading: leading, - title: Text( - methodName, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: isMobile ? 13 : 14, - ), - ), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - description, - style: TextStyle( - fontSize: isMobile ? 11 : 12, - color: Colors.grey.shade600, - ), - ), - if (platforms.isNotEmpty) ...[ - const SizedBox(height: 6), - SupportBadgesRow(supportedPlatforms: platforms, compact: true), - ], - if (entries.isNotEmpty) ...[ - const SizedBox(height: 6), - MethodResultHistory( - entries: entries, - selectedIndex: selectedHistoryIndex, - title: historyTitle ?? methodName, - onSelected: onHistorySelected, - ), - ], - if (extraContent != null) ...[const Divider(), extraContent!], - ], - ), - trailing: trailingWidget, - ), - ); - } -} - -/// A denser method tile for use in grouped method sections. -/// -/// Similar to [MethodCard] but with a denser layout suitable for -/// embedding in card sections like "Open Methods", "Control Methods", etc. -class MethodTile extends StatelessWidget { - /// The name of the method to display. - final String methodName; - - /// A description of what the method does. - final String description; - - /// The set of platforms that support this method. - final Set supportedPlatforms; - - /// The result history entries to display. - final List? historyEntries; - - /// The currently selected history index. - final int? selectedHistoryIndex; - - /// Called when the user selects a history entry. - final ValueChanged? onHistorySelected; - - /// Called when the run button is pressed. If null, the button is disabled. - final VoidCallback? onRun; - - /// Whether to show a loading state on the run button. - final bool isLoading; - - /// Optional title to use for the history section. - final String? historyTitle; - - const MethodTile({ - super.key, - required this.methodName, - required this.description, - required this.supportedPlatforms, - this.historyEntries, - this.selectedHistoryIndex, - this.onHistorySelected, - this.onRun, - this.isLoading = false, - this.historyTitle, - }); - - @override - Widget build(BuildContext context) { - final isMobile = context.isMobile; - final entries = historyEntries ?? const []; - final buttonStyle = isMobile - ? ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - minimumSize: const Size(0, 40), - textStyle: const TextStyle( - inherit: false, - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ) - : null; - return Card( - margin: const EdgeInsets.only(bottom: 8), - child: ListTile( - contentPadding: EdgeInsets.symmetric( - horizontal: isMobile ? 12 : 16, - vertical: isMobile ? 6 : 8, - ), - title: Text( - methodName, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: isMobile ? 13 : 14, - ), - ), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - description, - style: TextStyle( - fontSize: isMobile ? 11 : 12, - color: Colors.grey.shade600, - ), - ), - const SizedBox(height: 6), - SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - if (entries.isNotEmpty) ...[ - const SizedBox(height: 6), - MethodResultHistory( - entries: entries, - selectedIndex: selectedHistoryIndex, - title: historyTitle ?? methodName, - onSelected: onHistorySelected, - ), - ], - ], - ), - trailing: ElevatedButton( - style: buttonStyle, - onPressed: !isLoading ? onRun : null, - child: const Text('Run'), - ), - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/common/method_result_history.dart b/flutter_inappwebview/example/lib/widgets/common/method_result_history.dart deleted file mode 100644 index ee9f27ca6c..0000000000 --- a/flutter_inappwebview/example/lib/widgets/common/method_result_history.dart +++ /dev/null @@ -1,283 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; - -class MethodResultEntry { - final String message; - final bool isError; - final DateTime timestamp; - final dynamic value; - - const MethodResultEntry({ - required this.message, - required this.isError, - required this.timestamp, - this.value, - }); - - /// Returns the copyable string representation of the result value. - /// Attempts toMap()/toJson() conversion first, then JSON encoding, falls back to toString(). - String get copyableValue { - if (value == null) return message; - - // Try to convert to serializable form first - final serializable = _toSerializable(value); - - try { - return const JsonEncoder.withIndent(' ').convert(serializable); - } catch (_) { - return serializable.toString(); - } - } - - /// Converts a value to a JSON-serializable form. - /// Handles objects with toMap() or toJson() methods, Lists, Maps, and primitives. - static dynamic _toSerializable(dynamic value) { - if (value == null) return null; - if (value is String || value is num || value is bool) return value; - - // Handle List recursively - if (value is List) { - return value.map(_toSerializable).toList(); - } - - // Handle Map recursively - if (value is Map) { - return value.map((k, v) => MapEntry(k.toString(), _toSerializable(v))); - } - - // Try toMap() - common in flutter_inappwebview objects - try { - final result = (value as dynamic).toMap?.call(); - if (result is Map) { - return _toSerializable(result); - } - } catch (_) {} - - // Try toJson() - common in many Flutter/Dart packages - try { - final result = (value as dynamic).toJson?.call(); - if (result is Map) { - return _toSerializable(result); - } - } catch (_) {} - - // Fallback to toString() - return value.toString(); - } -} - -class MethodResultHistory extends StatefulWidget { - const MethodResultHistory({ - super.key, - required this.entries, - this.selectedIndex, - this.onSelected, - this.maxEntries = 3, - this.title, - this.copyTooltip = 'Copy result', - this.emptyLabel, - this.initiallyExpanded = false, - }); - - final List entries; - final int? selectedIndex; - final ValueChanged? onSelected; - final int maxEntries; - final String? title; - final String copyTooltip; - final String? emptyLabel; - final bool initiallyExpanded; - - @override - State createState() => _MethodResultHistoryState(); -} - -class _MethodResultHistoryState extends State { - late bool _isExpanded; - late int _localSelectedIndex; - - @override - void initState() { - super.initState(); - _isExpanded = widget.initiallyExpanded; - _localSelectedIndex = widget.selectedIndex ?? 0; - } - - @override - Widget build(BuildContext context) { - if (widget.entries.isEmpty) { - if (widget.emptyLabel == null) { - return const SizedBox.shrink(); - } - return Padding( - padding: const EdgeInsets.only(top: 4), - child: Text( - widget.emptyLabel!, - style: TextStyle(fontSize: 11, color: Colors.grey.shade600), - ), - ); - } - - final visibleEntries = widget.entries.take(widget.maxEntries).toList(); - final effectiveSelectedIndex = - widget.selectedIndex != null && - widget.selectedIndex! < visibleEntries.length - ? widget.selectedIndex! - : (_localSelectedIndex < visibleEntries.length - ? _localSelectedIndex - : 0); - final selectedEntry = visibleEntries[effectiveSelectedIndex]; - final latestEntry = visibleEntries.first; - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - InkWell( - onTap: () => setState(() => _isExpanded = !_isExpanded), - borderRadius: BorderRadius.circular(4), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: Row( - children: [ - Icon( - _isExpanded - ? Icons.keyboard_arrow_down - : Icons.keyboard_arrow_right, - size: 18, - color: Colors.grey.shade600, - ), - const SizedBox(width: 4), - Text( - widget.title ?? 'History', - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - const SizedBox(width: 8), - // Show latest result status icon when collapsed - if (!_isExpanded) ...[ - Icon( - latestEntry.isError - ? Icons.error_outline - : Icons.check_circle, - size: 14, - color: latestEntry.isError ? Colors.red : Colors.green, - ), - const SizedBox(width: 4), - Expanded( - child: Text( - latestEntry.message, - style: TextStyle( - fontSize: 11, - fontFamily: 'monospace', - color: latestEntry.isError - ? Colors.red.shade800 - : Colors.green.shade800, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - ] else ...[ - const Spacer(), - ], - IconButton( - key: const Key('method-history-copy'), - icon: const Icon(Icons.content_copy, size: 16), - tooltip: widget.copyTooltip, - constraints: const BoxConstraints( - minWidth: 32, - minHeight: 32, - ), - padding: EdgeInsets.zero, - onPressed: () { - Clipboard.setData( - ClipboardData(text: selectedEntry.copyableValue), - ); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Result copied to clipboard'), - duration: Duration(seconds: 1), - ), - ); - }, - ), - ], - ), - ), - ), - if (_isExpanded) ...[ - const SizedBox(height: 4), - for (var index = 0; index < visibleEntries.length; index++) - _HistoryEntryTile( - key: Key('method-history-entry-$index'), - entry: visibleEntries[index], - isSelected: index == effectiveSelectedIndex, - onTap: widget.onSelected == null - ? () => setState(() => _localSelectedIndex = index) - : () => widget.onSelected!(index), - ), - ], - ], - ); - } -} - -class _HistoryEntryTile extends StatelessWidget { - const _HistoryEntryTile({ - super.key, - required this.entry, - required this.isSelected, - this.onTap, - }); - - final MethodResultEntry entry; - final bool isSelected; - final VoidCallback? onTap; - - @override - Widget build(BuildContext context) { - final baseColor = entry.isError ? Colors.red : Colors.green; - final borderColor = isSelected ? baseColor : Colors.grey.shade300; - final backgroundColor = isSelected - ? baseColor.withOpacity(0.1) - : Colors.grey.shade100; - - return InkWell( - onTap: onTap, - child: Container( - margin: const EdgeInsets.only(bottom: 6), - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6), - decoration: BoxDecoration( - color: backgroundColor, - borderRadius: BorderRadius.circular(4), - border: Border.all(color: borderColor), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Icon( - entry.isError ? Icons.error_outline : Icons.check_circle, - size: 14, - color: baseColor, - ), - const SizedBox(width: 6), - Expanded( - child: Text( - entry.message, - style: TextStyle( - fontSize: 11, - fontFamily: 'monospace', - color: baseColor.shade800, - ), - ), - ), - ], - ), - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/common/parameter_dialog.dart b/flutter_inappwebview/example/lib/widgets/common/parameter_dialog.dart deleted file mode 100644 index fcfa40202f..0000000000 --- a/flutter_inappwebview/example/lib/widgets/common/parameter_dialog.dart +++ /dev/null @@ -1,1218 +0,0 @@ -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:file_picker/file_picker.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview_example/utils/parameter_dialog_utils.dart'; - -enum ParameterValueType { - string, - number, - boolean, - color, - date, - bytes, - list, - map, - enumeration, -} - -class ParameterValueHint { - final T? value; - final ParameterValueType type; - - const ParameterValueHint(this.value, this.type); -} - -/// A specialized hint for enum parameters that includes available values. -/// Works with both standard Dart enums and custom enum-like classes -/// (like UserScriptInjectionTime, CompressFormat) that have a `values` property -/// and a `name()` method. -class EnumParameterValueHint extends ParameterValueHint { - /// The list of all available enum values. - /// Accepts both List and Set (will be converted to List internally). - final List enumValues; - - /// Whether the enum should allow multiple selections. - /// Useful for bitmask/flag-style enums. - final bool isMultiSelect; - - /// Optional display names for enum values. - /// For standard Dart enums, defaults to `e.name`. - /// For custom enum-like classes, this is optional; the default - /// resolver tries `name()` then `.name` before falling back to `toString()`. - final String Function(T)? displayName; - - /// Creates an enum parameter value hint. - /// [values] can be a List or Set (common for custom enum-like classes). - const EnumParameterValueHint( - Object? value, - this.enumValues, { - this.displayName, - this.isMultiSelect = false, - }) : super(value, ParameterValueType.enumeration); - - /// Factory constructor that accepts an Iterable (List or Set). - factory EnumParameterValueHint.fromIterable( - Object? value, - Iterable values, { - String Function(T)? displayName, - bool isMultiSelect = false, - }) { - return EnumParameterValueHint( - value, - values.toList(), - displayName: displayName, - isMultiSelect: isMultiSelect, - ); - } -} - -Future?> showParameterDialog({ - required BuildContext context, - required String title, - required Map parameters, - String? description, - List requiredPaths = const [], -}) { - return showDialog>( - context: context, - builder: (context) => ParameterDialog( - title: title, - parameters: parameters, - description: description, - requiredPaths: requiredPaths, - ), - ); -} - -class ParameterDialog extends StatefulWidget { - final String title; - final String? description; - final Map parameters; - final List requiredPaths; - - const ParameterDialog({ - super.key, - required this.title, - required this.parameters, - this.description, - this.requiredPaths = const [], - }); - - @override - State createState() => _ParameterDialogState(); -} - -class _ParameterDialogState extends State { - final Map _controllers = {}; - final Map _controllerTypes = {}; - final Map> _controllerPaths = {}; - final Map _hintedTypes = {}; - final Map _errors = {}; - - /// Stores enum metadata for enum parameters (key -> EnumInfo) - final Map _enumInfoMap = {}; - - late Map _editedParameters; - - /// Default display name function that works with both Dart enums and custom enum-like classes. - /// Tries to call `.name()` method first (for custom classes), then falls back to `.name` property (for Dart enums). - static String _defaultEnumDisplayName(dynamic e) { - if (e == null) return '(none)'; - // Try calling name() method first (for custom enum-like classes) - try { - final dynamic result = (e as dynamic).name(); - if (result is String) return result; - } catch (_) {} - // Fall back to .name property (for Dart enums) - try { - final dynamic result = (e as dynamic).name; - if (result is String) return result; - } catch (_) {} - // Last resort: toString - return e.toString(); - } - - @override - void initState() { - super.initState(); - _editedParameters = _normalizeParameters(widget.parameters); - } - - @override - void dispose() { - for (final controller in _controllers.values) { - controller.dispose(); - } - super.dispose(); - } - - Map _normalizeParameters(Map parameters) { - final cloned = ParameterDialogUtils.deepCloneMap(parameters); - - void walk(dynamic value, List path) { - if (value is Map) { - value.forEach((key, nested) => walk(nested, [...path, key])); - return; - } - if (value is List) { - for (var i = 0; i < value.length; i++) { - walk(value[i], [...path, i]); - } - return; - } - if (value is EnumParameterValueHint) { - final key = _pathKey(path); - _hintedTypes[key] = ParameterValueType.enumeration; - // Wrap the typed displayName function in a dynamic closure to handle - // the generic type properly (e.g., String Function(CompressFormat) -> String Function(dynamic)) - // We use dynamic access here to bypass covariant check failures with generic functions - final userDisplayName = (value as dynamic).displayName; - String Function(dynamic) displayNameFn; - if (userDisplayName != null) { - displayNameFn = (dynamic e) => userDisplayName(e); - } else { - displayNameFn = _defaultEnumDisplayName; - } - final enumValues = (value as dynamic).enumValues.toList(); - final isMultiSelect = (value as dynamic).isMultiSelect == true; - _enumInfoMap[key] = _EnumInfo( - values: enumValues, - displayName: displayNameFn, - isMultiSelect: isMultiSelect, - ); - final normalizedValue = isMultiSelect - ? _normalizeEnumMultiSelectValue(value.value, enumValues) - : value.value; - ParameterDialogUtils.setValueAtPath(cloned, path, normalizedValue); - return; - } - if (value is ParameterValueHint) { - final key = _pathKey(path); - _hintedTypes[key] = value.type; - ParameterDialogUtils.setValueAtPath( - cloned, - path, - ParameterDialogUtils.deepCloneValue(value.value), - ); - } - } - - walk(cloned, []); - return cloned; - } - - String _pathKey(List path) { - final buffer = StringBuffer(); - for (final segment in path) { - if (segment is int) { - buffer.write('[${segment}]'); - } else { - if (buffer.isNotEmpty) buffer.write('.'); - buffer.write(segment.toString()); - } - } - return buffer.toString(); - } - - List _parsePathKey(String pathKey) { - final result = []; - final buffer = StringBuffer(); - var index = 0; - - void flushBuffer() { - if (buffer.isNotEmpty) { - result.add(buffer.toString()); - buffer.clear(); - } - } - - while (index < pathKey.length) { - final char = pathKey[index]; - if (char == '.') { - flushBuffer(); - index++; - continue; - } - if (char == '[') { - flushBuffer(); - final endIndex = pathKey.indexOf(']', index); - if (endIndex == -1) { - buffer.write(pathKey.substring(index)); - break; - } - final rawIndex = pathKey.substring(index + 1, endIndex); - final parsedIndex = int.tryParse(rawIndex); - if (parsedIndex != null) { - result.add(parsedIndex); - } else { - buffer.write(pathKey.substring(index, endIndex + 1)); - } - index = endIndex + 1; - continue; - } - buffer.write(char); - index++; - } - - flushBuffer(); - return result; - } - - bool _isValueEmpty(dynamic value) { - if (value == null) return true; - if (value is String) return value.trim().isEmpty; - if (value is Uint8List) return value.isEmpty; - if (value is List) return value.isEmpty; - if (value is Map) return value.isEmpty; - return false; - } - - List _normalizeEnumMultiSelectValue( - dynamic value, - List allowedValues, - ) { - if (value == null) return []; - - Iterable rawValues; - if (value is Set) { - rawValues = value; - } else if (value is List) { - rawValues = value; - } else { - rawValues = [value]; - } - - return rawValues.where(allowedValues.contains).toList(); - } - - ParameterValueType _inferType(dynamic value, List path) { - final hinted = _hintedTypes[_pathKey(path)]; - if (hinted != null) return hinted; - if (value is bool) return ParameterValueType.boolean; - if (value is num) return ParameterValueType.number; - if (value is Color) return ParameterValueType.color; - if (value is DateTime) return ParameterValueType.date; - if (value is Uint8List) return ParameterValueType.bytes; - if (value is List) return ParameterValueType.list; - if (value is Map) return ParameterValueType.map; - return ParameterValueType.string; - } - - TextEditingController _getController( - List path, - String initialValue, - ParameterValueType type, - ) { - final key = _pathKey(path); - if (_controllers.containsKey(key)) { - return _controllers[key]!; - } - - final controller = TextEditingController(text: initialValue); - _controllers[key] = controller; - _controllerTypes[key] = type; - _controllerPaths[key] = path; - return controller; - } - - Future _pickBytes(List path) async { - final result = await FilePicker.platform.pickFiles(withData: true); - if (result == null || result.files.isEmpty) return; - - final bytes = result.files.first.bytes; - if (bytes == null) return; - - setState(() { - ParameterDialogUtils.setValueAtPath(_editedParameters, path, bytes); - final key = _pathKey(path); - _controllers[key]?.text = 'base64:${base64.encode(bytes)}'; - _errors[key] = null; - }); - } - - Future _pickDate(List path, DateTime? current) async { - final now = DateTime.now(); - final date = await showDatePicker( - context: context, - initialDate: current ?? now, - firstDate: now.subtract(const Duration(days: 3650)), - lastDate: now.add(const Duration(days: 3650)), - ); - if (date == null) return; - - setState(() { - ParameterDialogUtils.setValueAtPath(_editedParameters, path, date); - }); - } - - Future _pickColor(List path, Color? current) async { - final picked = await showDialog( - context: context, - builder: (context) => _ColorPickerDialog(current: current), - ); - - if (picked == null) return; - setState(() { - ParameterDialogUtils.setValueAtPath(_editedParameters, path, picked); - }); - } - - void _addMapEntry(List path) { - final keyController = TextEditingController(); - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Add Field'), - content: TextField( - controller: keyController, - decoration: const InputDecoration( - labelText: 'Key', - border: OutlineInputBorder(), - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: () { - final key = keyController.text.trim(); - if (key.isEmpty) return; - setState(() { - final map = ParameterDialogUtils.getValueAtPath( - _editedParameters, - path, - ); - if (map is Map) { - map[key] = ''; - } - }); - Navigator.pop(context); - }, - child: const Text('Add'), - ), - ], - ), - ); - } - - void _addListEntry(List path) { - setState(() { - final list = - ParameterDialogUtils.getValueAtPath(_editedParameters, path) as List; - if (list.isEmpty) { - list.add(''); - return; - } - list.add(ParameterDialogUtils.deepCloneValue(list.last)); - }); - } - - void _removeEntry(List path, Object keyOrIndex) { - setState(() { - final container = ParameterDialogUtils.getValueAtPath( - _editedParameters, - path, - ); - if (container is Map) { - container.remove(keyOrIndex); - } else if (container is List && keyOrIndex is int) { - if (keyOrIndex >= 0 && keyOrIndex < container.length) { - container.removeAt(keyOrIndex); - } - } - }); - } - - void _apply() { - _errors.clear(); - - for (final entry in _controllers.entries) { - final key = entry.key; - final controller = entry.value; - final path = _controllerPaths[key]!; - final type = _controllerTypes[key]!; - final text = controller.text.trim(); - - switch (type) { - case ParameterValueType.number: - final parsed = ParameterDialogUtils.parseNumber(text); - if (text.isNotEmpty && parsed == null) { - _errors[key] = 'Invalid number'; - continue; - } - ParameterDialogUtils.setValueAtPath(_editedParameters, path, parsed); - break; - case ParameterValueType.bytes: - final parsed = ParameterDialogUtils.parseBytes(text); - if (text.isNotEmpty && parsed == null) { - _errors[key] = 'Invalid base64'; - continue; - } - ParameterDialogUtils.setValueAtPath(_editedParameters, path, parsed); - break; - default: - ParameterDialogUtils.setValueAtPath(_editedParameters, path, text); - break; - } - } - - for (final requiredPath in widget.requiredPaths) { - if (_errors.containsKey(requiredPath)) { - continue; - } - final parsedPath = _parsePathKey(requiredPath); - final value = ParameterDialogUtils.getValueAtPath( - _editedParameters, - parsedPath, - ); - if (_isValueEmpty(value)) { - _errors[requiredPath] = 'Required'; - } - } - - if (_errors.isNotEmpty) { - setState(() {}); - return; - } - - Navigator.pop(context, _editedParameters); - } - - @override - Widget build(BuildContext context) { - final parameterWidgets = _buildParameterWidgets(_editedParameters, []); - - return AlertDialog( - title: Text(widget.title), - content: SizedBox( - width: double.maxFinite, - child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (widget.description != null) ...[ - Text( - widget.description!, - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - const SizedBox(height: 12), - ], - ...parameterWidgets, - ], - ), - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), - ), - ElevatedButton(onPressed: _apply, child: const Text('Apply')), - ], - ); - } - - List _buildParameterWidgets(dynamic value, List path) { - if (value is Map) { - return [ - ...value.entries.map((entry) { - final entryPath = [...path, entry.key.toString()]; - final type = _inferType(entry.value, entryPath); - return _buildField( - entry.key.toString(), - entry.value, - entryPath, - type, - canRemove: path.isNotEmpty, - onRemove: () => _removeEntry(path, entry.key), - ); - }), - if (path.isNotEmpty) - Align( - alignment: Alignment.centerLeft, - child: TextButton.icon( - onPressed: () => _addMapEntry(path), - icon: const Icon(Icons.add), - label: const Text('Add field'), - ), - ), - ]; - } - - if (value is List) { - return [ - ...value.asMap().entries.map((entry) { - final index = entry.key; - final itemPath = [...path, index]; - final type = _inferType(entry.value, itemPath); - return _buildField( - '[${entry.key}]', - entry.value, - itemPath, - type, - canRemove: true, - onRemove: () => _removeEntry(path, index), - ); - }), - Align( - alignment: Alignment.centerLeft, - child: TextButton.icon( - onPressed: () => _addListEntry(path), - icon: const Icon(Icons.add), - label: const Text('Add item'), - ), - ), - ]; - } - - final type = _inferType(value, path); - return [_buildField(path.last.toString(), value, path, type)]; - } - - Widget _buildField( - String label, - dynamic value, - List path, - ParameterValueType type, { - bool canRemove = false, - VoidCallback? onRemove, - }) { - final key = _pathKey(path); - final errorText = _errors[key]; - - Widget field; - - switch (type) { - case ParameterValueType.boolean: - field = SwitchListTile( - contentPadding: EdgeInsets.zero, - title: Text(label), - value: (value as bool?) ?? false, - onChanged: (updated) { - setState(() { - ParameterDialogUtils.setValueAtPath( - _editedParameters, - path, - updated, - ); - }); - }, - ); - break; - case ParameterValueType.color: - final color = value as Color?; - field = Row( - children: [ - Expanded(child: Text(label)), - Container( - width: 24, - height: 24, - decoration: BoxDecoration( - color: color ?? Colors.transparent, - border: Border.all(color: Colors.grey.shade400), - borderRadius: BorderRadius.circular(4), - ), - ), - const SizedBox(width: 8), - TextButton( - onPressed: () => _pickColor(path, color), - child: const Text('Pick'), - ), - TextButton( - onPressed: () { - setState(() { - ParameterDialogUtils.setValueAtPath( - _editedParameters, - path, - null, - ); - }); - }, - child: const Text('Clear'), - ), - ], - ); - break; - case ParameterValueType.date: - final date = value as DateTime?; - field = Row( - children: [ - Expanded( - child: Text( - '$label: ${date?.toIso8601String().split('T').first ?? 'Not set'}', - ), - ), - TextButton( - onPressed: () => _pickDate(path, date), - child: const Text('Pick'), - ), - TextButton( - onPressed: () { - setState(() { - ParameterDialogUtils.setValueAtPath( - _editedParameters, - path, - null, - ); - }); - }, - child: const Text('Clear'), - ), - ], - ); - break; - case ParameterValueType.bytes: - final controller = _getController( - path, - value is Uint8List ? 'base64:${base64.encode(value)}' : '', - type, - ); - field = Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(label), - const SizedBox(height: 6), - TextField( - controller: controller, - decoration: InputDecoration( - labelText: 'Enter text (UTF-8) or base64:... for binary', - hintText: 'Type text here or paste base64:...', - border: const OutlineInputBorder(), - errorText: errorText, - ), - maxLines: 4, - ), - const SizedBox(height: 6), - Row( - children: [ - TextButton.icon( - onPressed: () => _pickBytes(path), - icon: const Icon(Icons.attach_file), - label: const Text('Pick file'), - ), - if (value is Uint8List) Text('(${value.length} bytes)'), - ], - ), - Text( - 'Tip: Plain text is converted to UTF-8 bytes. Use "base64:..." prefix for binary data.', - style: TextStyle(fontSize: 11, color: Colors.grey.shade600), - ), - ], - ); - break; - case ParameterValueType.number: - final controller = _getController(path, value?.toString() ?? '', type); - field = TextField( - controller: controller, - keyboardType: const TextInputType.numberWithOptions(decimal: true), - decoration: InputDecoration( - labelText: label, - border: const OutlineInputBorder(), - errorText: errorText, - ), - ); - break; - case ParameterValueType.list: - field = ExpansionTile( - title: Text(label), - children: _buildParameterWidgets(value, path), - ); - break; - case ParameterValueType.map: - field = ExpansionTile( - title: Text(label), - children: _buildParameterWidgets(value, path), - ); - break; - case ParameterValueType.string: - final controller = _getController(path, value?.toString() ?? '', type); - field = TextField( - controller: controller, - decoration: InputDecoration( - labelText: label, - border: const OutlineInputBorder(), - errorText: errorText, - ), - ); - break; - case ParameterValueType.enumeration: - final enumInfo = _enumInfoMap[key]; - if (enumInfo == null) { - // Fallback to string field if no enum info - final controller = _getController( - path, - value?.toString() ?? '', - ParameterValueType.string, - ); - field = TextField( - controller: controller, - decoration: InputDecoration( - labelText: label, - border: const OutlineInputBorder(), - errorText: errorText, - ), - ); - } else if (enumInfo.isMultiSelect) { - final selectedValues = _normalizeEnumMultiSelectValue( - value, - enumInfo.values, - ); - field = InputDecorator( - decoration: InputDecoration( - labelText: label, - border: const OutlineInputBorder(), - errorText: errorText, - ), - child: Wrap( - spacing: 8, - runSpacing: 8, - children: enumInfo.values.map((enumValue) { - final isSelected = selectedValues.contains(enumValue); - return FilterChip( - label: Text(enumInfo.displayName(enumValue)), - selected: isSelected, - onSelected: (selected) { - setState(() { - final updated = List.from(selectedValues); - if (selected) { - if (!updated.contains(enumValue)) { - updated.add(enumValue); - } - } else { - updated.remove(enumValue); - } - ParameterDialogUtils.setValueAtPath( - _editedParameters, - path, - updated, - ); - }); - }, - ); - }).toList(), - ), - ); - } else { - field = DropdownButtonFormField( - value: value, - decoration: InputDecoration( - labelText: label, - border: const OutlineInputBorder(), - errorText: errorText, - ), - items: [ - const DropdownMenuItem( - value: null, - child: Text('(none)'), - ), - ...enumInfo.values.map( - (enumValue) => DropdownMenuItem( - value: enumValue, - child: Text(enumInfo.displayName(enumValue)), - ), - ), - ], - onChanged: (newValue) { - setState(() { - ParameterDialogUtils.setValueAtPath( - _editedParameters, - path, - newValue, - ); - }); - }, - ); - } - break; - } - - return Padding( - padding: const EdgeInsets.only(bottom: 12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Expanded(child: field), - if (canRemove && onRemove != null) ...[ - const SizedBox(width: 8), - IconButton( - icon: const Icon(Icons.delete_outline), - onPressed: onRemove, - ), - ], - ], - ), - if (errorText != null && - type != ParameterValueType.string && - type != ParameterValueType.number && - type != ParameterValueType.bytes) - Padding( - padding: const EdgeInsets.only(top: 4), - child: Text( - errorText, - style: TextStyle( - color: Theme.of(context).colorScheme.error, - fontSize: 12, - ), - ), - ), - ], - ), - ); - } -} - -/// Internal class to store enum metadata. -/// Works with both standard Dart enums and custom enum-like classes. -class _EnumInfo { - final List values; - final String Function(dynamic) displayName; - final bool isMultiSelect; - - const _EnumInfo({ - required this.values, - required this.displayName, - required this.isMultiSelect, - }); -} - -class _ColorPickerDialog extends StatefulWidget { - final Color? current; - - const _ColorPickerDialog({this.current}); - - @override - State<_ColorPickerDialog> createState() => _ColorPickerDialogState(); -} - -class _ColorPickerDialogState extends State<_ColorPickerDialog> { - late HSVColor _hsvColor; - late TextEditingController _hexController; - - // Common preset colors for quick selection - static const List _presetColors = [ - Colors.red, - Colors.pink, - Colors.purple, - Colors.deepPurple, - Colors.indigo, - Colors.blue, - Colors.lightBlue, - Colors.cyan, - Colors.teal, - Colors.green, - Colors.lightGreen, - Colors.lime, - Colors.yellow, - Colors.amber, - Colors.orange, - Colors.deepOrange, - Colors.brown, - Colors.grey, - Colors.blueGrey, - Colors.black, - Colors.white, - ]; - - @override - void initState() { - super.initState(); - _hsvColor = HSVColor.fromColor(widget.current ?? Colors.blue); - _hexController = TextEditingController( - text: _colorToHex(_hsvColor.toColor()), - ); - } - - @override - void dispose() { - _hexController.dispose(); - super.dispose(); - } - - String _colorToHex(Color color) { - return '#${color.value.toRadixString(16).padLeft(8, '0').substring(2).toUpperCase()}'; - } - - Color? _hexToColor(String hex) { - hex = hex.replaceAll('#', ''); - if (hex.length == 6) { - hex = 'FF$hex'; - } - if (hex.length != 8) return null; - final value = int.tryParse(hex, radix: 16); - if (value == null) return null; - return Color(value); - } - - void _updateFromHex(String hex) { - final color = _hexToColor(hex); - if (color != null) { - setState(() { - _hsvColor = HSVColor.fromColor(color); - }); - } - } - - @override - Widget build(BuildContext context) { - final currentColor = _hsvColor.toColor(); - - return AlertDialog( - title: const Text('Pick a color'), - content: SizedBox( - width: 320, - child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - // Color preview - Container( - height: 50, - width: double.infinity, - decoration: BoxDecoration( - color: currentColor, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Colors.grey.shade300), - ), - ), - const SizedBox(height: 16), - - // Hue slider - _buildSliderRow( - label: 'Hue', - value: _hsvColor.hue, - max: 360, - activeColor: HSVColor.fromAHSV( - 1, - _hsvColor.hue, - 1, - 1, - ).toColor(), - gradient: LinearGradient( - colors: List.generate( - 7, - (i) => HSVColor.fromAHSV(1, i * 60.0, 1, 1).toColor(), - ), - ), - onChanged: (value) { - setState(() { - _hsvColor = _hsvColor.withHue(value); - _hexController.text = _colorToHex(_hsvColor.toColor()); - }); - }, - ), - - // Saturation slider - _buildSliderRow( - label: 'Saturation', - value: _hsvColor.saturation * 100, - max: 100, - activeColor: currentColor, - gradient: LinearGradient( - colors: [ - HSVColor.fromAHSV( - 1, - _hsvColor.hue, - 0, - _hsvColor.value, - ).toColor(), - HSVColor.fromAHSV( - 1, - _hsvColor.hue, - 1, - _hsvColor.value, - ).toColor(), - ], - ), - onChanged: (value) { - setState(() { - _hsvColor = _hsvColor.withSaturation(value / 100); - _hexController.text = _colorToHex(_hsvColor.toColor()); - }); - }, - ), - - // Value/Brightness slider - _buildSliderRow( - label: 'Brightness', - value: _hsvColor.value * 100, - max: 100, - activeColor: currentColor, - gradient: LinearGradient( - colors: [ - Colors.black, - HSVColor.fromAHSV( - 1, - _hsvColor.hue, - _hsvColor.saturation, - 1, - ).toColor(), - ], - ), - onChanged: (value) { - setState(() { - _hsvColor = _hsvColor.withValue(value / 100); - _hexController.text = _colorToHex(_hsvColor.toColor()); - }); - }, - ), - - const SizedBox(height: 12), - - // Hex input - Row( - children: [ - Expanded( - child: TextField( - controller: _hexController, - decoration: const InputDecoration( - labelText: 'Hex', - border: OutlineInputBorder(), - isDense: true, - prefixText: '#', - ), - onChanged: _updateFromHex, - ), - ), - const SizedBox(width: 8), - // RGB display - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'R: ${currentColor.red}', - style: const TextStyle(fontSize: 11), - ), - Text( - 'G: ${currentColor.green}', - style: const TextStyle(fontSize: 11), - ), - Text( - 'B: ${currentColor.blue}', - style: const TextStyle(fontSize: 11), - ), - ], - ), - ], - ), - - const SizedBox(height: 16), - - // Preset colors - const Align( - alignment: Alignment.centerLeft, - child: Text( - 'Presets', - style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600), - ), - ), - const SizedBox(height: 8), - Wrap( - spacing: 6, - runSpacing: 6, - children: _presetColors - .map( - (color) => GestureDetector( - onTap: () { - setState(() { - _hsvColor = HSVColor.fromColor(color); - _hexController.text = _colorToHex(color); - }); - }, - child: Container( - width: 28, - height: 28, - decoration: BoxDecoration( - color: color, - borderRadius: BorderRadius.circular(4), - border: Border.all( - color: _hsvColor.toColor().value == color.value - ? Colors.black - : Colors.grey.shade300, - width: _hsvColor.toColor().value == color.value - ? 2 - : 1, - ), - ), - ), - ), - ) - .toList(), - ), - ], - ), - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: () => Navigator.pop(context, currentColor), - child: const Text('Select'), - ), - ], - ); - } - - Widget _buildSliderRow({ - required String label, - required double value, - required double max, - required Color activeColor, - required Gradient gradient, - required ValueChanged onChanged, - }) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(label, style: const TextStyle(fontSize: 12)), - Text( - value.toStringAsFixed(0), - style: const TextStyle(fontSize: 12), - ), - ], - ), - const SizedBox(height: 4), - Container( - height: 24, - decoration: BoxDecoration( - gradient: gradient, - borderRadius: BorderRadius.circular(12), - ), - child: SliderTheme( - data: SliderThemeData( - trackHeight: 24, - thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 10), - overlayShape: const RoundSliderOverlayShape(overlayRadius: 16), - trackShape: const RoundedRectSliderTrackShape(), - activeTrackColor: Colors.transparent, - inactiveTrackColor: Colors.transparent, - thumbColor: Colors.white, - overlayColor: activeColor.withOpacity(0.2), - ), - child: Slider( - value: value, - min: 0, - max: max, - onChanged: onChanged, - ), - ), - ), - ], - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/common/platform_filter.dart b/flutter_inappwebview/example/lib/widgets/common/platform_filter.dart deleted file mode 100644 index 5aec9ec11f..0000000000 --- a/flutter_inappwebview/example/lib/widgets/common/platform_filter.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; - -/// Widget for filtering tests by platform with checkboxes -class PlatformFilter extends StatelessWidget { - final List selectedPlatforms; - final Function(List) onChanged; - - const PlatformFilter({ - super.key, - required this.selectedPlatforms, - required this.onChanged, - }); - - @override - Widget build(BuildContext context) { - return Column( - mainAxisSize: MainAxisSize.min, - children: SupportedPlatform.values.map((platform) { - final isSelected = selectedPlatforms.contains(platform); - - return CheckboxListTile( - title: Text(platform.displayName), - value: isSelected, - onChanged: (bool? checked) { - final newSelection = List.from( - selectedPlatforms, - ); - - if (checked == true) { - if (!newSelection.contains(platform)) { - newSelection.add(platform); - } - } else { - newSelection.remove(platform); - } - - onChanged(newSelection); - }, - ); - }).toList(), - ); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/common/profile_selector_card.dart b/flutter_inappwebview/example/lib/widgets/common/profile_selector_card.dart deleted file mode 100644 index 805b51d3f6..0000000000 --- a/flutter_inappwebview/example/lib/widgets/common/profile_selector_card.dart +++ /dev/null @@ -1,358 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; -import 'package:flutter_inappwebview_example/models/settings_profile.dart'; -import 'package:flutter_inappwebview_example/models/webview_environment_profile.dart'; -import 'package:flutter_inappwebview_example/utils/responsive_utils.dart'; - -class ProfileSelectorCard extends StatelessWidget { - const ProfileSelectorCard({ - super.key, - required this.onEditSettingsProfile, - this.onEditEnvironmentProfile, - this.compact = false, - }); - - final VoidCallback onEditSettingsProfile; - final VoidCallback? onEditEnvironmentProfile; - - /// When true, displays a more compact layout suitable for embedding - /// in constrained spaces (e.g., below WebView) - final bool compact; - - static const double _desktopBreakpoint = 600; - - @override - Widget build(BuildContext context) { - final isMobile = context.isMobile; - return Consumer( - builder: (context, settingsManager, _) { - if (settingsManager.isLoading) { - return const Card( - child: Padding( - padding: EdgeInsets.all(16), - child: Center(child: CircularProgressIndicator()), - ), - ); - } - - final padding = compact - ? const EdgeInsets.all(8) - : isMobile - ? const EdgeInsets.all(12) - : const EdgeInsets.all(16); - final margin = compact - ? const EdgeInsets.symmetric(horizontal: 8, vertical: 4) - : isMobile - ? const EdgeInsets.symmetric(horizontal: 12, vertical: 6) - : null; - - return Card( - margin: margin, - child: Padding( - key: const Key('profile-selector-card-padding'), - padding: padding, - child: LayoutBuilder( - builder: (context, constraints) { - final isWide = constraints.maxWidth >= _desktopBreakpoint; - - if (isWide) { - // Desktop: Two columns side by side - return Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: _buildSettingsProfileRow( - context, - settingsManager, - ), - ), - const SizedBox(width: 24), - Expanded( - child: _buildEnvironmentProfileRow( - context, - settingsManager, - ), - ), - ], - ); - } else { - // Mobile: One column stacked - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildSettingsProfileRow(context, settingsManager), - SizedBox(height: compact ? 8 : (isMobile ? 12 : 16)), - _buildEnvironmentProfileRow(context, settingsManager), - ], - ); - } - }, - ), - ), - ); - }, - ); - } - - Widget _buildSettingsProfileRow( - BuildContext context, - SettingsManager settingsManager, - ) { - final current = settingsManager.currentProfile; - final isMobile = context.isMobile; - final titleFontSize = compact ? 12.0 : (isMobile ? 13.0 : 14.0); - final labelFontSize = compact ? 11.0 : (isMobile ? 12.0 : 13.0); - final iconSize = compact ? 18.0 : (isMobile ? 20.0 : 24.0); - final iconConstraints = compact - ? const BoxConstraints(minWidth: 32, minHeight: 32) - : isMobile - ? const BoxConstraints(minWidth: 40, minHeight: 40) - : null; - final contentPadding = compact - ? const EdgeInsets.symmetric(horizontal: 8, vertical: 8) - : isMobile - ? const EdgeInsets.symmetric(horizontal: 10, vertical: 10) - : null; - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '${InAppWebView} Settings', - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: titleFontSize, - ), - ), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - child: DropdownButtonFormField( - isExpanded: true, - value: settingsManager.currentProfileId, - decoration: InputDecoration( - labelText: 'Settings Profile', - border: const OutlineInputBorder(), - isDense: true, - contentPadding: contentPadding, - labelStyle: TextStyle(fontSize: labelFontSize), - ), - items: [ - const DropdownMenuItem( - value: null, - child: Text('Default Settings'), - ), - ...settingsManager.profiles.map( - (profile) => DropdownMenuItem( - value: profile.id, - child: Text(profile.name), - ), - ), - ], - onChanged: (value) async { - if (value == null) { - await settingsManager.resetToDefaults(); - } else { - await settingsManager.loadProfile(value); - } - }, - ), - ), - const SizedBox(width: 8), - IconButton( - icon: const Icon(Icons.edit), - tooltip: 'Edit settings profile', - constraints: iconConstraints, - iconSize: iconSize, - onPressed: onEditSettingsProfile, - ), - IconButton( - icon: const Icon(Icons.delete), - tooltip: 'Delete selected profile', - constraints: iconConstraints, - iconSize: iconSize, - onPressed: current == null - ? null - : () => _confirmDeleteSettingsProfile(context, current), - ), - ], - ), - ], - ); - } - - Widget _buildEnvironmentProfileRow( - BuildContext context, - SettingsManager settingsManager, - ) { - final current = settingsManager.currentEnvironmentProfile; - final supported = settingsManager.isEnvironmentSupported; - final isMobile = context.isMobile; - final titleFontSize = compact ? 12.0 : (isMobile ? 13.0 : 14.0); - final labelFontSize = compact ? 11.0 : (isMobile ? 12.0 : 13.0); - final statusFontSize = compact ? 10.0 : (isMobile ? 11.0 : 12.0); - final iconSize = compact ? 18.0 : (isMobile ? 20.0 : 24.0); - final iconConstraints = compact - ? const BoxConstraints(minWidth: 32, minHeight: 32) - : isMobile - ? const BoxConstraints(minWidth: 40, minHeight: 40) - : null; - final contentPadding = compact - ? const EdgeInsets.symmetric(horizontal: 8, vertical: 8) - : isMobile - ? const EdgeInsets.symmetric(horizontal: 10, vertical: 10) - : null; - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - child: Text( - '$WebViewEnvironment', - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: titleFontSize, - ), - ), - ), - if (!supported) - Text( - 'Not supported', - style: TextStyle(fontSize: statusFontSize, color: Colors.grey), - ), - ], - ), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - child: DropdownButtonFormField( - isExpanded: true, - value: settingsManager.currentEnvironmentProfileId, - decoration: InputDecoration( - labelText: 'Environment Profile', - border: const OutlineInputBorder(), - isDense: true, - contentPadding: contentPadding, - labelStyle: TextStyle(fontSize: labelFontSize), - ), - items: [ - const DropdownMenuItem( - value: null, - child: Text('No Environment'), - ), - ...settingsManager.environmentProfiles.map( - (profile) => DropdownMenuItem( - value: profile.id, - child: Text(profile.name), - ), - ), - ], - onChanged: (value) async { - if (value == null) { - await settingsManager.clearEnvironmentSelection(); - } else { - await settingsManager.loadEnvironmentProfile(value); - } - }, - ), - ), - const SizedBox(width: 8), - IconButton( - icon: const Icon(Icons.edit), - tooltip: 'Edit environment profile', - constraints: iconConstraints, - iconSize: iconSize, - onPressed: onEditEnvironmentProfile, - ), - IconButton( - icon: const Icon(Icons.delete), - tooltip: 'Delete environment profile', - constraints: iconConstraints, - iconSize: iconSize, - onPressed: current == null - ? null - : () => _confirmDeleteEnvironmentProfile(context, current), - ), - ], - ), - if (settingsManager.isEnvironmentLoading) - const Padding( - padding: EdgeInsets.only(top: 8), - child: LinearProgressIndicator(), - ), - ], - ); - } - - Future _confirmDeleteSettingsProfile( - BuildContext context, - SettingsProfile profile, - ) async { - final shouldDelete = await _confirmDialog( - context, - title: 'Delete Settings Profile', - message: 'Delete "${profile.name}"?', - ); - if (shouldDelete) { - await context.read().deleteProfile(profile.id); - if (context.mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Deleted profile "${profile.name}"')), - ); - } - } - } - - Future _confirmDeleteEnvironmentProfile( - BuildContext context, - WebViewEnvironmentProfile profile, - ) async { - final shouldDelete = await _confirmDialog( - context, - title: 'Delete Environment Profile', - message: 'Delete "${profile.name}"?', - ); - if (shouldDelete) { - await context.read().deleteEnvironmentProfile( - profile.id, - ); - if (context.mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Deleted environment "${profile.name}"')), - ); - } - } - } - - Future _confirmDialog( - BuildContext context, { - required String title, - required String message, - }) async { - return (await showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text(title), - content: Text(message), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context, false), - child: const Text('Cancel'), - ), - ElevatedButton( - style: ElevatedButton.styleFrom(backgroundColor: Colors.red), - onPressed: () => Navigator.pop(context, true), - child: const Text('Delete'), - ), - ], - ), - )) ?? - false; - } -} diff --git a/flutter_inappwebview/example/lib/widgets/common/resize_handle.dart b/flutter_inappwebview/example/lib/widgets/common/resize_handle.dart deleted file mode 100644 index 00cd9d86be..0000000000 --- a/flutter_inappwebview/example/lib/widgets/common/resize_handle.dart +++ /dev/null @@ -1,52 +0,0 @@ -import 'package:flutter/material.dart'; - -/// A draggable handle for resizing vertically-split sections. -/// -/// Used in screens like WebViewTesterScreen, ControllersScreen, and WebStorageScreen -/// to allow users to resize the WebView preview area. -class ResizeHandle extends StatelessWidget { - /// Called when the user drags the handle. [delta] is the vertical displacement. - final ValueChanged onDrag; - - /// Height of the resize handle area. - final double height; - - /// Color of the handle background. - final Color? backgroundColor; - - /// Color of the grip indicator. - final Color? gripColor; - - const ResizeHandle({ - super.key, - required this.onDrag, - this.height = 6.0, - this.backgroundColor, - this.gripColor, - }); - - @override - Widget build(BuildContext context) { - return MouseRegion( - cursor: SystemMouseCursors.resizeRow, - child: GestureDetector( - behavior: HitTestBehavior.translucent, - onVerticalDragUpdate: (details) => onDrag(details.delta.dy), - child: Container( - height: height, - color: backgroundColor ?? Colors.grey.shade300, - child: Center( - child: Container( - width: 40, - height: 2, - decoration: BoxDecoration( - color: gripColor ?? Colors.grey.shade600, - borderRadius: BorderRadius.circular(2), - ), - ), - ), - ), - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/common/responsive_row.dart b/flutter_inappwebview/example/lib/widgets/common/responsive_row.dart deleted file mode 100644 index 07864e7a03..0000000000 --- a/flutter_inappwebview/example/lib/widgets/common/responsive_row.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview_example/utils/responsive_utils.dart'; - -/// A layout widget that switches between [Row] and [Column] by breakpoint. -class ResponsiveRow extends StatelessWidget { - const ResponsiveRow({ - super.key, - required this.children, - this.spacing = 0, - this.runSpacing = 0, - this.mainAxisAlignment = MainAxisAlignment.start, - this.crossAxisAlignment = CrossAxisAlignment.center, - this.mainAxisSize = MainAxisSize.max, - this.showDivider = false, - this.divider, - this.rowKey, - this.columnKey, - }); - - final List children; - final double spacing; - final double runSpacing; - final MainAxisAlignment mainAxisAlignment; - final CrossAxisAlignment crossAxisAlignment; - final MainAxisSize mainAxisSize; - final bool showDivider; - final Widget? divider; - final Key? rowKey; - final Key? columnKey; - - @override - Widget build(BuildContext context) { - return LayoutBuilder( - builder: (context, constraints) { - final isMobile = ResponsiveBreakpoints.isMobileWidth( - constraints.maxWidth, - ); - return isMobile ? _buildColumn() : _buildRow(); - }, - ); - } - - Widget _buildRow() { - return Row( - key: rowKey, - mainAxisAlignment: mainAxisAlignment, - crossAxisAlignment: crossAxisAlignment, - mainAxisSize: mainAxisSize, - children: _withSpacing(axis: Axis.horizontal, spacing: spacing), - ); - } - - Widget _buildColumn() { - return Column( - key: columnKey, - mainAxisAlignment: mainAxisAlignment, - crossAxisAlignment: crossAxisAlignment, - mainAxisSize: MainAxisSize.min, - children: _withSpacing( - axis: Axis.vertical, - spacing: runSpacing > 0 ? runSpacing : spacing, - ), - ); - } - - List _withSpacing({required Axis axis, required double spacing}) { - if (children.isEmpty) { - return const []; - } - - final items = []; - for (var index = 0; index < children.length; index++) { - items.add(children[index]); - if (index == children.length - 1) { - continue; - } - if (showDivider) { - items.add(_resolveDivider(axis)); - } - if (spacing > 0) { - items.add( - axis == Axis.horizontal - ? SizedBox(width: spacing) - : SizedBox(height: spacing), - ); - } - } - return items; - } - - Widget _resolveDivider(Axis axis) { - if (divider != null) { - return divider!; - } - if (axis == Axis.horizontal) { - return const VerticalDivider(width: 1); - } - return const Divider(height: 1); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/common/section_card.dart b/flutter_inappwebview/example/lib/widgets/common/section_card.dart deleted file mode 100644 index 939cecd907..0000000000 --- a/flutter_inappwebview/example/lib/widgets/common/section_card.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'package:flutter/material.dart'; - -/// A grouped section within a card containing related information. -/// -/// Used for displaying categorized features in PlatformInfoScreen. -class InfoSection extends StatelessWidget { - /// The title of the section. - final String title; - - /// Icon to display next to the title. - final IconData icon; - - /// The child widgets. - final List children; - - const InfoSection({ - super.key, - required this.title, - required this.icon, - required this.children, - }); - - @override - Widget build(BuildContext context) { - return Card( - elevation: 2, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(icon, color: Theme.of(context).primaryColor), - const SizedBox(width: 8), - Text( - title, - style: Theme.of( - context, - ).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold), - ), - ], - ), - const Divider(height: 24), - ...children, - ], - ), - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/common/status_card.dart b/flutter_inappwebview/example/lib/widgets/common/status_card.dart deleted file mode 100644 index 898ffa7b47..0000000000 --- a/flutter_inappwebview/example/lib/widgets/common/status_card.dart +++ /dev/null @@ -1,196 +0,0 @@ -import 'package:flutter/material.dart'; - -/// A card displaying the status of a component (e.g., browser, WebView, channel). -/// -/// Used in screens like InAppBrowserScreen and ControllersScreen to show -/// whether a component is active/open or inactive/closed. -class StatusCard extends StatelessWidget { - /// Whether the component is in an active/open state. - final bool isActive; - - /// The icon to display when active. - final IconData activeIcon; - - /// The icon to display when inactive. - final IconData inactiveIcon; - - /// The title text to display when active. - final String activeTitle; - - /// The title text to display when inactive. - final String inactiveTitle; - - /// Optional subtitle text. - final String? subtitle; - - /// Background color when active. Defaults to green shade. - final Color? activeColor; - - /// Background color when inactive. Defaults to grey shade. - final Color? inactiveColor; - - /// Optional trailing widget. - final Widget? trailing; - - const StatusCard({ - super.key, - required this.isActive, - required this.activeIcon, - required this.inactiveIcon, - required this.activeTitle, - required this.inactiveTitle, - this.subtitle, - this.activeColor, - this.inactiveColor, - this.trailing, - }); - - @override - Widget build(BuildContext context) { - final bgColor = isActive - ? (activeColor ?? Colors.green.shade50) - : (inactiveColor ?? Colors.grey.shade100); - final iconColor = isActive ? Colors.green : Colors.grey; - final textColor = isActive ? Colors.green : Colors.grey; - - return Card( - color: bgColor, - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - children: [ - Icon( - isActive ? activeIcon : inactiveIcon, - color: iconColor, - size: 32, - ), - const SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - isActive ? activeTitle : inactiveTitle, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: textColor, - ), - ), - if (subtitle != null) - Text( - subtitle!, - style: TextStyle( - fontSize: 12, - color: Colors.grey.shade600, - ), - ), - ], - ), - ), - if (trailing != null) trailing!, - ], - ), - ), - ); - } -} - -/// A small status indicator badge with an icon and text. -/// -/// Useful for showing inline status information like "WebView Ready" or "Loading...". -class StatusBadge extends StatelessWidget { - /// Whether the status is positive/active. - final bool isActive; - - /// The text to display. - final String text; - - /// Optional icon to display. Defaults to check/cancel icons. - final IconData? icon; - - const StatusBadge({ - super.key, - required this.isActive, - required this.text, - this.icon, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.7), - borderRadius: BorderRadius.circular(4), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (icon != null) - Icon(icon!, color: isActive ? Colors.green : Colors.white, size: 14) - else - Icon( - isActive ? Icons.check : Icons.hourglass_empty, - color: isActive ? Colors.green : Colors.white, - size: 14, - ), - const SizedBox(width: 4), - Text( - text, - style: TextStyle( - color: isActive ? Colors.green : Colors.white, - fontSize: 12, - ), - ), - ], - ), - ); - } -} - -/// A channel status indicator showing active/inactive state. -/// -/// Used for WebMessageChannel and similar components. -class ChannelStatusIndicator extends StatelessWidget { - /// Whether the channel is active. - final bool isActive; - - /// Text to display when active. - final String activeText; - - /// Text to display when inactive. - final String inactiveText; - - const ChannelStatusIndicator({ - super.key, - required this.isActive, - this.activeText = 'Channel Active', - this.inactiveText = 'No Channel', - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: isActive ? Colors.green.shade50 : Colors.grey.shade100, - borderRadius: BorderRadius.circular(4), - ), - child: Row( - children: [ - Icon( - isActive ? Icons.check_circle : Icons.cancel, - color: isActive ? Colors.green : Colors.grey, - size: 20, - ), - const SizedBox(width: 8), - Text( - isActive ? activeText : inactiveText, - style: TextStyle(color: isActive ? Colors.green : Colors.grey), - ), - ], - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/common/support_badge.dart b/flutter_inappwebview/example/lib/widgets/common/support_badge.dart deleted file mode 100644 index 8acf3a7921..0000000000 --- a/flutter_inappwebview/example/lib/widgets/common/support_badge.dart +++ /dev/null @@ -1,104 +0,0 @@ -import 'package:flutter/material.dart'; -import '../../utils/support_checker.dart'; - -class SupportBadge extends StatelessWidget { - final SupportedPlatform platform; - final bool isSupported; - final bool showLabel; - final bool compact; - - const SupportBadge({ - super.key, - required this.platform, - required this.isSupported, - this.showLabel = false, - this.compact = false, - }); - - @override - Widget build(BuildContext context) { - final iconSize = compact ? 14.0 : 16.0; - final statusSize = compact ? 10.0 : 12.0; - final padding = compact - ? const EdgeInsets.symmetric(horizontal: 6, vertical: 3) - : const EdgeInsets.symmetric(horizontal: 8, vertical: 4); - final borderRadius = compact ? 10.0 : 12.0; - - final backgroundColor = isSupported - ? platform.color.withOpacity(0.12) - : Colors.grey.shade200; - final borderColor = isSupported - ? platform.color.withOpacity(0.4) - : Colors.grey.shade300; - final iconColor = isSupported ? platform.color : Colors.grey.shade500; - - return Tooltip( - message: - '${platform.displayName}: ${isSupported ? "Supported" : "Not supported"}', - child: Container( - padding: padding, - decoration: BoxDecoration( - color: backgroundColor, - borderRadius: BorderRadius.circular(borderRadius), - border: Border.all(color: borderColor), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(platform.icon, size: iconSize, color: iconColor), - if (showLabel) ...[ - const SizedBox(width: 4), - Text( - platform.displayName, - style: TextStyle( - fontSize: compact ? 10 : 11, - fontWeight: FontWeight.w600, - color: iconColor, - ), - ), - ], - const SizedBox(width: 4), - Icon( - isSupported ? Icons.check_circle : Icons.cancel, - size: statusSize, - color: isSupported ? Colors.green : Colors.red.shade300, - ), - ], - ), - ), - ); - } -} - -class SupportBadgesRow extends StatelessWidget { - final Set supportedPlatforms; - final List platforms; - final bool showLabels; - final bool compact; - - const SupportBadgesRow({ - super.key, - required this.supportedPlatforms, - this.platforms = SupportedPlatform.values, - this.showLabels = false, - this.compact = false, - }); - - @override - Widget build(BuildContext context) { - return Wrap( - spacing: compact ? 4 : 6, - runSpacing: compact ? 4 : 6, - children: platforms - .map( - (platform) => SupportBadge( - platform: platform, - isSupported: supportedPlatforms.contains(platform), - showLabel: showLabels, - compact: compact, - ), - ) - .toList(), - ); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/common/test_card.dart b/flutter_inappwebview/example/lib/widgets/common/test_card.dart deleted file mode 100644 index af2af961e7..0000000000 --- a/flutter_inappwebview/example/lib/widgets/common/test_card.dart +++ /dev/null @@ -1,140 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview_example/models/test_case.dart'; - -/// Test status enum -enum TestStatus { none, running, passed, failed } - -/// Widget displaying a test case with run button, status indicator, and expandable details -class TestCard extends StatefulWidget { - final TestCase testCase; - final VoidCallback onRun; - final TestStatus status; - - const TestCard({ - super.key, - required this.testCase, - required this.onRun, - this.status = TestStatus.none, - }); - - @override - State createState() => _TestCardState(); -} - -class _TestCardState extends State { - bool _isExpanded = false; - - @override - Widget build(BuildContext context) { - return Card( - margin: const EdgeInsets.all(8), - child: InkWell( - onTap: () { - setState(() { - _isExpanded = !_isExpanded; - }); - }, - child: Padding( - padding: const EdgeInsets.all(12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.testCase.title, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 4), - Text( - widget.testCase.description, - style: TextStyle( - fontSize: 14, - color: Colors.grey[600], - ), - ), - ], - ), - ), - const SizedBox(width: 8), - _buildStatusIndicator(), - IconButton( - icon: const Icon(Icons.play_arrow), - onPressed: widget.onRun, - color: Theme.of(context).primaryColor, - ), - ], - ), - if (_isExpanded) ...[const Divider(), _buildDetails()], - ], - ), - ), - ), - ); - } - - Widget _buildStatusIndicator() { - switch (widget.status) { - case TestStatus.running: - return const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator(strokeWidth: 2), - ); - case TestStatus.passed: - return const Icon(Icons.check_circle, color: Colors.green); - case TestStatus.failed: - return const Icon(Icons.error, color: Colors.red); - case TestStatus.none: - return const SizedBox.shrink(); - } - } - - Widget _buildDetails() { - return Padding( - padding: const EdgeInsets.only(top: 8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildDetailRow('Category:', widget.testCase.category.name), - const SizedBox(height: 4), - _buildDetailRow('Complexity:', widget.testCase.complexity.name), - const SizedBox(height: 8), - const Text( - 'Supported Platforms:', - style: TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(height: 4), - Wrap( - spacing: 4, - children: widget.testCase.supportedPlatforms - .map( - (p) => Chip( - label: Text(p, style: const TextStyle(fontSize: 12)), - padding: const EdgeInsets.all(2), - ), - ) - .toList(), - ), - ], - ), - ); - } - - Widget _buildDetailRow(String label, String value) { - return Row( - children: [ - Text(label, style: const TextStyle(fontWeight: FontWeight.bold)), - const SizedBox(width: 4), - Text(value), - ], - ); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/settings/responsive_setting_tile.dart b/flutter_inappwebview/example/lib/widgets/settings/responsive_setting_tile.dart deleted file mode 100644 index dd46e4ee88..0000000000 --- a/flutter_inappwebview/example/lib/widgets/settings/responsive_setting_tile.dart +++ /dev/null @@ -1,72 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview_example/utils/responsive_utils.dart'; - -class ResponsiveSettingTile extends StatelessWidget { - const ResponsiveSettingTile({ - super.key, - required this.title, - required this.description, - required this.control, - this.badges, - this.trailing, - this.spacing = 8, - this.inlineControl = false, - }); - - final Widget title; - final Widget description; - final Widget control; - final Widget? badges; - final Widget? trailing; - final double spacing; - final bool inlineControl; - - @override - Widget build(BuildContext context) { - final isMobile = context.isMobile; - - final titleSection = Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded(child: title), - if (trailing != null) trailing!, - ], - ), - const SizedBox(height: 4), - description, - if (badges != null) ...[SizedBox(height: spacing), badges!], - ], - ); - - final controlRow = Row(children: [Expanded(child: control)]); - - if (inlineControl) { - return Row( - key: const ValueKey('responsive_setting_tile_inline_control'), - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded(child: titleSection), - const SizedBox(width: 8), - control, - ], - ); - } - - return Column( - key: ValueKey( - isMobile - ? 'responsive_setting_tile_mobile_layout' - : 'responsive_setting_tile_desktop_layout', - ), - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - titleSection, - SizedBox(height: spacing), - controlRow, - ], - ); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/test_automation/custom_test_step_dialog.dart b/flutter_inappwebview/example/lib/widgets/test_automation/custom_test_step_dialog.dart deleted file mode 100644 index 11e1d9a9a0..0000000000 --- a/flutter_inappwebview/example/lib/widgets/test_automation/custom_test_step_dialog.dart +++ /dev/null @@ -1,1181 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import '../../models/test_configuration.dart'; -import '../../utils/constants.dart'; -import '../../utils/controller_methods_registry.dart'; -import '../../widgets/common/parameter_dialog.dart'; -import '../../widgets/test_automation/method_selector_widget.dart'; - -/// Dialog for creating/editing custom test steps -class CustomTestStepDialog extends StatefulWidget { - final CustomTestStep? existingStep; - final Function(CustomTestStep) onSave; - - const CustomTestStepDialog({ - super.key, - this.existingStep, - required this.onSave, - }); - - @override - State createState() => _CustomTestStepDialogState(); -} - -class _CustomTestStepDialogState extends State { - late final TextEditingController _nameController; - late final TextEditingController _descriptionController; - late final TextEditingController _scriptController; - late final TextEditingController _urlController; - late final TextEditingController _htmlController; - late final TextEditingController _selectorController; - late final TextEditingController _textController; - late final TextEditingController _xController; - late final TextEditingController _yController; - late final TextEditingController _delayController; - late final TextEditingController _expectedResultController; - late final TextEditingController _targetProgressController; - late final TextEditingController _urlPatternController; - - CustomTestActionType _selectedActionType = - CustomTestActionType.evaluateJavascript; - TestCategory _selectedCategory = TestCategory.advanced; - bool _enabled = true; - ExpectedResultType _expectedResultType = ExpectedResultType.any; - - // Controller method selection - ControllerMethodEntry? _selectedMethod; - Map _methodParameters = {}; - - // Navigation event selection - NavigationEventType _selectedNavigationEvent = NavigationEventType.onLoadStop; - String _progressComparison = 'greaterThanOrEquals'; - - @override - void initState() { - super.initState(); - final step = widget.existingStep; - _nameController = TextEditingController(text: step?.name ?? ''); - _descriptionController = TextEditingController( - text: step?.description ?? '', - ); - _scriptController = TextEditingController(text: step?.action.script ?? ''); - _urlController = TextEditingController(text: step?.action.url ?? ''); - _htmlController = TextEditingController(text: step?.action.html ?? ''); - _selectorController = TextEditingController( - text: step?.action.selector ?? '', - ); - _textController = TextEditingController(text: step?.action.text ?? ''); - _xController = TextEditingController( - text: step?.action.x?.toString() ?? '0', - ); - _yController = TextEditingController( - text: step?.action.y?.toString() ?? '0', - ); - _delayController = TextEditingController( - text: step?.action.delayMs?.toString() ?? '1000', - ); - _expectedResultController = TextEditingController( - text: step?.expectedResult ?? '', - ); - _targetProgressController = TextEditingController( - text: step?.action.targetProgress?.toString() ?? '100', - ); - _urlPatternController = TextEditingController( - text: step?.action.urlPattern ?? '', - ); - - if (step != null) { - _selectedActionType = step.action.type; - _selectedCategory = step.category; - _enabled = step.enabled; - _expectedResultType = step.expectedResultType; - - // Load controller method if applicable - if (step.action.type == CustomTestActionType.controllerMethod) { - final methodId = step.action.methodId; - if (methodId != null) { - _selectedMethod = ControllerMethodsRegistry.instance.findMethodById( - methodId, - ); - _methodParameters = Map.from(step.action.methodParameters ?? {}); - } - } - - // Load navigation event settings if applicable - if (step.action.type == CustomTestActionType.waitForNavigationEvent) { - _selectedNavigationEvent = - step.action.navigationEvent ?? NavigationEventType.onLoadStop; - _progressComparison = - step.action.progressComparison ?? 'greaterThanOrEquals'; - } - } - } - - @override - void dispose() { - _nameController.dispose(); - _descriptionController.dispose(); - _scriptController.dispose(); - _urlController.dispose(); - _htmlController.dispose(); - _selectorController.dispose(); - _textController.dispose(); - _xController.dispose(); - _yController.dispose(); - _delayController.dispose(); - _expectedResultController.dispose(); - _targetProgressController.dispose(); - _urlPatternController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final isEditing = widget.existingStep != null; - - return AlertDialog( - title: Text(isEditing ? 'Edit Test Step' : 'Create Test Step'), - content: SizedBox( - width: 500, - child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Basic info - TextField( - controller: _nameController, - decoration: const InputDecoration( - labelText: 'Name *', - hintText: 'Enter test step name', - border: OutlineInputBorder(), - ), - ), - const SizedBox(height: 12), - TextField( - controller: _descriptionController, - decoration: const InputDecoration( - labelText: 'Description', - hintText: 'Describe what this test does', - border: OutlineInputBorder(), - ), - maxLines: 2, - ), - const SizedBox(height: 12), - - // Category dropdown - DropdownButtonFormField( - value: _selectedCategory, - decoration: const InputDecoration( - labelText: 'Category', - border: OutlineInputBorder(), - ), - items: TestCategory.values.map((c) { - return DropdownMenuItem( - value: c, - child: Text( - c.name.substring(0, 1).toUpperCase() + - c.name.substring(1), - ), - ); - }).toList(), - onChanged: (value) { - if (value != null) { - setState(() => _selectedCategory = value); - } - }, - ), - const SizedBox(height: 16), - - // Action type dropdown - const Text( - 'Action Type', - style: TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(height: 8), - DropdownButtonFormField( - value: _selectedActionType, - decoration: const InputDecoration(border: OutlineInputBorder()), - items: CustomTestActionType.values.map((type) { - return DropdownMenuItem( - value: type, - child: Text(_getActionTypeName(type)), - ); - }).toList(), - onChanged: (value) { - if (value != null) { - setState(() => _selectedActionType = value); - } - }, - ), - const SizedBox(height: 16), - - // Action-specific fields - ..._buildActionFields(), - - const SizedBox(height: 16), - const Text( - 'Expected Result Validation', - style: TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(height: 8), - DropdownButtonFormField( - value: _expectedResultType, - decoration: const InputDecoration( - labelText: 'Validation Type', - border: OutlineInputBorder(), - ), - items: ExpectedResultType.values.map((type) { - return DropdownMenuItem( - value: type, - child: Text(_getExpectedResultTypeName(type)), - ); - }).toList(), - onChanged: (value) { - if (value != null) { - setState(() => _expectedResultType = value); - } - }, - ), - if (_needsExpectedResultValue(_expectedResultType)) ...[ - const SizedBox(height: 12), - TextField( - controller: _expectedResultController, - decoration: InputDecoration( - labelText: _getExpectedResultLabel(_expectedResultType), - hintText: _getExpectedResultHint(_expectedResultType), - border: const OutlineInputBorder(), - ), - maxLines: - _expectedResultType == ExpectedResultType.regex || - _expectedResultType == - ExpectedResultType.customExpression - ? 3 - : 1, - style: - _expectedResultType == ExpectedResultType.regex || - _expectedResultType == - ExpectedResultType.customExpression - ? const TextStyle(fontFamily: 'monospace') - : null, - ), - ], - const SizedBox(height: 8), - Text( - _getExpectedResultTypeDescription(_expectedResultType), - style: TextStyle( - fontSize: 12, - color: Colors.grey.shade600, - fontStyle: FontStyle.italic, - ), - ), - const SizedBox(height: 12), - - // Enabled switch - SwitchListTile( - title: const Text('Enabled'), - subtitle: const Text('Include this step in test runs'), - value: _enabled, - onChanged: (value) { - setState(() => _enabled = value); - }, - contentPadding: EdgeInsets.zero, - ), - ], - ), - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: _saveStep, - child: Text(isEditing ? 'Update' : 'Create'), - ), - ], - ); - } - - List _buildActionFields() { - switch (_selectedActionType) { - case CustomTestActionType.evaluateJavascript: - return [ - TextField( - controller: _scriptController, - decoration: const InputDecoration( - labelText: 'JavaScript Code *', - hintText: 'Enter JavaScript to evaluate', - border: OutlineInputBorder(), - ), - maxLines: 5, - style: const TextStyle(fontFamily: 'monospace'), - ), - ]; - - case CustomTestActionType.loadUrl: - return [ - TextField( - controller: _urlController, - decoration: const InputDecoration( - labelText: 'URL *', - hintText: 'https://example.com', - border: OutlineInputBorder(), - ), - ), - ]; - - case CustomTestActionType.loadHtml: - return [ - TextField( - controller: _htmlController, - decoration: const InputDecoration( - labelText: 'HTML Content *', - hintText: '...', - border: OutlineInputBorder(), - ), - maxLines: 5, - style: const TextStyle(fontFamily: 'monospace'), - ), - ]; - - case CustomTestActionType.checkUrl: - return [ - TextField( - controller: _urlController, - decoration: const InputDecoration( - labelText: 'Expected URL (partial match) *', - hintText: 'example.com', - border: OutlineInputBorder(), - ), - ), - ]; - - case CustomTestActionType.checkTitle: - return [ - TextField( - controller: _textController, - decoration: const InputDecoration( - labelText: 'Expected Title *', - hintText: 'Page Title', - border: OutlineInputBorder(), - ), - ), - ]; - - case CustomTestActionType.checkElement: - case CustomTestActionType.waitForElement: - case CustomTestActionType.clickElement: - return [ - TextField( - controller: _selectorController, - decoration: const InputDecoration( - labelText: 'CSS Selector *', - hintText: '#myElement or .myClass', - border: OutlineInputBorder(), - ), - ), - if (_selectedActionType == CustomTestActionType.waitForElement) ...[ - const SizedBox(height: 12), - TextField( - controller: _delayController, - decoration: const InputDecoration( - labelText: 'Timeout (ms)', - border: OutlineInputBorder(), - ), - keyboardType: TextInputType.number, - inputFormatters: [FilteringTextInputFormatter.digitsOnly], - ), - ], - ]; - - case CustomTestActionType.typeText: - return [ - TextField( - controller: _selectorController, - decoration: const InputDecoration( - labelText: 'CSS Selector *', - hintText: '#inputField', - border: OutlineInputBorder(), - ), - ), - const SizedBox(height: 12), - TextField( - controller: _textController, - decoration: const InputDecoration( - labelText: 'Text to Type *', - hintText: 'Hello World', - border: OutlineInputBorder(), - ), - ), - ]; - - case CustomTestActionType.scrollTo: - return [ - Row( - children: [ - Expanded( - child: TextField( - controller: _xController, - decoration: const InputDecoration( - labelText: 'X Position', - border: OutlineInputBorder(), - ), - keyboardType: TextInputType.number, - inputFormatters: [FilteringTextInputFormatter.digitsOnly], - ), - ), - const SizedBox(width: 12), - Expanded( - child: TextField( - controller: _yController, - decoration: const InputDecoration( - labelText: 'Y Position', - border: OutlineInputBorder(), - ), - keyboardType: TextInputType.number, - inputFormatters: [FilteringTextInputFormatter.digitsOnly], - ), - ), - ], - ), - ]; - - case CustomTestActionType.delay: - return [ - TextField( - controller: _delayController, - decoration: const InputDecoration( - labelText: 'Delay (milliseconds) *', - hintText: '1000', - border: OutlineInputBorder(), - ), - keyboardType: TextInputType.number, - inputFormatters: [FilteringTextInputFormatter.digitsOnly], - ), - ]; - - case CustomTestActionType.takeScreenshot: - return [ - const Text( - 'No additional configuration needed.\nScreenshot will be captured and returned.', - style: TextStyle(fontStyle: FontStyle.italic), - ), - ]; - - case CustomTestActionType.custom: - return [ - TextField( - controller: _scriptController, - decoration: const InputDecoration( - labelText: 'Custom JavaScript Code *', - hintText: - 'return { passed: true, message: "Custom test passed" };', - border: OutlineInputBorder(), - ), - maxLines: 8, - style: const TextStyle(fontFamily: 'monospace'), - ), - ]; - - case CustomTestActionType.waitForNavigationEvent: - return _buildWaitForNavigationEventFields(); - - case CustomTestActionType.controllerMethod: - return _buildControllerMethodFields(); - } - } - - List _buildWaitForNavigationEventFields() { - return [ - // Navigation event selector - DropdownButtonFormField( - value: _selectedNavigationEvent, - decoration: const InputDecoration( - labelText: 'Navigation Event', - border: OutlineInputBorder(), - ), - items: NavigationEventType.values.map((event) { - return DropdownMenuItem( - value: event, - child: Text(_getNavigationEventName(event)), - ); - }).toList(), - onChanged: (value) { - if (value != null) { - setState(() => _selectedNavigationEvent = value); - } - }, - ), - const SizedBox(height: 12), - - // Progress-specific options (only for onProgressChanged) - if (_selectedNavigationEvent == - NavigationEventType.onProgressChanged) ...[ - Row( - children: [ - Expanded( - flex: 2, - child: DropdownButtonFormField( - value: _progressComparison, - decoration: const InputDecoration( - labelText: 'Condition', - border: OutlineInputBorder(), - ), - items: const [ - DropdownMenuItem(value: 'equals', child: Text('Equals')), - DropdownMenuItem( - value: 'greaterThan', - child: Text('Greater than'), - ), - DropdownMenuItem( - value: 'greaterThanOrEquals', - child: Text('Greater than or equals'), - ), - DropdownMenuItem(value: 'lessThan', child: Text('Less than')), - ], - onChanged: (value) { - if (value != null) { - setState(() => _progressComparison = value); - } - }, - ), - ), - const SizedBox(width: 12), - Expanded( - child: TextField( - controller: _targetProgressController, - decoration: const InputDecoration( - labelText: 'Progress (%)', - border: OutlineInputBorder(), - hintText: '100', - ), - keyboardType: TextInputType.number, - inputFormatters: [FilteringTextInputFormatter.digitsOnly], - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - 'Wait until progress ${_getComparisonDescription(_progressComparison)} the specified value', - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - const SizedBox(height: 12), - ], - - // URL pattern (optional) - TextField( - controller: _urlPatternController, - decoration: const InputDecoration( - labelText: 'URL Pattern (optional)', - hintText: 'example.com or regex pattern', - border: OutlineInputBorder(), - helperText: 'Only trigger when URL contains this text', - ), - ), - const SizedBox(height: 8), - Text( - _getNavigationEventDescription(_selectedNavigationEvent), - style: TextStyle( - fontSize: 12, - color: Colors.grey.shade600, - fontStyle: FontStyle.italic, - ), - ), - ]; - } - - String _getNavigationEventName(NavigationEventType event) { - switch (event) { - case NavigationEventType.onLoadStop: - return 'onLoadStop (Page Finished Loading)'; - case NavigationEventType.onLoadStart: - return 'onLoadStart (Page Started Loading)'; - case NavigationEventType.onProgressChanged: - return 'onProgressChanged (Loading Progress)'; - case NavigationEventType.onPageCommitVisible: - return 'onPageCommitVisible (First Paint)'; - case NavigationEventType.onTitleChanged: - return 'onTitleChanged (Title Updated)'; - case NavigationEventType.onUpdateVisitedHistory: - return 'onUpdateVisitedHistory (History Updated)'; - } - } - - String _getNavigationEventDescription(NavigationEventType event) { - switch (event) { - case NavigationEventType.onLoadStop: - return 'Waits for the page to finish loading completely'; - case NavigationEventType.onLoadStart: - return 'Waits for a new page navigation to begin'; - case NavigationEventType.onProgressChanged: - return 'Waits for the loading progress to reach a specific value'; - case NavigationEventType.onPageCommitVisible: - return 'Waits for the first content to become visible'; - case NavigationEventType.onTitleChanged: - return 'Waits for the page title to change'; - case NavigationEventType.onUpdateVisitedHistory: - return 'Waits for the browser history to be updated'; - } - } - - String _getComparisonDescription(String comparison) { - switch (comparison) { - case 'equals': - return 'equals'; - case 'greaterThan': - return 'is greater than'; - case 'greaterThanOrEquals': - return 'is greater than or equal to'; - case 'lessThan': - return 'is less than'; - default: - return comparison; - } - } - - List _buildControllerMethodFields() { - return [ - // Method selector - const Text( - 'Select Controller Method', - style: TextStyle(fontWeight: FontWeight.w500), - ), - const SizedBox(height: 8), - InkWell( - onTap: () => _showMethodPickerDialog(), - child: Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey.shade400), - borderRadius: BorderRadius.circular(4), - ), - child: Row( - children: [ - const Icon(Icons.code, color: Colors.blue), - const SizedBox(width: 12), - Expanded( - child: _selectedMethod != null - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - _selectedMethod!.name, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - Text( - _selectedMethod!.description, - style: TextStyle( - fontSize: 12, - color: Colors.grey.shade600, - ), - ), - ], - ) - : Text( - 'Select a controller method...', - style: TextStyle(color: Colors.grey.shade600), - ), - ), - const Icon(Icons.arrow_drop_down), - ], - ), - ), - ), - - // Parameters section - if (_selectedMethod != null && - _selectedMethod!.parameters.isNotEmpty) ...[ - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Method Parameters', - style: TextStyle(fontWeight: FontWeight.w500), - ), - TextButton.icon( - icon: const Icon(Icons.edit, size: 16), - label: const Text('Configure'), - onPressed: () => _showParameterDialog(), - ), - ], - ), - const SizedBox(height: 8), - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.grey.shade100, - borderRadius: BorderRadius.circular(4), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: _selectedMethod!.parameters.entries.map((entry) { - final value = _methodParameters[entry.key] ?? entry.value; - return Padding( - padding: const EdgeInsets.symmetric(vertical: 2), - child: Row( - children: [ - Text( - '${entry.key}: ', - style: const TextStyle( - fontFamily: 'monospace', - fontWeight: FontWeight.w500, - ), - ), - Expanded( - child: Text( - _formatParameterValue(value), - style: TextStyle( - fontFamily: 'monospace', - color: Colors.grey.shade700, - ), - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - ); - }).toList(), - ), - ), - ], - ]; - } - - String _formatParameterValue(dynamic value) { - if (value == null) return 'null'; - if (value is String) return '"$value"'; - if (value is Map) return '{...}'; - if (value is List) return '[${value.length} items]'; - if (value is ParameterValueHint) return _formatParameterValue(value.value); - return value.toString(); - } - - Future _showMethodPickerDialog() async { - final result = await showMethodPickerDialog( - context: context, - selectedMethodId: _selectedMethod?.id, - title: 'Select Controller Method', - ); - - if (result != null) { - setState(() { - _selectedMethod = result; - _methodParameters = Map.from(result.parameters); - }); - } - } - - Future _showParameterDialog() async { - if (_selectedMethod == null) return; - - // Merge current values into parameters intelligently - final params = {}; - - _selectedMethod!.parameters.forEach((key, defValue) { - if (_methodParameters.containsKey(key)) { - final currentValue = _methodParameters[key]; - - // If definition is a Hint, we need to wrap the currentValue in a Hint - if (defValue is ParameterValueHint) { - if (defValue is EnumParameterValueHint) { - dynamic typedValue = currentValue; - if (currentValue is String) { - try { - typedValue = defValue.enumValues.firstWhere( - (e) => _getEnumName(e) == currentValue, - orElse: () { - // Try case-insensitive matching if exact match fails - try { - return defValue.enumValues.firstWhere( - (e) => - _getEnumName(e).toLowerCase() == - currentValue.toLowerCase(), - ); - } catch (_) { - // If no match found, fallback to the default value from definition - // This prevents "There should be exactly one item..." errors in DropdownButton - return defValue.value; - } - }, - ); - } catch (_) { - // Should not happen due to nested try/catch but safe fallback - typedValue = defValue.value; - } - } - - // Access displayName dynamically to avoid type errors - // caused by contravariance in function arguments (e.g. UserScriptInjectionTime vs dynamic) - final dynamic displayNameFunc = (defValue as dynamic).displayName; - - // Create a new hint with the current value - // We use dynamic to bypass strict type checks when recreating - params[key] = EnumParameterValueHint( - typedValue, - defValue.enumValues, - displayName: displayNameFunc != null - ? (e) => displayNameFunc(e) as String - : null, - ); - } else { - params[key] = ParameterValueHint(currentValue, defValue.type); - } - } else { - params[key] = currentValue; - } - } else { - // Use default from definition - params[key] = defValue; - } - }); - - // Add any extra parameters that might exist in _methodParameters but not in definition - _methodParameters.forEach((key, value) { - if (!params.containsKey(key)) { - params[key] = value; - } - }); - - final result = await showParameterDialog( - context: context, - title: '${_selectedMethod!.name} Parameters', - parameters: params, - requiredPaths: _selectedMethod!.requiredParameters, - ); - - if (result != null) { - setState(() { - _methodParameters = result; - }); - } - } - - String _getEnumName(dynamic e) { - if (e == null) return ''; - try { - final dynamic result = (e as dynamic).name(); - if (result is String) return result; - } catch (_) {} - try { - final dynamic result = (e as dynamic).name; - if (result is String) return result; - } catch (_) {} - return e.toString(); - } - - String _getActionTypeName(CustomTestActionType type) { - switch (type) { - case CustomTestActionType.evaluateJavascript: - return 'Evaluate JavaScript'; - case CustomTestActionType.loadUrl: - return 'Load URL'; - case CustomTestActionType.loadHtml: - return 'Load HTML'; - case CustomTestActionType.checkUrl: - return 'Check URL'; - case CustomTestActionType.checkTitle: - return 'Check Title'; - case CustomTestActionType.checkElement: - return 'Check Element Exists'; - case CustomTestActionType.waitForElement: - return 'Wait for Element'; - case CustomTestActionType.clickElement: - return 'Click Element'; - case CustomTestActionType.typeText: - return 'Type Text'; - case CustomTestActionType.scrollTo: - return 'Scroll To'; - case CustomTestActionType.takeScreenshot: - return 'Take Screenshot'; - case CustomTestActionType.delay: - return 'Delay/Wait'; - case CustomTestActionType.waitForNavigationEvent: - return 'Wait for Navigation Event'; - case CustomTestActionType.controllerMethod: - return 'Controller Method'; - case CustomTestActionType.custom: - return 'Custom Action'; - } - } - - String _getExpectedResultTypeName(ExpectedResultType type) { - switch (type) { - case ExpectedResultType.any: - return 'Any (No Validation)'; - case ExpectedResultType.exact: - return 'Exact Match'; - case ExpectedResultType.contains: - return 'Contains (Case Sensitive)'; - case ExpectedResultType.containsIgnoreCase: - return 'Contains (Case Insensitive)'; - case ExpectedResultType.regex: - return 'Regex Pattern'; - case ExpectedResultType.notNull: - return 'Not Null'; - case ExpectedResultType.isNull: - return 'Is Null'; - case ExpectedResultType.truthy: - return 'Truthy Value'; - case ExpectedResultType.falsy: - return 'Falsy Value'; - case ExpectedResultType.typeIs: - return 'Type Check'; - case ExpectedResultType.notEmpty: - return 'Not Empty'; - case ExpectedResultType.hasKey: - return 'Has Key (Map)'; - case ExpectedResultType.lengthEquals: - return 'Length Equals'; - case ExpectedResultType.greaterThan: - return 'Greater Than'; - case ExpectedResultType.lessThan: - return 'Less Than'; - case ExpectedResultType.customExpression: - return 'Custom Expression'; - } - } - - String _getExpectedResultTypeDescription(ExpectedResultType type) { - switch (type) { - case ExpectedResultType.any: - return 'Test passes as long as it executes without errors'; - case ExpectedResultType.exact: - return 'Result must exactly match the expected value (as string)'; - case ExpectedResultType.contains: - return 'Result string must contain the expected value'; - case ExpectedResultType.containsIgnoreCase: - return 'Result string must contain the expected value (ignoring case)'; - case ExpectedResultType.regex: - return 'Result must match the regular expression pattern'; - case ExpectedResultType.notNull: - return 'Result must not be null'; - case ExpectedResultType.isNull: - return 'Result must be null'; - case ExpectedResultType.truthy: - return 'Result must be truthy (not null, false, 0, or empty)'; - case ExpectedResultType.falsy: - return 'Result must be falsy (null, false, 0, or empty)'; - case ExpectedResultType.typeIs: - return 'Result type must match (e.g., String, int, Map, List)'; - case ExpectedResultType.notEmpty: - return 'Result must not be empty (string, list, or map)'; - case ExpectedResultType.hasKey: - return 'Result Map must contain the specified key'; - case ExpectedResultType.lengthEquals: - return 'Result length must equal the specified number'; - case ExpectedResultType.greaterThan: - return 'Numeric result must be greater than the expected value'; - case ExpectedResultType.lessThan: - return 'Numeric result must be less than the expected value'; - case ExpectedResultType.customExpression: - return 'Custom JavaScript expression (receives "result" variable)'; - } - } - - bool _needsExpectedResultValue(ExpectedResultType type) { - switch (type) { - case ExpectedResultType.any: - case ExpectedResultType.notNull: - case ExpectedResultType.isNull: - case ExpectedResultType.truthy: - case ExpectedResultType.falsy: - case ExpectedResultType.notEmpty: - return false; - default: - return true; - } - } - - String _getExpectedResultLabel(ExpectedResultType type) { - switch (type) { - case ExpectedResultType.exact: - return 'Expected Value'; - case ExpectedResultType.contains: - case ExpectedResultType.containsIgnoreCase: - return 'Contains Text'; - case ExpectedResultType.regex: - return 'Regex Pattern'; - case ExpectedResultType.typeIs: - return 'Type Name'; - case ExpectedResultType.hasKey: - return 'Key Name'; - case ExpectedResultType.lengthEquals: - return 'Expected Length'; - case ExpectedResultType.greaterThan: - case ExpectedResultType.lessThan: - return 'Comparison Value'; - case ExpectedResultType.customExpression: - return 'JavaScript Expression'; - default: - return 'Expected Value'; - } - } - - String _getExpectedResultHint(ExpectedResultType type) { - switch (type) { - case ExpectedResultType.exact: - return 'Enter the exact expected result'; - case ExpectedResultType.contains: - case ExpectedResultType.containsIgnoreCase: - return 'Enter text to search for'; - case ExpectedResultType.regex: - return '^https?://.*\\.com\$'; - case ExpectedResultType.typeIs: - return 'String, int, Map, List, etc.'; - case ExpectedResultType.hasKey: - return 'Key name to check'; - case ExpectedResultType.lengthEquals: - return '10'; - case ExpectedResultType.greaterThan: - case ExpectedResultType.lessThan: - return 'Numeric value'; - case ExpectedResultType.customExpression: - return 'return result != null && result.length > 0;'; - default: - return ''; - } - } - - void _saveStep() { - final name = _nameController.text.trim(); - if (name.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Please enter a name for the test step')), - ); - return; - } - - final action = _buildAction(); - if (action == null) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Please fill in required fields')), - ); - return; - } - - // Validate expected result if needed - if (_needsExpectedResultValue(_expectedResultType) && - _expectedResultController.text.trim().isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Please provide an expected result value'), - ), - ); - return; - } - - final step = CustomTestStep( - id: - widget.existingStep?.id ?? - 'step_${DateTime.now().millisecondsSinceEpoch}', - name: name, - description: _descriptionController.text.trim(), - category: _selectedCategory, - action: action, - expectedResult: _expectedResultController.text.trim().isNotEmpty - ? _expectedResultController.text.trim() - : null, - expectedResultType: _expectedResultType, - enabled: _enabled, - order: widget.existingStep?.order ?? 0, - ); - - widget.onSave(step); - Navigator.pop(context); - } - - CustomTestAction? _buildAction() { - switch (_selectedActionType) { - case CustomTestActionType.evaluateJavascript: - final script = _scriptController.text.trim(); - if (script.isEmpty) return null; - return CustomTestAction.evaluateJs(script); - - case CustomTestActionType.loadUrl: - final url = _urlController.text.trim(); - if (url.isEmpty) return null; - return CustomTestAction.loadUrl(url); - - case CustomTestActionType.loadHtml: - final html = _htmlController.text.trim(); - if (html.isEmpty) return null; - return CustomTestAction.loadHtml(html); - - case CustomTestActionType.checkUrl: - final url = _urlController.text.trim(); - if (url.isEmpty) return null; - return CustomTestAction.checkUrl(url); - - case CustomTestActionType.checkTitle: - final title = _textController.text.trim(); - if (title.isEmpty) return null; - return CustomTestAction.checkTitle(title); - - case CustomTestActionType.checkElement: - final selector = _selectorController.text.trim(); - if (selector.isEmpty) return null; - return CustomTestAction.checkElement(selector); - - case CustomTestActionType.waitForElement: - final selector = _selectorController.text.trim(); - if (selector.isEmpty) return null; - final timeout = int.tryParse(_delayController.text) ?? 5000; - return CustomTestAction.waitForElement(selector, timeoutMs: timeout); - - case CustomTestActionType.clickElement: - final selector = _selectorController.text.trim(); - if (selector.isEmpty) return null; - return CustomTestAction.clickElement(selector); - - case CustomTestActionType.typeText: - final selector = _selectorController.text.trim(); - final text = _textController.text; - if (selector.isEmpty || text.isEmpty) return null; - return CustomTestAction.typeText(selector, text); - - case CustomTestActionType.scrollTo: - final x = int.tryParse(_xController.text) ?? 0; - final y = int.tryParse(_yController.text) ?? 0; - return CustomTestAction.scrollTo(x, y); - - case CustomTestActionType.takeScreenshot: - return const CustomTestAction( - type: CustomTestActionType.takeScreenshot, - ); - - case CustomTestActionType.delay: - final delay = int.tryParse(_delayController.text); - if (delay == null || delay <= 0) return null; - return CustomTestAction.delay(delay); - - case CustomTestActionType.waitForNavigationEvent: - final targetProgress = int.tryParse(_targetProgressController.text); - final urlPattern = _urlPatternController.text.trim(); - return CustomTestAction.waitForNavigationEvent( - _selectedNavigationEvent, - targetProgress: targetProgress, - progressComparison: _progressComparison, - urlPattern: urlPattern.isNotEmpty ? urlPattern : null, - ); - - case CustomTestActionType.custom: - final code = _scriptController.text.trim(); - if (code.isEmpty) return null; - return CustomTestAction( - type: CustomTestActionType.custom, - customCode: code, - ); - - case CustomTestActionType.controllerMethod: - if (_selectedMethod == null) return null; - return CustomTestAction.controllerMethod( - _selectedMethod!.id, - parameters: _methodParameters.isNotEmpty ? _methodParameters : null, - ); - } - } -} diff --git a/flutter_inappwebview/example/lib/widgets/test_automation/method_selector_widget.dart b/flutter_inappwebview/example/lib/widgets/test_automation/method_selector_widget.dart deleted file mode 100644 index db497f507b..0000000000 --- a/flutter_inappwebview/example/lib/widgets/test_automation/method_selector_widget.dart +++ /dev/null @@ -1,476 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview_example/utils/controller_methods_registry.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_card.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; - -/// A widget that allows users to select a controller method and configure its parameters -class MethodSelectorWidget extends StatefulWidget { - /// The currently selected method ID - final String? selectedMethodId; - - /// The current parameters for the selected method - final Map parameters; - - /// Called when a method is selected - final ValueChanged onMethodSelected; - - /// Called when parameters are updated - final ValueChanged> onParametersChanged; - - const MethodSelectorWidget({ - super.key, - this.selectedMethodId, - this.parameters = const {}, - required this.onMethodSelected, - required this.onParametersChanged, - }); - - @override - State createState() => _MethodSelectorWidgetState(); -} - -class _MethodSelectorWidgetState extends State { - final _searchController = TextEditingController(); - String _searchQuery = ''; - ControllerMethodEntry? _selectedMethod; - Map _parameters = {}; - - @override - void initState() { - super.initState(); - _parameters = Map.from(widget.parameters); - if (widget.selectedMethodId != null) { - _selectedMethod = ControllerMethodsRegistry.instance.findMethodById( - widget.selectedMethodId!, - ); - } - } - - @override - void dispose() { - _searchController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final registry = ControllerMethodsRegistry.instance; - final filteredCategories = registry.searchCategories(_searchQuery); - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Selected method display - if (_selectedMethod != null) ...[ - _buildSelectedMethodCard(), - const SizedBox(height: 16), - ], - - // Search and selection - TextField( - controller: _searchController, - decoration: InputDecoration( - labelText: 'Search Methods', - hintText: 'Type to search...', - prefixIcon: const Icon(Icons.search), - suffixIcon: _searchQuery.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear), - onPressed: () { - _searchController.clear(); - setState(() => _searchQuery = ''); - }, - ) - : null, - border: const OutlineInputBorder(), - ), - onChanged: (value) { - setState(() => _searchQuery = value); - }, - ), - const SizedBox(height: 12), - - // Method categories list - Expanded( - child: filteredCategories.isEmpty - ? const Center(child: Text('No methods found')) - : ListView.builder( - itemCount: filteredCategories.length, - itemBuilder: (context, index) { - final category = filteredCategories[index]; - return _buildCategorySection(category); - }, - ), - ), - ], - ); - } - - Widget _buildSelectedMethodCard() { - final method = _selectedMethod!; - return MethodCard( - methodName: method.name, - description: method.description, - leading: const Icon(Icons.check_circle, color: Colors.green), - backgroundColor: Theme.of(context).colorScheme.primaryContainer, - trailing: IconButton( - icon: const Icon(Icons.close), - onPressed: () { - setState(() { - _selectedMethod = null; - _parameters = {}; - }); - widget.onMethodSelected(null); - widget.onParametersChanged({}); - }, - tooltip: 'Clear selection', - ), - extraContent: method.parameters.isNotEmpty - ? _buildParametersSection() - : null, - ); - } - - Widget _buildParametersSection() { - final method = _selectedMethod!; - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('Parameters', style: Theme.of(context).textTheme.titleSmall), - TextButton.icon( - icon: const Icon(Icons.edit, size: 16), - label: const Text('Configure'), - onPressed: () => _showParameterDialog(), - ), - ], - ), - if (_parameters.isNotEmpty) - ...method.parameters.entries - .where((e) => _parameters.containsKey(e.key)) - .map( - (e) => Padding( - padding: const EdgeInsets.symmetric(vertical: 2), - child: Row( - children: [ - Text( - '${e.key}: ', - style: const TextStyle(fontWeight: FontWeight.w500), - ), - Expanded( - child: Text( - _formatParameterValue(_parameters[e.key]), - style: Theme.of(context).textTheme.bodySmall, - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - ), - ) - else - Text( - 'Using default values', - style: Theme.of( - context, - ).textTheme.bodySmall?.copyWith(fontStyle: FontStyle.italic), - ), - ], - ); - } - - String _formatParameterValue(dynamic value) { - if (value == null) return 'null'; - if (value is String) return '"$value"'; - if (value is Map) return '{...}'; - if (value is List) return '[${value.length} items]'; - return value.toString(); - } - - Widget _buildCategorySection(ControllerMethodCategory category) { - return ExpansionTile( - leading: Icon(category.icon), - title: Text(category.name), - subtitle: Text('${category.methods.length} methods'), - children: category.methods.map((method) { - final isSelected = _selectedMethod?.id == method.id; - return ListTile( - selected: isSelected, - leading: isSelected - ? const Icon(Icons.check_circle, color: Colors.green) - : const Icon(Icons.code), - title: Text(method.name), - subtitle: Text( - method.description, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - trailing: method.parameters.isNotEmpty - ? Chip( - label: Text('${method.parameters.length} params'), - visualDensity: VisualDensity.compact, - ) - : null, - onTap: () => _selectMethod(method), - ); - }).toList(), - ); - } - - void _selectMethod(ControllerMethodEntry method) { - setState(() { - _selectedMethod = method; - _parameters = Map.from(method.parameters); - }); - widget.onMethodSelected(method); - widget.onParametersChanged(_parameters); - } - - Future _showParameterDialog() async { - if (_selectedMethod == null) return; - - // Merge current values into parameters - final params = { - ..._selectedMethod!.parameters, - ..._parameters, - }; - - final result = await showParameterDialog( - context: context, - title: '${_selectedMethod!.name} Parameters', - parameters: params, - requiredPaths: _selectedMethod!.requiredParameters, - ); - - if (result != null) { - setState(() { - _parameters = result; - }); - widget.onParametersChanged(result); - } - } -} - -/// A compact method selector for use in dialogs -class CompactMethodSelector extends StatelessWidget { - final String? selectedMethodId; - final ValueChanged onMethodSelected; - - const CompactMethodSelector({ - super.key, - this.selectedMethodId, - required this.onMethodSelected, - }); - - @override - Widget build(BuildContext context) { - final registry = ControllerMethodsRegistry.instance; - final selectedMethod = selectedMethodId != null - ? registry.findMethodById(selectedMethodId!) - : null; - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Controller Method', - style: Theme.of(context).textTheme.titleSmall, - ), - const SizedBox(height: 8), - InkWell( - onTap: () => _showMethodPickerDialog(context), - child: Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - border: Border.all(color: Theme.of(context).dividerColor), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - const Icon(Icons.code), - const SizedBox(width: 12), - Expanded( - child: selectedMethod != null - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - selectedMethod.name, - style: const TextStyle( - fontWeight: FontWeight.bold, - ), - ), - Text( - selectedMethod.description, - style: Theme.of(context).textTheme.bodySmall, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ], - ) - : const Text('Select a method...'), - ), - const Icon(Icons.arrow_drop_down), - ], - ), - ), - ), - ], - ); - } - - Future _showMethodPickerDialog(BuildContext context) async { - final result = await showMethodPickerDialog( - context: context, - selectedMethodId: selectedMethodId, - ); - - onMethodSelected(result); - } -} - -/// Shows a dialog for picking a controller method. -/// -/// Returns the selected [ControllerMethodEntry] or null if cancelled. -Future showMethodPickerDialog({ - required BuildContext context, - String? selectedMethodId, - String title = 'Select Method', -}) { - return showDialog( - context: context, - builder: (context) => - MethodPickerDialog(selectedMethodId: selectedMethodId, title: title), - ); -} - -/// Dialog for picking a controller method from the registry. -/// -/// Displays categorized methods with search functionality. -class MethodPickerDialog extends StatefulWidget { - /// The currently selected method ID, if any. - final String? selectedMethodId; - - /// The title to display in the dialog. - final String title; - - const MethodPickerDialog({ - super.key, - this.selectedMethodId, - this.title = 'Select Method', - }); - - @override - State createState() => _MethodPickerDialogState(); -} - -class _MethodPickerDialogState extends State { - final _searchController = TextEditingController(); - String _searchQuery = ''; - - @override - void dispose() { - _searchController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final registry = ControllerMethodsRegistry.instance; - final filteredCategories = registry.searchCategories(_searchQuery); - - return AlertDialog( - title: Text(widget.title), - content: SizedBox( - width: double.maxFinite, - height: 400, - child: Column( - children: [ - TextField( - controller: _searchController, - decoration: InputDecoration( - hintText: 'Search methods...', - prefixIcon: const Icon(Icons.search), - suffixIcon: _searchQuery.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear), - onPressed: () { - _searchController.clear(); - setState(() => _searchQuery = ''); - }, - ) - : null, - border: const OutlineInputBorder(), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - ), - onChanged: (value) { - setState(() => _searchQuery = value); - }, - ), - const SizedBox(height: 12), - Expanded( - child: filteredCategories.isEmpty - ? const Center(child: Text('No methods found')) - : ListView.builder( - itemCount: filteredCategories.length, - itemBuilder: (context, index) { - final category = filteredCategories[index]; - return ExpansionTile( - leading: Icon(category.icon, size: 20), - title: Text( - category.name, - style: const TextStyle(fontSize: 14), - ), - subtitle: Text('${category.methods.length} methods'), - children: category.methods.map((method) { - final isSelected = - widget.selectedMethodId == method.id; - return ListTile( - dense: true, - selected: isSelected, - leading: isSelected - ? const Icon( - Icons.check_circle, - color: Colors.green, - size: 20, - ) - : const Icon(Icons.code, size: 20), - title: Text(method.name), - subtitle: Text( - method.description, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontSize: 11), - ), - trailing: method.parameters.isNotEmpty - ? Chip( - label: Text( - '${method.parameters.length}', - ), - visualDensity: VisualDensity.compact, - ) - : null, - onTap: () => Navigator.of(context).pop(method), - ); - }).toList(), - ); - }, - ), - ), - ], - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(), - child: const Text('Cancel'), - ), - ], - ); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/webview/event_console_widget.dart b/flutter_inappwebview/example/lib/widgets/webview/event_console_widget.dart deleted file mode 100644 index b9a247116e..0000000000 --- a/flutter_inappwebview/example/lib/widgets/webview/event_console_widget.dart +++ /dev/null @@ -1,238 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/models/event_log_entry.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; - -/// Widget to display WebView event logs in a console-like interface -class EventConsoleWidget extends StatefulWidget { - const EventConsoleWidget({super.key}); - - @override - State createState() => _EventConsoleWidgetState(); -} - -class _EventConsoleWidgetState extends State { - EventType? _selectedFilter; - - @override - Widget build(BuildContext context) { - return CustomScrollView( - slivers: [ - SliverPersistentHeader( - pinned: true, - delegate: _StickyHeaderDelegate( - minHeight: 70, - maxHeight: 70, - child: _buildHeader(), - ), - ), - _buildEventList(), - ], - ); - } - - Widget _buildHeader() { - return Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: Colors.grey.shade100, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: Row( - children: [ - const Text( - 'Events', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), - ), - const SizedBox(width: 16), - Expanded(child: _buildFilterDropdown()), - IconButton( - icon: const Icon(Icons.clear_all), - tooltip: 'Clear', - onPressed: () { - context.read().clear(); - }, - ), - ], - ), - ); - } - - Widget _buildFilterDropdown() { - return DropdownButton( - value: _selectedFilter, - isExpanded: true, - hint: const Text('All Events'), - items: [ - const DropdownMenuItem( - value: null, - child: Text('All Events'), - ), - ...EventType.values.map((type) { - return DropdownMenuItem( - value: type, - child: Text(type.name), - ); - }), - ], - onChanged: (value) { - setState(() { - _selectedFilter = value; - }); - }, - ); - } - - Widget _buildEventList() { - return Consumer( - builder: (context, provider, child) { - final events = _selectedFilter == null - ? provider.events - : provider.filterByType(_selectedFilter); - - if (events.isEmpty) { - return const SliverFillRemaining( - hasScrollBody: false, - child: Center( - child: Text( - 'No events logged yet', - style: TextStyle(color: Colors.grey), - ), - ), - ); - } - - return SliverList( - delegate: SliverChildBuilderDelegate((context, index) { - final event = events[events.length - 1 - index]; - return _buildEventItem(event); - }, childCount: events.length), - ); - }, - ); - } - - Widget _buildEventItem(EventLogEntry event) { - final timeFormat = DateFormat('HH:mm:ss.SSS'); - - return Card( - margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - child: ExpansionTile( - leading: Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: _getEventTypeColor(event.eventType), - borderRadius: BorderRadius.circular(4), - ), - child: Text( - event.eventType.name, - style: const TextStyle(fontSize: 10, fontWeight: FontWeight.bold), - ), - ), - title: Text(event.message, style: const TextStyle(fontSize: 14)), - subtitle: Text( - timeFormat.format(event.timestamp), - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - children: event.data != null - ? [ - Container( - padding: const EdgeInsets.all(12), - color: Colors.grey.shade50, - width: double.infinity, - child: _buildEventData(event.data!), - ), - ] - : [], - ), - ); - } - - Widget _buildEventData(Map data) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: data.entries.map((entry) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 2), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '${entry.key}: ', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 12, - ), - ), - Expanded( - child: Text( - entry.value.toString(), - style: const TextStyle(fontSize: 12), - ), - ), - ], - ), - ); - }).toList(), - ); - } - - Color _getEventTypeColor(EventType type) { - switch (type) { - case EventType.error: - return Colors.red.shade100; - case EventType.navigation: - return Colors.blue.shade100; - case EventType.javascript: - return Colors.yellow.shade100; - case EventType.console: - return Colors.grey.shade200; - case EventType.network: - return Colors.purple.shade100; - case EventType.performance: - return Colors.orange.shade100; - case EventType.storage: - case EventType.cookies: - return Colors.teal.shade100; - case EventType.messaging: - return Colors.indigo.shade100; - case EventType.ui: - return Colors.pink.shade100; - } - } -} - -class _StickyHeaderDelegate extends SliverPersistentHeaderDelegate { - final Widget child; - final double minHeight; - final double maxHeight; - - _StickyHeaderDelegate({ - required this.child, - required this.minHeight, - required this.maxHeight, - }); - - @override - Widget build( - BuildContext context, - double shrinkOffset, - bool overlapsContent, - ) { - return SizedBox.expand(child: child); - } - - @override - double get maxExtent => maxHeight; - - @override - double get minExtent => minHeight; - - @override - bool shouldRebuild(_StickyHeaderDelegate oldDelegate) { - return maxHeight != oldDelegate.maxHeight || - minHeight != oldDelegate.minHeight || - child != oldDelegate.child; - } -} diff --git a/flutter_inappwebview/example/lib/widgets/webview/javascript_console_widget.dart b/flutter_inappwebview/example/lib/widgets/webview/javascript_console_widget.dart deleted file mode 100644 index e6e81aa560..0000000000 --- a/flutter_inappwebview/example/lib/widgets/webview/javascript_console_widget.dart +++ /dev/null @@ -1,329 +0,0 @@ -import 'dart:convert'; -import 'package:flutter/material.dart'; - -/// Result of a JavaScript execution -class JsExecutionResult { - final String code; - final DateTime timestamp; - final dynamic result; - final String? error; - final bool isAsync; - - JsExecutionResult({ - required this.code, - required this.timestamp, - this.result, - this.error, - this.isAsync = false, - }); -} - -/// Widget to execute JavaScript and view results -class JavaScriptConsoleWidget extends StatefulWidget { - final Future Function(String code) onExecute; - final Future Function(String code)? onExecuteAsync; - - const JavaScriptConsoleWidget({ - super.key, - required this.onExecute, - this.onExecuteAsync, - }); - - @override - State createState() => - _JavaScriptConsoleWidgetState(); -} - -class _JavaScriptConsoleWidgetState extends State { - final TextEditingController _codeController = TextEditingController(); - final List _history = []; - bool _isExecuting = false; - - @override - void dispose() { - _codeController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return CustomScrollView( - slivers: [ - SliverToBoxAdapter(child: _buildHeader()), - SliverToBoxAdapter(child: _buildInputArea()), - _buildResultsArea(), - ], - ); - } - - Widget _buildHeader() { - return Container( - padding: const EdgeInsets.all(8.0), - // ... (unchanged code, but I need to include it for context match or just replace build) - decoration: BoxDecoration( - color: Colors.grey.shade100, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: Row( - children: [ - const Text( - 'JavaScript Console', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), - ), - const Spacer(), - IconButton( - icon: const Icon(Icons.clear), - tooltip: 'Clear', - onPressed: _clear, - ), - ], - ), - ); - } - - Widget _buildInputArea() { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - TextField( - controller: _codeController, - decoration: const InputDecoration( - hintText: 'Enter JavaScript code', - border: OutlineInputBorder(), - contentPadding: EdgeInsets.all(12), - ), - maxLines: 3, - onChanged: (_) => setState(() {}), - ), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - child: ElevatedButton( - onPressed: _codeController.text.trim().isEmpty || _isExecuting - ? null - : () => _execute(false), - child: _isExecuting - ? const SizedBox( - height: 16, - width: 16, - child: CircularProgressIndicator(strokeWidth: 2), - ) - : const Text('Execute'), - ), - ), - const SizedBox(width: 8), - Expanded( - child: ElevatedButton( - onPressed: - _codeController.text.trim().isEmpty || - _isExecuting || - widget.onExecuteAsync == null - ? null - : () => _execute(true), - child: const Text('Execute Async'), - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildResultsArea() { - if (_history.isEmpty) { - return const SliverFillRemaining( - hasScrollBody: false, - child: Center( - child: Text( - 'Execute JavaScript to see results', - style: TextStyle(color: Colors.grey), - ), - ), - ); - } - - return SliverList( - delegate: SliverChildBuilderDelegate((context, index) { - final result = _history[index]; - return _buildResultItem(result); - }, childCount: _history.length), - ); - } - - Widget _buildResultItem(JsExecutionResult result) { - return Card( - margin: const EdgeInsets.all(8), - child: Padding( - padding: const EdgeInsets.all(12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon( - result.error != null ? Icons.error : Icons.check_circle, - color: result.error != null ? Colors.red : Colors.green, - size: 16, - ), - const SizedBox(width: 4), - Text( - result.isAsync ? 'Async Execution' : 'Execution', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 12, - ), - ), - const Spacer(), - Text( - _formatTime(result.timestamp), - style: TextStyle(fontSize: 11, color: Colors.grey.shade600), - ), - ], - ), - const SizedBox(height: 8), - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.grey.shade100, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - result.code, - style: const TextStyle(fontSize: 12, fontFamily: 'monospace'), - ), - ), - const SizedBox(height: 8), - if (result.error != null) - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.red.shade50, - borderRadius: BorderRadius.circular(4), - border: Border.all(color: Colors.red.shade200), - ), - child: Row( - children: [ - const Icon( - Icons.error_outline, - color: Colors.red, - size: 16, - ), - const SizedBox(width: 8), - Expanded( - child: Text( - 'Error: ${result.error}', - style: const TextStyle(fontSize: 12, color: Colors.red), - ), - ), - ], - ), - ) - else - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.green.shade50, - borderRadius: BorderRadius.circular(4), - border: Border.all(color: Colors.green.shade200), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Result:', - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 4), - Text( - _formatResult(result.result), - style: const TextStyle( - fontSize: 12, - fontFamily: 'monospace', - ), - ), - ], - ), - ), - ], - ), - ), - ); - } - - Future _execute(bool isAsync) async { - final code = _codeController.text.trim(); - if (code.isEmpty) return; - - setState(() { - _isExecuting = true; - }); - - try { - final result = isAsync && widget.onExecuteAsync != null - ? await widget.onExecuteAsync!(code) - : await widget.onExecute(code); - - setState(() { - _history.add( - JsExecutionResult( - code: code, - timestamp: DateTime.now(), - result: result, - isAsync: isAsync, - ), - ); - _isExecuting = false; - }); - } catch (e) { - setState(() { - _history.add( - JsExecutionResult( - code: code, - timestamp: DateTime.now(), - error: e.toString(), - isAsync: isAsync, - ), - ); - _isExecuting = false; - }); - } - } - - void _clear() { - setState(() { - _codeController.clear(); - _history.clear(); - }); - } - - String _formatTime(DateTime time) { - return '${time.hour.toString().padLeft(2, '0')}:' - '${time.minute.toString().padLeft(2, '0')}:' - '${time.second.toString().padLeft(2, '0')}'; - } - - String _formatResult(dynamic result) { - if (result == null) return 'null'; - if (result is String) return result; - if (result is Map || result is List) { - try { - const encoder = JsonEncoder.withIndent(' '); - return encoder.convert(result); - } catch (e) { - return result.toString(); - } - } - return result.toString(); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/webview/method_tester_widget.dart b/flutter_inappwebview/example/lib/widgets/webview/method_tester_widget.dart deleted file mode 100644 index b02ac16944..0000000000 --- a/flutter_inappwebview/example/lib/widgets/webview/method_tester_widget.dart +++ /dev/null @@ -1,1818 +0,0 @@ -import 'dart:convert'; -import 'dart:typed_data'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; -import 'package:flutter_inappwebview_example/widgets/common/support_badge.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_result_history.dart'; - -/// Method entry for a single controller method -class MethodEntry { - /// The method enum that this entry represents. - /// The name is derived from methodEnum.name. - final PlatformInAppWebViewControllerMethod methodEnum; - final String description; - final Map parameters; - final List requiredParameters; - final Future Function( - InAppWebViewController controller, - Map params, - ) - execute; - - const MethodEntry({ - required this.methodEnum, - required this.description, - this.parameters = const {}, - this.requiredParameters = const [], - required this.execute, - }); - - /// The display name derived from methodEnum.name - String get name => methodEnum.name; -} - -/// Enum representing the categories of controller methods for the tester widget -enum MethodCategoryType { - navigation('Navigation & Loading', Icons.navigation), - pageInfo('Page Info & Content', Icons.info_outline), - javascript('JavaScript Execution', Icons.code), - jsHandlers('JavaScript Handlers', Icons.link), - userScripts('User Scripts', Icons.description), - scrolling('Scrolling & Layout', Icons.swap_vert), - zoom('Zoom', Icons.zoom_in), - settings('Settings & State', Icons.settings), - screenshotPrint('Screenshot & Print', Icons.camera_alt), - cacheHistory('Cache & History', Icons.history), - pauseResume('Pause & Resume', Icons.pause_circle_outline), - webMessaging('Web Messaging', Icons.message), - media('Media & Fullscreen', Icons.play_circle_outline), - cameraMic('Camera & Microphone', Icons.videocam), - security('Security', Icons.security), - saveRestore('Save & Restore', Icons.save), - misc('Misc/Advanced', Icons.more_horiz); - - final String displayName; - final IconData icon; - - const MethodCategoryType(this.displayName, this.icon); -} - -/// A category of methods -class MethodCategory { - /// The category type enum - name and icon are derived from this - final MethodCategoryType categoryType; - final List methods; - - const MethodCategory({required this.categoryType, required this.methods}); - - /// The display name derived from categoryType.displayName - String get name => categoryType.displayName; - - /// The icon derived from categoryType.icon - IconData get icon => categoryType.icon; -} - -/// Widget to test WebView controller methods -/// Tests controller methods organized by category -class MethodTesterWidget extends StatefulWidget { - final InAppWebViewController? controller; - - const MethodTesterWidget({super.key, required this.controller}); - - @override - State createState() => _MethodTesterWidgetState(); -} - -class _MethodTesterWidgetState extends State { - final TextEditingController _searchController = TextEditingController(); - String _searchQuery = ''; - final Map> _methodHistory = {}; - final Map _selectedHistoryIndex = {}; - final Map _executing = {}; - final Set _expandedCategories = { - 0, - }; // First category expanded by default - - // All method categories - late final List _categories; - - @override - void initState() { - super.initState(); - _categories = _buildMethodCategories(); - } - - @override - void dispose() { - _searchController.dispose(); - super.dispose(); - } - - List _buildMethodCategories() { - return [ - // Navigation & Loading (16 methods) - MethodCategory( - categoryType: MethodCategoryType.navigation, - methods: [ - MethodEntry( - description: 'Loads the given URL', - methodEnum: PlatformInAppWebViewControllerMethod.loadUrl, - parameters: { - 'url': 'https://example.com', - 'method': 'GET', - 'headers': {}, - 'body': const ParameterValueHint( - null, - ParameterValueType.bytes, - ), - }, - requiredParameters: ['url'], - execute: (controller, params) async { - final url = params['url']?.toString() ?? ''; - final method = params['method']?.toString(); - final headers = (params['headers'] as Map?)?.map( - (key, value) => MapEntry(key.toString(), value), - ); - final body = params['body'] as Uint8List?; - - await controller.loadUrl( - urlRequest: URLRequest( - url: WebUri(url), - method: method?.isNotEmpty == true ? method : null, - headers: headers?.cast(), - body: body, - ), - ); - return 'URL loaded successfully'; - }, - ), - MethodEntry( - description: 'Loads URL using POST method', - methodEnum: PlatformInAppWebViewControllerMethod.postUrl, - parameters: { - 'url': 'https://httpbin.org/post', - 'postData': const ParameterValueHint( - null, - ParameterValueType.bytes, - ), - }, - requiredParameters: ['url', 'postData'], - execute: (controller, params) async { - final url = params['url']?.toString() ?? ''; - Uint8List? postData; - final postDataParam = params['postData']; - if (postDataParam is Uint8List) { - postData = postDataParam; - } else if (postDataParam is String && postDataParam.isNotEmpty) { - // Convert string to bytes (UTF-8) - postData = Uint8List.fromList(postDataParam.codeUnits); - } - await controller.postUrl( - url: WebUri(url), - postData: postData ?? Uint8List(0), - ); - return 'POST request sent with ${postData?.length ?? 0} bytes'; - }, - ), - MethodEntry( - description: 'Loads HTML data string', - methodEnum: PlatformInAppWebViewControllerMethod.loadData, - parameters: { - 'data': '

Test HTML

', - 'mimeType': 'text/html', - 'encoding': 'utf-8', - 'baseUrl': '', - 'historyUrl': '', - }, - requiredParameters: ['data'], - execute: (controller, params) async { - final data = params['data']?.toString() ?? ''; - final mimeType = params['mimeType']?.toString(); - final encoding = params['encoding']?.toString(); - final baseUrl = params['baseUrl']?.toString(); - final historyUrl = params['historyUrl']?.toString(); - - await controller.loadData( - data: data, - mimeType: mimeType?.isNotEmpty == true - ? mimeType! - : 'text/html', - encoding: encoding?.isNotEmpty == true ? encoding! : 'utf-8', - baseUrl: baseUrl?.isNotEmpty == true ? WebUri(baseUrl!) : null, - historyUrl: historyUrl?.isNotEmpty == true - ? WebUri(historyUrl!) - : null, - ); - return 'HTML data loaded'; - }, - ), - MethodEntry( - description: 'Loads a file from assets', - methodEnum: PlatformInAppWebViewControllerMethod.loadFile, - parameters: {'assetFilePath': 'assets/index.html'}, - requiredParameters: ['assetFilePath'], - execute: (controller, params) async { - final path = params['assetFilePath']?.toString() ?? ''; - await controller.loadFile(assetFilePath: path); - return 'File loaded from assets'; - }, - ), - MethodEntry( - description: 'Reloads the current page', - methodEnum: PlatformInAppWebViewControllerMethod.reload, - execute: (controller, params) async { - await controller.reload(); - return 'Page reloaded'; - }, - ), - MethodEntry( - description: 'Reloads bypassing cache', - methodEnum: PlatformInAppWebViewControllerMethod.reloadFromOrigin, - execute: (controller, params) async { - await controller.reloadFromOrigin(); - return 'Page reloaded from origin'; - }, - ), - MethodEntry( - description: 'Navigates back in history', - methodEnum: PlatformInAppWebViewControllerMethod.goBack, - execute: (controller, params) async { - await controller.goBack(); - return 'Navigated back'; - }, - ), - MethodEntry( - description: 'Navigates forward in history', - methodEnum: PlatformInAppWebViewControllerMethod.goForward, - execute: (controller, params) async { - await controller.goForward(); - return 'Navigated forward'; - }, - ), - MethodEntry( - description: 'Navigates by steps', - methodEnum: PlatformInAppWebViewControllerMethod.goBackOrForward, - parameters: {'steps': -1}, - requiredParameters: ['steps'], - execute: (controller, params) async { - final steps = (params['steps'] as num?)?.toInt() ?? -1; - await controller.goBackOrForward(steps: steps); - return 'Navigated by steps'; - }, - ), - MethodEntry( - description: 'Navigates to history item', - methodEnum: PlatformInAppWebViewControllerMethod.goTo, - parameters: {'index': 0}, - requiredParameters: ['index'], - execute: (controller, params) async { - final history = await controller.getCopyBackForwardList(); - final index = (params['index'] as num?)?.toInt() ?? 0; - if (history != null && - history.list != null && - history.list!.isNotEmpty && - index >= 0 && - index < history.list!.length) { - await controller.goTo(historyItem: history.list![index]); - return 'Navigated to history item'; - } - return 'No history items available'; - }, - ), - MethodEntry( - description: 'Checks if can go back', - methodEnum: PlatformInAppWebViewControllerMethod.canGoBack, - execute: (controller, params) async { - return await controller.canGoBack(); - }, - ), - MethodEntry( - description: 'Checks if can go forward', - methodEnum: PlatformInAppWebViewControllerMethod.canGoForward, - execute: (controller, params) async { - return await controller.canGoForward(); - }, - ), - MethodEntry( - description: 'Checks if can navigate by steps', - methodEnum: PlatformInAppWebViewControllerMethod.canGoBackOrForward, - parameters: {'steps': -1}, - requiredParameters: ['steps'], - execute: (controller, params) async { - final steps = (params['steps'] as num?)?.toInt() ?? -1; - return await controller.canGoBackOrForward(steps: steps); - }, - ), - MethodEntry( - description: 'Checks if page is loading', - methodEnum: PlatformInAppWebViewControllerMethod.isLoading, - execute: (controller, params) async { - return await controller.isLoading(); - }, - ), - MethodEntry( - description: 'Stops page loading', - methodEnum: PlatformInAppWebViewControllerMethod.stopLoading, - execute: (controller, params) async { - await controller.stopLoading(); - return 'Loading stopped'; - }, - ), - MethodEntry( - description: 'Loads simulated request', - methodEnum: - PlatformInAppWebViewControllerMethod.loadSimulatedRequest, - parameters: { - 'url': 'https://example.com', - 'data': Uint8List.fromList( - 'Simulated'.codeUnits, - ), - }, - requiredParameters: ['url', 'data'], - execute: (controller, params) async { - final url = params['url']?.toString() ?? ''; - final data = params['data'] as Uint8List?; - await controller.loadSimulatedRequest( - urlRequest: URLRequest(url: WebUri(url)), - data: data ?? Uint8List(0), - ); - return 'Simulated request loaded'; - }, - ), - ], - ), - - // Page Info & Content (12 methods) - MethodCategory( - categoryType: MethodCategoryType.pageInfo, - methods: [ - MethodEntry( - description: 'Gets current page URL', - methodEnum: PlatformInAppWebViewControllerMethod.getUrl, - execute: (controller, params) async { - return (await controller.getUrl())?.toString() ?? 'No URL'; - }, - ), - MethodEntry( - description: 'Gets current page title', - methodEnum: PlatformInAppWebViewControllerMethod.getTitle, - execute: (controller, params) async { - return await controller.getTitle() ?? 'No title'; - }, - ), - MethodEntry( - description: 'Gets page load progress', - methodEnum: PlatformInAppWebViewControllerMethod.getProgress, - execute: (controller, params) async { - return await controller.getProgress(); - }, - ), - MethodEntry( - description: 'Gets page HTML source', - methodEnum: PlatformInAppWebViewControllerMethod.getHtml, - execute: (controller, params) async { - final html = await controller.getHtml(); - if (html != null && html.length > 500) { - return '${html.substring(0, 500)}...'; - } - return html ?? 'No HTML'; - }, - ), - MethodEntry( - description: 'Gets page favicons', - methodEnum: PlatformInAppWebViewControllerMethod.getFavicons, - execute: (controller, params) async { - final favicons = await controller.getFavicons(); - return 'Found ${favicons.length} favicons'; - }, - ), - MethodEntry( - description: 'Gets original URL before redirects', - methodEnum: PlatformInAppWebViewControllerMethod.getOriginalUrl, - execute: (controller, params) async { - return (await controller.getOriginalUrl())?.toString() ?? - 'No URL'; - }, - ), - MethodEntry( - description: 'Gets selected text', - methodEnum: PlatformInAppWebViewControllerMethod.getSelectedText, - execute: (controller, params) async { - return await controller.getSelectedText() ?? 'No selection'; - }, - ), - MethodEntry( - description: 'Gets hit test result', - methodEnum: PlatformInAppWebViewControllerMethod.getHitTestResult, - execute: (controller, params) async { - final result = await controller.getHitTestResult(); - return result?.type.toString() ?? 'No hit test result'; - }, - ), - MethodEntry( - description: 'Gets meta tags from page', - methodEnum: PlatformInAppWebViewControllerMethod.getMetaTags, - execute: (controller, params) async { - final tags = await controller.getMetaTags(); - return 'Found ${tags.length} meta tags'; - }, - ), - MethodEntry( - description: 'Gets meta theme color', - methodEnum: PlatformInAppWebViewControllerMethod.getMetaThemeColor, - execute: (controller, params) async { - final color = await controller.getMetaThemeColor(); - return color?.toString() ?? 'No theme color'; - }, - ), - MethodEntry( - description: 'Gets SSL certificate info and X509 data', - methodEnum: PlatformInAppWebViewControllerMethod.getCertificate, - execute: (controller, params) async { - final cert = await controller.getCertificate(); - if (cert == null) return {'error': 'No certificate available'}; - return cert.toMap(); - }, - ), - MethodEntry( - description: 'Gets navigation history', - methodEnum: - PlatformInAppWebViewControllerMethod.getCopyBackForwardList, - execute: (controller, params) async { - final history = await controller.getCopyBackForwardList(); - return 'History: ${history?.list?.length ?? 0} items, current: ${history?.currentIndex}'; - }, - ), - ], - ), - - // JavaScript Execution (7 methods) - MethodCategory( - categoryType: MethodCategoryType.javascript, - methods: [ - MethodEntry( - description: 'Executes JavaScript code', - methodEnum: PlatformInAppWebViewControllerMethod.evaluateJavascript, - parameters: {'source': 'document.title'}, - requiredParameters: ['source'], - execute: (controller, params) async { - return await controller.evaluateJavascript( - source: params['source']?.toString() ?? '', - ); - }, - ), - MethodEntry( - description: 'Calls async JavaScript function', - methodEnum: - PlatformInAppWebViewControllerMethod.callAsyncJavaScript, - parameters: { - 'functionBody': 'return await Promise.resolve("async result");', - 'arguments': {}, - }, - requiredParameters: ['functionBody'], - execute: (controller, params) async { - final arguments = params['arguments'] as Map?; - final result = await controller.callAsyncJavaScript( - functionBody: params['functionBody']?.toString() ?? '', - arguments: arguments?.cast() ?? const {}, - ); - return result?.value ?? 'No result'; - }, - ), - MethodEntry( - description: 'Injects JS file from URL', - methodEnum: PlatformInAppWebViewControllerMethod - .injectJavascriptFileFromUrl, - parameters: { - 'urlFile': 'https://code.jquery.com/jquery-3.7.1.min.js', - }, - requiredParameters: ['urlFile'], - execute: (controller, params) async { - await controller.injectJavascriptFileFromUrl( - urlFile: WebUri(params['urlFile']?.toString() ?? ''), - ); - return 'JavaScript file injected'; - }, - ), - MethodEntry( - description: 'Injects JS file from assets', - methodEnum: PlatformInAppWebViewControllerMethod - .injectJavascriptFileFromAsset, - parameters: {'assetFilePath': 'assets/js/script.js'}, - requiredParameters: ['assetFilePath'], - execute: (controller, params) async { - try { - await controller.injectJavascriptFileFromAsset( - assetFilePath: params['assetFilePath']?.toString() ?? '', - ); - return 'JavaScript asset injected'; - } catch (e) { - return 'Asset not found or injection failed'; - } - }, - ), - MethodEntry( - description: 'Injects CSS code', - methodEnum: PlatformInAppWebViewControllerMethod.injectCSSCode, - parameters: { - 'source': 'body { background-color: #f0f0f0 !important; }', - }, - requiredParameters: ['source'], - execute: (controller, params) async { - await controller.injectCSSCode( - source: params['source']?.toString() ?? '', - ); - return 'CSS code injected'; - }, - ), - MethodEntry( - description: 'Injects CSS file from URL', - methodEnum: - PlatformInAppWebViewControllerMethod.injectCSSFileFromUrl, - parameters: { - 'urlFile': - 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css', - }, - requiredParameters: ['urlFile'], - execute: (controller, params) async { - await controller.injectCSSFileFromUrl( - urlFile: WebUri(params['urlFile']?.toString() ?? ''), - ); - return 'CSS file injected'; - }, - ), - MethodEntry( - description: 'Injects CSS file from assets', - methodEnum: - PlatformInAppWebViewControllerMethod.injectCSSFileFromAsset, - parameters: {'assetFilePath': 'assets/css/style.css'}, - requiredParameters: ['assetFilePath'], - execute: (controller, params) async { - try { - await controller.injectCSSFileFromAsset( - assetFilePath: params['assetFilePath']?.toString() ?? '', - ); - return 'CSS asset injected'; - } catch (e) { - return 'Asset not found or injection failed'; - } - }, - ), - ], - ), - - // JavaScript Handlers (3 methods) - MethodCategory( - categoryType: MethodCategoryType.jsHandlers, - methods: [ - MethodEntry( - description: 'Adds a JavaScript handler', - methodEnum: - PlatformInAppWebViewControllerMethod.addJavaScriptHandler, - parameters: {'handlerName': 'testHandler'}, - requiredParameters: ['handlerName'], - execute: (controller, params) async { - final handlerName = params['handlerName']?.toString() ?? ''; - controller.addJavaScriptHandler( - handlerName: handlerName, - callback: (args) { - return {'received': args}; - }, - ); - return 'Handler "$handlerName" added'; - }, - ), - MethodEntry( - description: 'Removes a JavaScript handler', - methodEnum: - PlatformInAppWebViewControllerMethod.removeJavaScriptHandler, - parameters: {'handlerName': 'testHandler'}, - requiredParameters: ['handlerName'], - execute: (controller, params) async { - final removed = controller.removeJavaScriptHandler( - handlerName: params['handlerName']?.toString() ?? '', - ); - return removed != null ? 'Handler removed' : 'Handler not found'; - }, - ), - MethodEntry( - description: 'Checks if handler exists', - methodEnum: - PlatformInAppWebViewControllerMethod.hasJavaScriptHandler, - parameters: {'handlerName': 'testHandler'}, - requiredParameters: ['handlerName'], - execute: (controller, params) async { - return controller.hasJavaScriptHandler( - handlerName: params['handlerName']?.toString() ?? '', - ); - }, - ), - ], - ), - - // User Scripts (5 methods) - MethodCategory( - categoryType: MethodCategoryType.userScripts, - methods: [ - MethodEntry( - description: 'Adds a user script', - methodEnum: PlatformInAppWebViewControllerMethod.addUserScript, - parameters: { - 'source': 'console.log("User script executed");', - 'injectionTime': EnumParameterValueHint( - UserScriptInjectionTime.AT_DOCUMENT_END, - UserScriptInjectionTime.values.toList(), - displayName: (e) => e.name(), - ), - 'groupName': 'testGroup', - }, - requiredParameters: ['source'], - execute: (controller, params) async { - final injectionTimeParam = params['injectionTime']; - final injectionTime = - injectionTimeParam is UserScriptInjectionTime - ? injectionTimeParam - : _parseUserScriptInjectionTime( - injectionTimeParam?.toString(), - ); - await controller.addUserScript( - userScript: UserScript( - source: params['source']?.toString() ?? '', - injectionTime: injectionTime, - groupName: params['groupName']?.toString(), - ), - ); - return 'User script added'; - }, - ), - MethodEntry( - description: 'Removes a user script', - methodEnum: PlatformInAppWebViewControllerMethod.removeUserScript, - parameters: { - 'source': 'console.log("User script executed");', - 'injectionTime': EnumParameterValueHint( - UserScriptInjectionTime.AT_DOCUMENT_END, - UserScriptInjectionTime.values.toList(), - displayName: (e) => e.name(), - ), - 'groupName': 'testGroup', - }, - requiredParameters: ['source'], - execute: (controller, params) async { - final injectionTimeParam = params['injectionTime']; - final injectionTime = - injectionTimeParam is UserScriptInjectionTime - ? injectionTimeParam - : _parseUserScriptInjectionTime( - injectionTimeParam?.toString(), - ); - final script = UserScript( - source: params['source']?.toString() ?? '', - injectionTime: injectionTime, - groupName: params['groupName']?.toString(), - ); - final removed = await controller.removeUserScript( - userScript: script, - ); - return removed ? 'Script removed' : 'Script not found'; - }, - ), - MethodEntry( - description: 'Removes scripts by group name', - methodEnum: PlatformInAppWebViewControllerMethod - .removeUserScriptsByGroupName, - parameters: {'groupName': 'testGroup'}, - requiredParameters: ['groupName'], - execute: (controller, params) async { - await controller.removeUserScriptsByGroupName( - groupName: params['groupName']?.toString() ?? '', - ); - return 'Scripts in group removed'; - }, - ), - MethodEntry( - description: 'Removes all user scripts', - methodEnum: - PlatformInAppWebViewControllerMethod.removeAllUserScripts, - execute: (controller, params) async { - await controller.removeAllUserScripts(); - return 'All user scripts removed'; - }, - ), - MethodEntry( - description: 'Checks if user script exists', - methodEnum: PlatformInAppWebViewControllerMethod.hasUserScript, - parameters: { - 'source': 'console.log("test");', - 'injectionTime': EnumParameterValueHint( - UserScriptInjectionTime.AT_DOCUMENT_END, - UserScriptInjectionTime.values.toList(), - displayName: (e) => e.name(), - ), - }, - requiredParameters: ['source'], - execute: (controller, params) async { - final injectionTimeParam = params['injectionTime']; - final injectionTime = - injectionTimeParam is UserScriptInjectionTime - ? injectionTimeParam - : _parseUserScriptInjectionTime( - injectionTimeParam?.toString(), - ); - final script = UserScript( - source: params['source']?.toString() ?? '', - injectionTime: injectionTime, - ); - return controller.hasUserScript(userScript: script); - }, - ), - ], - ), - - // Scrolling & Layout (10 methods) - MethodCategory( - categoryType: MethodCategoryType.scrolling, - methods: [ - MethodEntry( - description: 'Scrolls to position', - methodEnum: PlatformInAppWebViewControllerMethod.scrollTo, - parameters: {'x': 0, 'y': 100, 'animated': true}, - execute: (controller, params) async { - final x = (params['x'] as num?)?.toInt() ?? 0; - final y = (params['y'] as num?)?.toInt() ?? 0; - final animated = params['animated'] as bool? ?? true; - await controller.scrollTo(x: x, y: y, animated: animated); - return 'Scrolled to (0, 100)'; - }, - ), - MethodEntry( - description: 'Scrolls by offset', - methodEnum: PlatformInAppWebViewControllerMethod.scrollBy, - parameters: {'x': 0, 'y': 50, 'animated': true}, - execute: (controller, params) async { - final x = (params['x'] as num?)?.toInt() ?? 0; - final y = (params['y'] as num?)?.toInt() ?? 0; - final animated = params['animated'] as bool? ?? true; - await controller.scrollBy(x: x, y: y, animated: animated); - return 'Scrolled by (0, 50)'; - }, - ), - MethodEntry( - description: 'Gets horizontal scroll position', - methodEnum: PlatformInAppWebViewControllerMethod.getScrollX, - execute: (controller, params) async { - return await controller.getScrollX(); - }, - ), - MethodEntry( - description: 'Gets vertical scroll position', - methodEnum: PlatformInAppWebViewControllerMethod.getScrollY, - execute: (controller, params) async { - return await controller.getScrollY(); - }, - ), - MethodEntry( - description: 'Gets content height', - methodEnum: PlatformInAppWebViewControllerMethod.getContentHeight, - execute: (controller, params) async { - return await controller.getContentHeight(); - }, - ), - MethodEntry( - description: 'Gets content width', - methodEnum: PlatformInAppWebViewControllerMethod.getContentWidth, - execute: (controller, params) async { - return await controller.getContentWidth(); - }, - ), - MethodEntry( - description: 'Checks if can scroll vertically', - methodEnum: - PlatformInAppWebViewControllerMethod.canScrollVertically, - execute: (controller, params) async { - return await controller.canScrollVertically(); - }, - ), - MethodEntry( - description: 'Checks if can scroll horizontally', - methodEnum: - PlatformInAppWebViewControllerMethod.canScrollHorizontally, - execute: (controller, params) async { - return await controller.canScrollHorizontally(); - }, - ), - MethodEntry( - description: 'Scrolls page down', - methodEnum: PlatformInAppWebViewControllerMethod.pageDown, - parameters: {'bottom': false}, - execute: (controller, params) async { - final bottom = params['bottom'] as bool? ?? false; - return await controller.pageDown(bottom: bottom); - }, - ), - MethodEntry( - description: 'Scrolls page up', - methodEnum: PlatformInAppWebViewControllerMethod.pageUp, - parameters: {'top': false}, - execute: (controller, params) async { - final top = params['top'] as bool? ?? false; - return await controller.pageUp(top: top); - }, - ), - ], - ), - - // Zoom (4 methods) - MethodCategory( - categoryType: MethodCategoryType.zoom, - methods: [ - MethodEntry( - description: 'Zooms by factor', - methodEnum: PlatformInAppWebViewControllerMethod.zoomBy, - parameters: {'zoomFactor': 1.5, 'animated': true}, - requiredParameters: ['zoomFactor'], - execute: (controller, params) async { - final zoomFactor = - (params['zoomFactor'] as num?)?.toDouble() ?? 1.0; - final animated = params['animated'] as bool? ?? true; - await controller.zoomBy( - zoomFactor: zoomFactor, - animated: animated, - ); - return 'Zoomed to 1.5x'; - }, - ), - MethodEntry( - description: 'Zooms in', - methodEnum: PlatformInAppWebViewControllerMethod.zoomIn, - execute: (controller, params) async { - return await controller.zoomIn(); - }, - ), - MethodEntry( - description: 'Zooms out', - methodEnum: PlatformInAppWebViewControllerMethod.zoomOut, - execute: (controller, params) async { - return await controller.zoomOut(); - }, - ), - MethodEntry( - description: 'Gets current zoom scale', - methodEnum: PlatformInAppWebViewControllerMethod.getZoomScale, - execute: (controller, params) async { - return await controller.getZoomScale(); - }, - ), - ], - ), - - // Settings & State (5 methods) - MethodCategory( - categoryType: MethodCategoryType.settings, - methods: [ - MethodEntry( - description: 'Sets WebView settings', - methodEnum: PlatformInAppWebViewControllerMethod.setSettings, - parameters: {'javaScriptEnabled': true, 'supportZoom': true}, - execute: (controller, params) async { - await controller.setSettings( - settings: InAppWebViewSettings( - javaScriptEnabled: params['javaScriptEnabled'] as bool?, - supportZoom: params['supportZoom'] as bool?, - ), - ); - return 'Settings updated'; - }, - ), - MethodEntry( - description: 'Gets WebView settings', - methodEnum: PlatformInAppWebViewControllerMethod.getSettings, - execute: (controller, params) async { - final settings = await controller.getSettings(); - return 'JS enabled: ${settings?.javaScriptEnabled}'; - }, - ), - MethodEntry( - description: 'Sets context menu', - methodEnum: PlatformInAppWebViewControllerMethod.setContextMenu, - parameters: {'menuItemTitle': 'Test Item'}, - execute: (controller, params) async { - await controller.setContextMenu( - ContextMenu( - menuItems: [ - ContextMenuItem( - id: 1, - title: params['menuItemTitle']?.toString() ?? 'Item', - action: () {}, - ), - ], - ), - ); - return 'Context menu set'; - }, - ), - MethodEntry( - description: 'Requests focus for WebView', - methodEnum: PlatformInAppWebViewControllerMethod.requestFocus, - execute: (controller, params) async { - return await controller.requestFocus(); - }, - ), - MethodEntry( - description: 'Clears focus from WebView', - methodEnum: PlatformInAppWebViewControllerMethod.clearFocus, - execute: (controller, params) async { - await controller.clearFocus(); - return 'Focus cleared'; - }, - ), - ], - ), - - // Screenshot & Print (3 methods) - MethodCategory( - categoryType: MethodCategoryType.screenshotPrint, - methods: [ - MethodEntry( - description: 'Takes a screenshot', - methodEnum: PlatformInAppWebViewControllerMethod.takeScreenshot, - parameters: { - 'compressFormat': EnumParameterValueHint( - CompressFormat.PNG, - CompressFormat.values.toList(), - displayName: (e) => e.name(), - ), - 'quality': 100, - 'snapshotWidth': const ParameterValueHint( - null, - ParameterValueType.number, - ), - }, - execute: (controller, params) async { - final compressFormatParam = params['compressFormat']; - final compressFormat = compressFormatParam is CompressFormat - ? compressFormatParam - : CompressFormat.PNG; - final quality = (params['quality'] as num?)?.toInt() ?? 100; - final snapshotWidthParam = params['snapshotWidth']; - final snapshotWidth = snapshotWidthParam is ParameterValueHint - ? (snapshotWidthParam.value as num?)?.toDouble() - : (snapshotWidthParam as num?)?.toDouble(); - - final screenshot = await controller.takeScreenshot( - screenshotConfiguration: ScreenshotConfiguration( - compressFormat: compressFormat, - quality: quality, - snapshotWidth: snapshotWidth, - ), - ); - if (screenshot != null) { - return 'Screenshot taken: ${screenshot.length} bytes'; - } - return 'Screenshot failed'; - }, - ), - MethodEntry( - description: 'Prints current page', - methodEnum: PlatformInAppWebViewControllerMethod.printCurrentPage, - execute: (controller, params) async { - final printJob = await controller.printCurrentPage(); - return printJob != null - ? 'Print dialog opened' - : 'Print not available'; - }, - ), - MethodEntry( - description: 'Creates PDF from page', - methodEnum: PlatformInAppWebViewControllerMethod.createPdf, - execute: (controller, params) async { - final pdf = await controller.createPdf(); - if (pdf != null) { - return 'PDF created: ${pdf.length} bytes'; - } - return 'PDF creation failed'; - }, - ), - ], - ), - - // Cache & History (3 methods) - MethodCategory( - categoryType: MethodCategoryType.cacheHistory, - methods: [ - MethodEntry( - description: 'Clears navigation history', - methodEnum: PlatformInAppWebViewControllerMethod.clearHistory, - execute: (controller, params) async { - await controller.clearHistory(); - return 'History cleared'; - }, - ), - MethodEntry( - description: 'Clears form data', - methodEnum: PlatformInAppWebViewControllerMethod.clearFormData, - execute: (controller, params) async { - await controller.clearFormData(); - return 'Form data cleared'; - }, - ), - MethodEntry( - description: 'Clears SSL preferences', - methodEnum: - PlatformInAppWebViewControllerMethod.clearSslPreferences, - execute: (controller, params) async { - await controller.clearSslPreferences(); - return 'SSL preferences cleared'; - }, - ), - ], - ), - - // Pause & Resume (4 methods) - MethodCategory( - categoryType: MethodCategoryType.pauseResume, - methods: [ - MethodEntry( - description: 'Pauses WebView', - methodEnum: PlatformInAppWebViewControllerMethod.pause, - execute: (controller, params) async { - await controller.pause(); - return 'WebView paused'; - }, - ), - MethodEntry( - description: 'Resumes WebView', - methodEnum: PlatformInAppWebViewControllerMethod.resume, - execute: (controller, params) async { - await controller.resume(); - return 'WebView resumed'; - }, - ), - MethodEntry( - description: 'Pauses JavaScript timers', - methodEnum: PlatformInAppWebViewControllerMethod.pauseTimers, - execute: (controller, params) async { - await controller.pauseTimers(); - return 'Timers paused'; - }, - ), - MethodEntry( - description: 'Resumes JavaScript timers', - methodEnum: PlatformInAppWebViewControllerMethod.resumeTimers, - execute: (controller, params) async { - await controller.resumeTimers(); - return 'Timers resumed'; - }, - ), - ], - ), - - // Web Messaging (4 methods) - MethodCategory( - categoryType: MethodCategoryType.webMessaging, - methods: [ - MethodEntry( - description: 'Creates a web message channel', - methodEnum: - PlatformInAppWebViewControllerMethod.createWebMessageChannel, - execute: (controller, params) async { - final channel = await controller.createWebMessageChannel(); - return channel != null - ? 'Channel created' - : 'Channel creation failed'; - }, - ), - MethodEntry( - description: 'Posts a web message', - methodEnum: PlatformInAppWebViewControllerMethod.postWebMessage, - parameters: {'message': 'Hello from Flutter', 'targetOrigin': '*'}, - requiredParameters: ['message'], - execute: (controller, params) async { - final targetOrigin = params['targetOrigin']?.toString(); - await controller.postWebMessage( - message: WebMessage(data: params['message']?.toString()), - targetOrigin: WebUri( - targetOrigin?.isNotEmpty == true ? targetOrigin! : '*', - ), - ); - return 'Message posted'; - }, - ), - MethodEntry( - description: 'Adds a web message listener', - methodEnum: - PlatformInAppWebViewControllerMethod.addWebMessageListener, - parameters: {'jsObjectName': 'testListener'}, - requiredParameters: ['jsObjectName'], - execute: (controller, params) async { - await controller.addWebMessageListener( - WebMessageListener( - jsObjectName: params['jsObjectName']?.toString() ?? '', - onPostMessage: - (message, sourceOrigin, isMainFrame, replyProxy) { - // Handle message - }, - ), - ); - return 'Listener added'; - }, - ), - MethodEntry( - description: 'Checks if listener exists', - methodEnum: - PlatformInAppWebViewControllerMethod.hasWebMessageListener, - parameters: {'jsObjectName': 'testListener'}, - requiredParameters: ['jsObjectName'], - execute: (controller, params) async { - final listener = WebMessageListener( - jsObjectName: params['jsObjectName']?.toString() ?? '', - onPostMessage: - (message, sourceOrigin, isMainFrame, replyProxy) {}, - ); - return controller.hasWebMessageListener(listener); - }, - ), - ], - ), - - // Media & Fullscreen (8 methods) - MethodCategory( - categoryType: MethodCategoryType.media, - methods: [ - MethodEntry( - description: 'Checks if in fullscreen', - methodEnum: PlatformInAppWebViewControllerMethod.isInFullscreen, - execute: (controller, params) async { - return await controller.isInFullscreen(); - }, - ), - MethodEntry( - description: 'Pauses all media', - methodEnum: - PlatformInAppWebViewControllerMethod.pauseAllMediaPlayback, - execute: (controller, params) async { - await controller.pauseAllMediaPlayback(); - return 'Media paused'; - }, - ), - MethodEntry( - description: 'Suspends media playback', - methodEnum: PlatformInAppWebViewControllerMethod - .setAllMediaPlaybackSuspended, - parameters: {'suspended': true}, - execute: (controller, params) async { - await controller.setAllMediaPlaybackSuspended( - suspended: params['suspended'] as bool? ?? true, - ); - return 'Media suspended'; - }, - ), - MethodEntry( - description: 'Closes media presentations', - methodEnum: - PlatformInAppWebViewControllerMethod.closeAllMediaPresentations, - execute: (controller, params) async { - await controller.closeAllMediaPresentations(); - return 'Media presentations closed'; - }, - ), - MethodEntry( - description: 'Gets media playback state', - methodEnum: - PlatformInAppWebViewControllerMethod.requestMediaPlaybackState, - execute: (controller, params) async { - final state = await controller.requestMediaPlaybackState(); - return state?.toString() ?? 'Unknown state'; - }, - ), - MethodEntry( - description: 'Checks if playing audio', - methodEnum: PlatformInAppWebViewControllerMethod.isPlayingAudio, - execute: (controller, params) async { - return await controller.isPlayingAudio(); - }, - ), - MethodEntry( - description: 'Checks if muted', - methodEnum: PlatformInAppWebViewControllerMethod.isMuted, - execute: (controller, params) async { - return await controller.isMuted(); - }, - ), - MethodEntry( - description: 'Sets mute state', - methodEnum: PlatformInAppWebViewControllerMethod.setMuted, - parameters: {'muted': true}, - execute: (controller, params) async { - await controller.setMuted( - muted: params['muted'] as bool? ?? true, - ); - return 'Muted'; - }, - ), - ], - ), - - // Camera & Microphone (4 methods) - MethodCategory( - categoryType: MethodCategoryType.cameraMic, - methods: [ - MethodEntry( - description: 'Gets camera capture state', - methodEnum: - PlatformInAppWebViewControllerMethod.getCameraCaptureState, - execute: (controller, params) async { - final state = await controller.getCameraCaptureState(); - return state?.toString() ?? 'Unknown state'; - }, - ), - MethodEntry( - description: 'Sets camera capture state', - methodEnum: - PlatformInAppWebViewControllerMethod.setCameraCaptureState, - parameters: { - 'state': EnumParameterValueHint( - MediaCaptureState.ACTIVE, - MediaCaptureState.values.toList(), - displayName: (e) => e.name(), - ), - }, - requiredParameters: ['state'], - execute: (controller, params) async { - final stateParam = params['state']; - final state = stateParam is MediaCaptureState - ? stateParam - : _parseMediaCaptureState(stateParam?.toString()); - await controller.setCameraCaptureState(state: state); - return 'Camera state set'; - }, - ), - MethodEntry( - description: 'Gets microphone capture state', - methodEnum: - PlatformInAppWebViewControllerMethod.getMicrophoneCaptureState, - execute: (controller, params) async { - final state = await controller.getMicrophoneCaptureState(); - return state?.toString() ?? 'Unknown state'; - }, - ), - MethodEntry( - description: 'Sets microphone capture state', - methodEnum: - PlatformInAppWebViewControllerMethod.setMicrophoneCaptureState, - parameters: { - 'state': EnumParameterValueHint( - MediaCaptureState.ACTIVE, - MediaCaptureState.values.toList(), - displayName: (e) => e.name(), - ), - }, - requiredParameters: ['state'], - execute: (controller, params) async { - final stateParam = params['state']; - final state = stateParam is MediaCaptureState - ? stateParam - : _parseMediaCaptureState(stateParam?.toString()); - await controller.setMicrophoneCaptureState(state: state); - return 'Microphone state set'; - }, - ), - ], - ), - - // Security (2 methods) - MethodCategory( - categoryType: MethodCategoryType.security, - methods: [ - MethodEntry( - description: 'Checks if secure context', - methodEnum: PlatformInAppWebViewControllerMethod.isSecureContext, - execute: (controller, params) async { - return await controller.isSecureContext(); - }, - ), - MethodEntry( - description: 'Checks if only secure content', - methodEnum: - PlatformInAppWebViewControllerMethod.hasOnlySecureContent, - execute: (controller, params) async { - return await controller.hasOnlySecureContent(); - }, - ), - ], - ), - - // Save & Restore (4 methods) - MethodCategory( - categoryType: MethodCategoryType.saveRestore, - methods: [ - MethodEntry( - description: 'Saves WebView state', - methodEnum: PlatformInAppWebViewControllerMethod.saveState, - execute: (controller, params) async { - final state = await controller.saveState(); - return state != null - ? 'State saved: ${state.length} bytes' - : 'Save failed'; - }, - ), - MethodEntry( - description: 'Restores WebView state', - methodEnum: PlatformInAppWebViewControllerMethod.restoreState, - execute: (controller, params) async { - // Would need saved state to restore - return 'No state to restore'; - }, - ), - MethodEntry( - description: 'Saves page as web archive', - methodEnum: PlatformInAppWebViewControllerMethod.saveWebArchive, - parameters: {'filePath': '/tmp/archive.mht', 'autoname': true}, - requiredParameters: ['filePath'], - execute: (controller, params) async { - try { - final path = await controller.saveWebArchive( - filePath: params['filePath']?.toString() ?? '', - autoname: params['autoname'] as bool? ?? true, - ); - return path ?? 'Archive save failed'; - } catch (e) { - return 'Error: $e'; - } - }, - ), - MethodEntry( - description: 'Creates web archive data', - methodEnum: - PlatformInAppWebViewControllerMethod.createWebArchiveData, - execute: (controller, params) async { - final data = await controller.createWebArchiveData(); - return data != null ? 'Archive: ${data.length} bytes' : 'Failed'; - }, - ), - ], - ), - - // Misc/Advanced (6 methods) - MethodCategory( - categoryType: MethodCategoryType.misc, - methods: [ - MethodEntry( - description: 'Gets the WebView ID', - methodEnum: PlatformInAppWebViewControllerMethod.getViewId, - execute: (controller, params) async { - return controller.getViewId(); - }, - ), - MethodEntry( - description: 'Starts Safe Browsing', - methodEnum: PlatformInAppWebViewControllerMethod.startSafeBrowsing, - execute: (controller, params) async { - return await controller.startSafeBrowsing(); - }, - ), - MethodEntry( - description: 'Opens DevTools', - methodEnum: PlatformInAppWebViewControllerMethod.openDevTools, - execute: (controller, params) async { - await controller.openDevTools(); - return 'DevTools opened'; - }, - ), - MethodEntry( - description: 'Gets focused node href', - methodEnum: - PlatformInAppWebViewControllerMethod.requestFocusNodeHref, - execute: (controller, params) async { - final result = await controller.requestFocusNodeHref(); - return result?.url ?? 'No focused node'; - }, - ), - MethodEntry( - description: 'Gets focused image URL', - methodEnum: PlatformInAppWebViewControllerMethod.requestImageRef, - execute: (controller, params) async { - final result = await controller.requestImageRef(); - return result?.url ?? 'No image focused'; - }, - ), - MethodEntry( - description: 'Checks interface support', - methodEnum: - PlatformInAppWebViewControllerMethod.isInterfaceSupported, - parameters: {'interface': WebViewInterface.ICoreWebView2.name()}, - requiredParameters: ['interface'], - execute: (controller, params) async { - return await controller.isInterfaceSupported( - _parseWebViewInterface(params['interface']?.toString()), - ); - }, - ), - ], - ), - ]; - } - - List _getFilteredCategories() { - if (_searchQuery.isEmpty) { - return _categories; - } - - final query = _searchQuery.toLowerCase(); - return _categories - .map((category) { - final filteredMethods = category.methods - .where( - (method) => - method.name.toLowerCase().contains(query) || - method.description.toLowerCase().contains(query), - ) - .toList(); - return MethodCategory( - categoryType: category.categoryType, - methods: filteredMethods, - ); - }) - .where((category) => category.methods.isNotEmpty) - .toList(); - } - - Future _executeMethod(MethodEntry entry) async { - if (widget.controller == null) return; - - setState(() { - _executing[entry.name] = true; - }); - - try { - Map params = entry.parameters; - if (entry.parameters.isNotEmpty) { - final updatedParams = await showParameterDialog( - context: context, - title: '${entry.name} parameters', - parameters: entry.parameters, - requiredPaths: entry.requiredParameters, - ); - - if (updatedParams == null) { - if (mounted) { - setState(() { - _executing[entry.name] = false; - }); - } - return; - } - params = updatedParams; - } - - final result = await entry.execute(widget.controller!, params); - if (mounted) { - setState(() { - _addMethodHistoryEntry( - entry.name, - _formatResult(result), - isError: false, - value: result, - ); - _executing[entry.name] = false; - }); - } - } catch (e) { - if (mounted) { - setState(() { - _addMethodHistoryEntry(entry.name, e.toString(), isError: true); - _executing[entry.name] = false; - }); - } - } - } - - void _addMethodHistoryEntry( - String methodName, - String message, { - required bool isError, - dynamic value, - }) { - final current = List.from( - _methodHistory[methodName] ?? const [], - ); - current.insert( - 0, - MethodResultEntry( - message: message, - isError: isError, - timestamp: DateTime.now(), - value: value, - ), - ); - if (current.length > 3) { - current.removeRange(3, current.length); - } - _methodHistory[methodName] = current; - _selectedHistoryIndex[methodName] = 0; - } - - @override - Widget build(BuildContext context) { - final filteredCategories = _getFilteredCategories(); - final totalMethods = _categories.fold( - 0, - (sum, cat) => sum + cat.methods.length, - ); - - return CustomScrollView( - slivers: [ - // Header with search - SliverPersistentHeader( - pinned: true, - delegate: _StickyHeaderDelegate( - minHeight: 80, - maxHeight: 80, - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.grey.shade100, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: Center( - child: TextField( - controller: _searchController, - decoration: InputDecoration( - hintText: 'Search $totalMethods methods...', - prefixIcon: const Icon(Icons.search, size: 20), - suffixIcon: _searchQuery.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear, size: 20), - onPressed: () { - _searchController.clear(); - setState(() => _searchQuery = ''); - }, - ) - : null, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - fillColor: Colors.white, - filled: true, - isDense: true, - ), - onChanged: (value) => setState(() => _searchQuery = value), - ), - ), - ), - ), - ), - - // Controller status - if (widget.controller == null) - SliverToBoxAdapter( - child: Container( - padding: const EdgeInsets.all(12), - color: Colors.orange.shade50, - child: const Row( - children: [ - Icon(Icons.warning, color: Colors.orange, size: 20), - SizedBox(width: 8), - Expanded( - child: Text( - 'WebView controller not available. Create a WebView first.', - style: TextStyle(color: Colors.orange), - ), - ), - ], - ), - ), - ), - - // Method categories - SliverList( - delegate: SliverChildBuilderDelegate((context, categoryIndex) { - final category = filteredCategories[categoryIndex]; - final originalIndex = _categories.indexOf(category); - final isExpanded = - _searchQuery.isNotEmpty || - _expandedCategories.contains(originalIndex); - - return ExpansionTile( - key: Key(category.name), - initiallyExpanded: isExpanded, - leading: Icon(category.icon, size: 24), - title: Text( - '${category.name} (${category.methods.length})', - style: const TextStyle(fontWeight: FontWeight.w600), - ), - onExpansionChanged: (expanded) { - setState(() { - if (expanded) { - _expandedCategories.add(originalIndex); - } else { - _expandedCategories.remove(originalIndex); - } - }); - }, - children: category.methods - .map((method) => _buildMethodTile(method)) - .toList(), - ); - }, childCount: filteredCategories.length), - ), - ], - ); - } - - Widget _buildMethodTile(MethodEntry method) { - final isExecuting = _executing[method.name] == true; - final historyEntries = _methodHistory[method.name] ?? const []; - final supportedPlatforms = SupportCheckHelper.supportedPlatformsForMethod( - method: method.methodEnum, - checker: InAppWebViewController.isMethodSupported, - ); - - return Container( - margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey.shade300), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Method header - ListTile( - dense: true, - title: Text( - method.name, - style: const TextStyle( - fontWeight: FontWeight.w600, - fontFamily: 'monospace', - ), - ), - subtitle: Padding( - padding: const EdgeInsets.only(top: 4), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - method.description, - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - const SizedBox(height: 6), - SupportBadgesRow( - supportedPlatforms: supportedPlatforms, - compact: true, - ), - ], - ), - ), - trailing: SizedBox( - width: 80, - height: 32, - child: ElevatedButton( - onPressed: widget.controller == null || isExecuting - ? null - : () => _executeMethod(method), - style: ElevatedButton.styleFrom( - padding: EdgeInsets.zero, - textStyle: const TextStyle(fontSize: 11), - ), - child: isExecuting - ? const SizedBox( - width: 16, - height: 16, - child: CircularProgressIndicator(strokeWidth: 2), - ) - : const Text('Execute'), - ), - ), - ), - - if (historyEntries.isNotEmpty) - Padding( - padding: const EdgeInsets.fromLTRB(12, 0, 12, 12), - child: MethodResultHistory( - entries: historyEntries, - selectedIndex: _selectedHistoryIndex[method.name], - onSelected: (index) { - setState(() => _selectedHistoryIndex[method.name] = index); - }, - ), - ), - ], - ), - ); - } - - UserScriptInjectionTime _parseUserScriptInjectionTime(String? value) { - if (value == null || value.isEmpty) { - return UserScriptInjectionTime.AT_DOCUMENT_END; - } - return UserScriptInjectionTime.values.firstWhere( - (entry) => entry.name().toLowerCase() == value.toLowerCase(), - orElse: () => UserScriptInjectionTime.AT_DOCUMENT_END, - ); - } - - MediaCaptureState _parseMediaCaptureState(String? value) { - if (value == null || value.isEmpty) { - return MediaCaptureState.ACTIVE; - } - return MediaCaptureState.values.firstWhere( - (entry) => entry.name().toLowerCase() == value.toLowerCase(), - orElse: () => MediaCaptureState.ACTIVE, - ); - } - - WebViewInterface _parseWebViewInterface(String? value) { - if (value == null || value.isEmpty) { - return WebViewInterface.ICoreWebView2; - } - return WebViewInterface.values.firstWhere( - (entry) => entry.name().toLowerCase() == value.toLowerCase(), - orElse: () => WebViewInterface.ICoreWebView2, - ); - } - - String _formatResult(dynamic result) { - if (result == null) return 'null'; - if (result is String) return result; - - // Try to convert to Map first - final mapResult = _toMapIfPossible(result); - if (mapResult != null) { - try { - const encoder = JsonEncoder.withIndent(' '); - return encoder.convert(mapResult); - } catch (e) { - return mapResult.toString(); - } - } - - if (result is Map || result is List) { - try { - const encoder = JsonEncoder.withIndent(' '); - return encoder.convert(result); - } catch (e) { - return result.toString(); - } - } - return result.toString(); - } - - /// Attempts to convert a result to a Map using common toMap/toJson patterns. - /// Returns null if conversion is not possible. - Map? _toMapIfPossible(dynamic result) { - if (result == null) return null; - if (result is Map) return Map.from(result); - try { - // ignore: avoid_dynamic_calls - return (result as dynamic).toMap(); - } catch (_) { - try { - // ignore: avoid_dynamic_calls - return (result as dynamic).toJson(); - } catch (_) { - return null; - } - } - } -} - -class _StickyHeaderDelegate extends SliverPersistentHeaderDelegate { - final Widget child; - final double minHeight; - final double maxHeight; - - _StickyHeaderDelegate({ - required this.child, - required this.minHeight, - required this.maxHeight, - }); - - @override - Widget build( - BuildContext context, - double shrinkOffset, - bool overlapsContent, - ) { - return SizedBox.expand(child: child); - } - - @override - double get maxExtent => maxHeight; - - @override - double get minExtent => minHeight; - - @override - bool shouldRebuild(_StickyHeaderDelegate oldDelegate) { - return maxHeight != oldDelegate.maxHeight || - minHeight != oldDelegate.minHeight || - child != oldDelegate.child; - } -} diff --git a/flutter_inappwebview/example/lib/widgets/webview/network_monitor_widget.dart b/flutter_inappwebview/example/lib/widgets/webview/network_monitor_widget.dart deleted file mode 100644 index bd934136f2..0000000000 --- a/flutter_inappwebview/example/lib/widgets/webview/network_monitor_widget.dart +++ /dev/null @@ -1,250 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/models/network_request.dart'; -import 'package:flutter_inappwebview_example/providers/network_monitor.dart'; - -/// Widget to display and monitor network requests -class NetworkMonitorWidget extends StatelessWidget { - const NetworkMonitorWidget({super.key}); - - @override - Widget build(BuildContext context) { - return CustomScrollView( - slivers: [ - SliverToBoxAdapter(child: _buildHeader(context)), - _buildRequestList(), - ], - ); - } - - Widget _buildHeader(BuildContext context) { - return Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: Colors.grey.shade100, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: Row( - children: [ - const Text( - 'Network', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), - ), - const SizedBox(width: 16), - Consumer( - builder: (context, monitor, child) { - return Row( - children: [ - Switch( - value: monitor.isMonitoring, - onChanged: (_) { - monitor.toggleMonitoring(); - }, - ), - const Text('Monitor Network'), - ], - ); - }, - ), - const Spacer(), - IconButton( - icon: const Icon(Icons.clear_all), - tooltip: 'Clear', - onPressed: () { - context.read().clearRequests(); - }, - ), - ], - ), - ); - } - - Widget _buildRequestList() { - return Consumer( - builder: (context, monitor, child) { - final requests = monitor.requests; - - if (requests.isEmpty) { - return const SliverFillRemaining( - hasScrollBody: false, - child: Center( - child: Text( - 'No network requests yet', - style: TextStyle(color: Colors.grey), - ), - ), - ); - } - - return SliverList( - delegate: SliverChildBuilderDelegate((context, index) { - final request = requests[requests.length - 1 - index]; - return _buildRequestItem(request); - }, childCount: requests.length), - ); - }, - ); - } - - Widget _buildRequestItem(NetworkRequest request) { - final timeFormat = DateFormat('HH:mm:ss'); - - return Card( - margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - child: ExpansionTile( - leading: Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: _getMethodColor(request.method), - borderRadius: BorderRadius.circular(4), - ), - child: Text( - request.method, - style: const TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ), - title: Text( - request.url, - style: const TextStyle(fontSize: 13), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - subtitle: Row( - children: [ - Text( - timeFormat.format(request.timestamp), - style: TextStyle(fontSize: 11, color: Colors.grey.shade600), - ), - const SizedBox(width: 8), - if (request.duration != null) - Text( - '${request.duration!.inMilliseconds}ms', - style: TextStyle(fontSize: 11, color: Colors.grey.shade600), - ), - ], - ), - trailing: request.statusCode != null - ? Chip( - label: Text( - request.statusCode.toString(), - style: const TextStyle(fontSize: 11), - ), - backgroundColor: _getStatusCodeColor(request.statusCode!), - padding: EdgeInsets.zero, - ) - : const Chip( - label: Text('Pending', style: TextStyle(fontSize: 11)), - backgroundColor: Colors.orange, - padding: EdgeInsets.zero, - ), - children: [ - Container( - padding: const EdgeInsets.all(12), - color: Colors.grey.shade50, - width: double.infinity, - child: _buildRequestDetails(request), - ), - ], - ), - ); - } - - Widget _buildRequestDetails(NetworkRequest request) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (request.headers != null && request.headers!.isNotEmpty) ...[ - const Text( - 'Request Headers', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12), - ), - const SizedBox(height: 4), - ...request.headers!.entries.map((entry) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 2), - child: Text( - '${entry.key}: ${entry.value}', - style: const TextStyle(fontSize: 11), - ), - ); - }), - const SizedBox(height: 8), - ], - if (request.body != null) ...[ - const Text( - 'Request Body', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12), - ), - const SizedBox(height: 4), - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.white, - border: Border.all(color: Colors.grey.shade300), - borderRadius: BorderRadius.circular(4), - ), - child: Text( - request.body!, - style: const TextStyle(fontSize: 11, fontFamily: 'monospace'), - ), - ), - const SizedBox(height: 8), - ], - if (request.response != null) ...[ - const Text( - 'Response', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12), - ), - const SizedBox(height: 4), - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.white, - border: Border.all(color: Colors.grey.shade300), - borderRadius: BorderRadius.circular(4), - ), - child: Text( - request.response!, - style: const TextStyle(fontSize: 11, fontFamily: 'monospace'), - ), - ), - ], - ], - ); - } - - Color _getMethodColor(String method) { - switch (method.toUpperCase()) { - case 'GET': - return Colors.blue; - case 'POST': - return Colors.green; - case 'PUT': - return Colors.orange; - case 'DELETE': - return Colors.red; - case 'PATCH': - return Colors.purple; - default: - return Colors.grey; - } - } - - Color _getStatusCodeColor(int statusCode) { - if (statusCode >= 200 && statusCode < 300) { - return Colors.green.shade100; - } else if (statusCode >= 300 && statusCode < 400) { - return Colors.blue.shade100; - } else if (statusCode >= 400 && statusCode < 500) { - return Colors.orange.shade100; - } else if (statusCode >= 500) { - return Colors.red.shade100; - } - return Colors.grey.shade100; - } -} diff --git a/flutter_inappwebview/example/lib/widgets/webview/static_method_tester_widget.dart b/flutter_inappwebview/example/lib/widgets/webview/static_method_tester_widget.dart deleted file mode 100644 index f20fbc3398..0000000000 --- a/flutter_inappwebview/example/lib/widgets/webview/static_method_tester_widget.dart +++ /dev/null @@ -1,929 +0,0 @@ -import 'dart:convert'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; -import 'package:flutter_inappwebview_example/widgets/common/support_badge.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_result_history.dart'; - -/// Enum representing available static method types -enum StaticMethodType { - // WebView controller methods - getDefaultUserAgent, - clearClientCertPreferences, - getSafeBrowsingPrivacyPolicyUrl, - setSafeBrowsingAllowlist, - getCurrentWebViewPackage, - setWebContentsDebuggingEnabled, - getVariationsHeader, - isMultiProcessEnabled, - disableWebView, - handlesURLScheme, - clearAllCache, - tRexRunnerHtml, - tRexRunnerCss, - - // In-app browser methods - openWithSystemBrowser, - - // Custom tab / Safari view controller methods - isAvailable, - getMaxToolbarItems, - getPackageName, - clearWebsiteData, - prewarmConnections, - - // Web authentication methods - // isAvailable - already defined above, reused - - // Service worker methods - instance, - - // WebView feature checks - isFeatureSupported, - isStartupFeatureSupported, - - // Process global config methods - apply, - - // Cookie methods - // instance - already defined above, reused - - // HTTP auth credential database methods - // instance - already defined above, reused - - // Web storage methods - // instance - already defined above, reused -} - -/// Enum representing static method class types -enum StaticClassType { - inAppWebViewController( - InAppWebViewController, - 'Static methods for WebView controller', - Icons.web, - ), - inAppBrowser( - InAppBrowser, - 'Static methods for in-app browser', - Icons.open_in_browser, - ), - chromeSafariBrowser( - ChromeSafariBrowser, - 'Static methods for Chrome Custom Tabs / SFSafariViewController', - Icons.tab, - ), - webAuthenticationSession( - WebAuthenticationSession, - 'Static methods for web authentication', - Icons.security, - ), - serviceWorkerController( - ServiceWorkerController, - 'Static methods for service worker control', - Icons.work, - ), - webViewFeature( - WebViewFeature, - 'Check WebView feature support (Android)', - Icons.check_circle, - ), - processGlobalConfig( - ProcessGlobalConfig, - 'Process-level configuration (Android)', - Icons.settings_applications, - ), - cookieManager(CookieManager, 'Cookie management methods', Icons.cookie), - httpAuthCredentialDatabase( - HttpAuthCredentialDatabase, - 'HTTP authentication credential storage', - Icons.lock, - ), - webStorageManager(WebStorageManager, 'Web storage management', Icons.storage); - - final Type apiType; - final String description; - final IconData icon; - - const StaticClassType(this.apiType, this.description, this.icon); - - String get displayName => apiType.toString(); -} - -/// Static method entry for a class's static method -class StaticMethodEntry { - /// The method type enum - name is derived from this - final StaticMethodType methodType; - final String description; - - /// The class name for looking up support info via SupportChecker - final Type classType; - final Map parameters; - final List requiredParameters; - final Future Function(Map params) execute; - - const StaticMethodEntry({ - required this.methodType, - required this.description, - required this.classType, - this.parameters = const {}, - this.requiredParameters = const [], - required this.execute, - }); - - /// The display name derived from methodType.name - String get name => methodType.name; - - /// Returns supported platforms using runtime checks via SupportChecker - Set get supportedPlatforms => - SupportChecker.getSupportedPlatformsForMethod(classType.toString(), name); -} - -/// A class containing static methods -class StaticMethodClass { - /// The class type enum - name, description and icon are derived from this - final StaticClassType classType; - final List methods; - - const StaticMethodClass({required this.classType, required this.methods}); - - /// The display name derived from classType.displayName - String get name => classType.displayName; - - /// The description derived from classType.description - String get description => classType.description; - - /// The icon derived from classType.icon - IconData get icon => classType.icon; -} - -/// Widget to test static methods across WebView-related classes -/// Tests static methods from the controller, browser, and other helpers. -class StaticMethodTesterWidget extends StatefulWidget { - const StaticMethodTesterWidget({super.key}); - - @override - State createState() => - _StaticMethodTesterWidgetState(); -} - -class _StaticMethodTesterWidgetState extends State { - final TextEditingController _searchController = TextEditingController(); - String _searchQuery = ''; - final Map> _methodHistory = {}; - final Map _selectedHistoryIndex = {}; - final Map _executing = {}; - final Set _expandedClasses = {0}; // First class expanded by default - - late final List _classes; - - @override - void initState() { - super.initState(); - _classes = _buildStaticMethodClasses(); - } - - @override - void dispose() { - _searchController.dispose(); - super.dispose(); - } - - List _buildStaticMethodClasses() { - return [ - // WebView controller static methods - StaticMethodClass( - classType: StaticClassType.inAppWebViewController, - methods: [ - StaticMethodEntry( - methodType: StaticMethodType.getDefaultUserAgent, - description: 'Gets the default User-Agent string', - classType: InAppWebViewController, - execute: (params) async { - return await InAppWebViewController.getDefaultUserAgent(); - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.clearClientCertPreferences, - description: 'Clears the client certificate preferences', - classType: InAppWebViewController, - execute: (params) async { - await InAppWebViewController.clearClientCertPreferences(); - return 'Client cert preferences cleared'; - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.getSafeBrowsingPrivacyPolicyUrl, - description: 'Gets the Safe Browsing privacy policy URL', - classType: InAppWebViewController, - execute: (params) async { - final url = - await InAppWebViewController.getSafeBrowsingPrivacyPolicyUrl(); - return url?.toString() ?? 'No URL available'; - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.setSafeBrowsingAllowlist, - description: 'Sets the Safe Browsing allowlist', - classType: InAppWebViewController, - parameters: {'hosts': 'example.com,test.com'}, - requiredParameters: ['hosts'], - execute: (params) async { - final hostsStr = params['hosts']?.toString() ?? ''; - final hosts = hostsStr.split(',').map((h) => h.trim()).toList(); - final result = - await InAppWebViewController.setSafeBrowsingAllowlist( - hosts: hosts, - ); - return result - ? 'Allowlist set successfully' - : 'Failed to set allowlist'; - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.getCurrentWebViewPackage, - description: 'Gets the current WebView package info', - classType: InAppWebViewController, - execute: (params) async { - final pkg = - await InAppWebViewController.getCurrentWebViewPackage(); - if (pkg == null) return 'No WebView package info'; - return 'Package: ${pkg.packageName}\nVersion: ${pkg.versionName}'; - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.setWebContentsDebuggingEnabled, - description: 'Enables or disables WebView debugging', - classType: InAppWebViewController, - parameters: {'debuggingEnabled': true}, - requiredParameters: ['debuggingEnabled'], - execute: (params) async { - final enabled = params['debuggingEnabled'] as bool? ?? true; - await InAppWebViewController.setWebContentsDebuggingEnabled( - enabled, - ); - return 'Debugging ${enabled ? "enabled" : "disabled"}'; - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.getVariationsHeader, - description: 'Gets the variations header', - classType: InAppWebViewController, - execute: (params) async { - final header = await InAppWebViewController.getVariationsHeader(); - return header ?? 'No variations header'; - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.isMultiProcessEnabled, - description: 'Checks if multi-process is enabled', - classType: InAppWebViewController, - execute: (params) async { - return await InAppWebViewController.isMultiProcessEnabled(); - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.disableWebView, - description: 'Disables the WebView', - classType: InAppWebViewController, - execute: (params) async { - await InAppWebViewController.disableWebView(); - return 'WebView disabled'; - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.handlesURLScheme, - description: 'Checks if WebView handles a URL scheme', - classType: InAppWebViewController, - parameters: {'urlScheme': 'https'}, - requiredParameters: ['urlScheme'], - execute: (params) async { - final scheme = params['urlScheme']?.toString() ?? 'https'; - return await InAppWebViewController.handlesURLScheme(scheme); - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.clearAllCache, - description: 'Clears all WebView caches', - classType: InAppWebViewController, - parameters: {'includeDiskFiles': true}, - execute: (params) async { - final includeDiskFiles = - params['includeDiskFiles'] as bool? ?? true; - await InAppWebViewController.clearAllCache( - includeDiskFiles: includeDiskFiles, - ); - return 'Cache cleared'; - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.tRexRunnerHtml, - description: 'Gets the T-Rex Runner game HTML', - classType: InAppWebViewController, - execute: (params) async { - final html = await InAppWebViewController.tRexRunnerHtml; - if (html.length > 200) { - return '${html.substring(0, 200)}... (${html.length} chars total)'; - } - return html; - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.tRexRunnerCss, - description: 'Gets the T-Rex Runner game CSS', - classType: InAppWebViewController, - execute: (params) async { - final css = await InAppWebViewController.tRexRunnerCss; - if (css.length > 200) { - return '${css.substring(0, 200)}... (${css.length} chars total)'; - } - return css; - }, - ), - ], - ), - - // In-app browser static methods - StaticMethodClass( - classType: StaticClassType.inAppBrowser, - methods: [ - StaticMethodEntry( - methodType: StaticMethodType.openWithSystemBrowser, - description: 'Opens a URL in the system browser', - classType: InAppBrowser, - parameters: {'url': 'https://flutter.dev'}, - requiredParameters: ['url'], - execute: (params) async { - final url = params['url']?.toString() ?? 'https://flutter.dev'; - await InAppBrowser.openWithSystemBrowser(url: WebUri(url)); - return 'Opened in system browser'; - }, - ), - ], - ), - - // Custom tab / Safari view controller static methods - StaticMethodClass( - classType: StaticClassType.chromeSafariBrowser, - methods: [ - StaticMethodEntry( - methodType: StaticMethodType.isAvailable, - description: - 'Checks if Chrome Custom Tabs / SFSafariViewController is available', - classType: ChromeSafariBrowser, - execute: (params) async { - return await ChromeSafariBrowser.isAvailable(); - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.getMaxToolbarItems, - description: 'Gets the maximum toolbar items (Android only)', - classType: ChromeSafariBrowser, - execute: (params) async { - return await ChromeSafariBrowser.getMaxToolbarItems(); - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.getPackageName, - description: 'Gets the package name for Custom Tabs (Android only)', - classType: ChromeSafariBrowser, - execute: (params) async { - final packageName = await ChromeSafariBrowser.getPackageName(); - return packageName ?? 'No package available'; - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.clearWebsiteData, - description: 'Clears website data (Android only)', - classType: ChromeSafariBrowser, - execute: (params) async { - await ChromeSafariBrowser.clearWebsiteData(); - return 'Website data cleared'; - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.prewarmConnections, - description: 'Prewarms connections (iOS only)', - classType: ChromeSafariBrowser, - parameters: {'urls': 'https://flutter.dev,https://dart.dev'}, - requiredParameters: ['urls'], - execute: (params) async { - final urlsStr = params['urls']?.toString() ?? ''; - final urls = urlsStr - .split(',') - .map((u) => WebUri(u.trim())) - .toList(); - final token = await ChromeSafariBrowser.prewarmConnections(urls); - return token != null - ? 'Prewarming token: ${token.hashCode}' - : 'Prewarming failed'; - }, - ), - ], - ), - - // WebAuthenticationSession static methods - StaticMethodClass( - classType: StaticClassType.webAuthenticationSession, - methods: [ - StaticMethodEntry( - methodType: StaticMethodType.isAvailable, - description: 'Checks if web authentication is available', - classType: WebAuthenticationSession, - execute: (params) async { - return await WebAuthenticationSession.isAvailable(); - }, - ), - ], - ), - - // ServiceWorkerController static methods - StaticMethodClass( - classType: StaticClassType.serviceWorkerController, - methods: [ - StaticMethodEntry( - methodType: StaticMethodType.instance, - description: 'Gets the singleton instance', - classType: ServiceWorkerController, - execute: (params) async { - final controller = ServiceWorkerController.instance(); - return '${ServiceWorkerController} instance: ${controller.hashCode}'; - }, - ), - ], - ), - - // WebViewFeature static methods - StaticMethodClass( - classType: StaticClassType.webViewFeature, - methods: [ - StaticMethodEntry( - methodType: StaticMethodType.isFeatureSupported, - description: 'Checks if a WebView feature is supported', - classType: WebViewFeature, - parameters: {'feature': WebViewFeature.WEB_MESSAGE_LISTENER.name()}, - requiredParameters: ['feature'], - execute: (params) async { - final featureName = - params['feature']?.toString() ?? - WebViewFeature.WEB_MESSAGE_LISTENER.name(); - final feature = WebViewFeature.values.firstWhere( - (f) => f.name().toUpperCase() == featureName.toUpperCase(), - orElse: () => WebViewFeature.WEB_MESSAGE_LISTENER, - ); - return await WebViewFeature.isFeatureSupported(feature); - }, - ), - StaticMethodEntry( - methodType: StaticMethodType.isStartupFeatureSupported, - description: 'Checks if a startup feature is supported', - classType: WebViewFeature, - parameters: { - 'feature': WebViewFeature - .STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX - .name(), - }, - requiredParameters: ['feature'], - execute: (params) async { - final featureName = - params['feature']?.toString() ?? - WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX - .name(); - final feature = WebViewFeature.values.firstWhere( - (f) => f.name().toUpperCase() == featureName.toUpperCase(), - orElse: () => - WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX, - ); - return await WebViewFeature.isStartupFeatureSupported(feature); - }, - ), - ], - ), - - // ProcessGlobalConfig static methods - StaticMethodClass( - classType: StaticClassType.processGlobalConfig, - methods: [ - StaticMethodEntry( - methodType: StaticMethodType.apply, - description: 'Applies process global config', - classType: ProcessGlobalConfig, - parameters: {'dataDirectorySuffix': ''}, - execute: (params) async { - final suffix = params['dataDirectorySuffix']?.toString(); - await ProcessGlobalConfig.instance().apply( - settings: ProcessGlobalConfigSettings( - dataDirectorySuffix: suffix?.isNotEmpty == true - ? suffix - : null, - ), - ); - return 'Config applied'; - }, - ), - ], - ), - - // CookieManager static methods - StaticMethodClass( - classType: StaticClassType.cookieManager, - methods: [ - StaticMethodEntry( - methodType: StaticMethodType.instance, - description: 'Gets the singleton instance', - classType: CookieManager, - execute: (params) async { - final manager = CookieManager.instance(); - return '${CookieManager} instance: ${manager.hashCode}'; - }, - ), - ], - ), - - // HttpAuthCredentialDatabase static methods - StaticMethodClass( - classType: StaticClassType.httpAuthCredentialDatabase, - methods: [ - StaticMethodEntry( - methodType: StaticMethodType.instance, - description: 'Gets the singleton instance', - classType: HttpAuthCredentialDatabase, - execute: (params) async { - final db = HttpAuthCredentialDatabase.instance(); - return '${HttpAuthCredentialDatabase} instance: ${db.hashCode}'; - }, - ), - ], - ), - - // WebStorageManager static methods - StaticMethodClass( - classType: StaticClassType.webStorageManager, - methods: [ - StaticMethodEntry( - methodType: StaticMethodType.instance, - description: 'Gets the singleton instance', - classType: WebStorageManager, - execute: (params) async { - final manager = WebStorageManager.instance(); - return '${WebStorageManager} instance: ${manager.hashCode}'; - }, - ), - ], - ), - ]; - } - - List _getFilteredClasses() { - if (_searchQuery.isEmpty) { - return _classes; - } - - final query = _searchQuery.toLowerCase(); - return _classes - .map((cls) { - final filteredMethods = cls.methods - .where( - (method) => - method.name.toLowerCase().contains(query) || - method.description.toLowerCase().contains(query) || - cls.name.toLowerCase().contains(query), - ) - .toList(); - return StaticMethodClass( - classType: cls.classType, - methods: filteredMethods, - ); - }) - .where((cls) => cls.methods.isNotEmpty) - .toList(); - } - - String _methodKey(String className, String methodName) => - '$className.$methodName'; - - Future _executeMethod( - StaticMethodClass cls, - StaticMethodEntry entry, - ) async { - final key = _methodKey(cls.name, entry.name); - setState(() { - _executing[key] = true; - }); - - try { - Map params = entry.parameters; - if (entry.parameters.isNotEmpty) { - final updatedParams = await showParameterDialog( - context: context, - title: '${cls.name}.${entry.name} parameters', - parameters: entry.parameters, - requiredPaths: entry.requiredParameters, - ); - - if (updatedParams == null) { - if (mounted) { - setState(() { - _executing[key] = false; - }); - } - return; - } - params = updatedParams; - } - - final result = await entry.execute(params); - if (mounted) { - setState(() { - _addMethodHistoryEntry( - key, - _formatResult(result), - isError: false, - value: result, - ); - _executing[key] = false; - }); - } - } catch (e) { - if (mounted) { - setState(() { - _addMethodHistoryEntry(key, e.toString(), isError: true); - _executing[key] = false; - }); - } - } - } - - void _addMethodHistoryEntry( - String methodKey, - String message, { - required bool isError, - dynamic value, - }) { - final current = List.from( - _methodHistory[methodKey] ?? const [], - ); - current.insert( - 0, - MethodResultEntry( - message: message, - isError: isError, - timestamp: DateTime.now(), - value: value, - ), - ); - if (current.length > 3) { - current.removeRange(3, current.length); - } - _methodHistory[methodKey] = current; - _selectedHistoryIndex[methodKey] = 0; - } - - String _formatResult(dynamic result) { - if (result == null) return 'null'; - if (result is String) return result; - - final mapResult = _toMapIfPossible(result); - if (mapResult != null) { - try { - const encoder = JsonEncoder.withIndent(' '); - return encoder.convert(mapResult); - } catch (e) { - return mapResult.toString(); - } - } - - if (result is Map || result is List) { - try { - const encoder = JsonEncoder.withIndent(' '); - return encoder.convert(result); - } catch (e) { - return result.toString(); - } - } - return result.toString(); - } - - dynamic _toMapIfPossible(dynamic value) { - if (value == null) return null; - if (value is Map || value is List) return value; - - try { - final toMapResult = (value as dynamic).toMap?.call(); - if (toMapResult is Map) return toMapResult; - } catch (_) {} - - try { - final toJsonResult = (value as dynamic).toJson?.call(); - if (toJsonResult is Map) return toJsonResult; - } catch (_) {} - - return null; - } - - @override - Widget build(BuildContext context) { - final filteredClasses = _getFilteredClasses(); - final totalMethods = _classes.fold( - 0, - (sum, cls) => sum + cls.methods.length, - ); - - return Column( - children: [ - // Header with search - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.grey.shade100, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - const Icon(Icons.functions, size: 20), - const SizedBox(width: 8), - Flexible( - child: Text( - 'Static Method Tester ($totalMethods methods)', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), - ], - ), - const SizedBox(height: 8), - TextField( - controller: _searchController, - decoration: InputDecoration( - hintText: 'Search static methods...', - prefixIcon: const Icon(Icons.search, size: 20), - suffixIcon: _searchQuery.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear, size: 20), - onPressed: () { - _searchController.clear(); - setState(() => _searchQuery = ''); - }, - ) - : null, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - isDense: true, - ), - onChanged: (value) => setState(() => _searchQuery = value), - ), - ], - ), - ), - - // Info banner - Container( - padding: const EdgeInsets.all(12), - color: Colors.blue.shade50, - child: const Row( - children: [ - Icon(Icons.info, color: Colors.blue, size: 20), - SizedBox(width: 8), - Expanded( - child: Text( - 'Static methods can be called without a WebView instance.', - style: TextStyle(color: Colors.blue), - ), - ), - ], - ), - ), - - // Method classes - Expanded( - child: ListView.builder( - itemCount: filteredClasses.length, - itemBuilder: (context, classIndex) { - final cls = filteredClasses[classIndex]; - final originalIndex = _classes.indexOf(cls); - final isExpanded = - _searchQuery.isNotEmpty || - _expandedClasses.contains(originalIndex); - - return ExpansionTile( - key: Key(cls.name), - initiallyExpanded: isExpanded, - leading: Icon(cls.icon, size: 24), - title: Text( - '${cls.name} (${cls.methods.length})', - style: const TextStyle(fontWeight: FontWeight.w600), - ), - subtitle: Text( - cls.description, - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - onExpansionChanged: (expanded) { - setState(() { - if (expanded) { - _expandedClasses.add(originalIndex); - } else { - _expandedClasses.remove(originalIndex); - } - }); - }, - children: cls.methods - .map((method) => _buildMethodTile(cls, method)) - .toList(), - ); - }, - ), - ), - ], - ); - } - - Widget _buildMethodTile(StaticMethodClass cls, StaticMethodEntry method) { - final key = _methodKey(cls.name, method.name); - final isExecuting = _executing[key] == true; - final historyEntries = _methodHistory[key] ?? const []; - - return Container( - margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey.shade300), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Method header - ListTile( - dense: true, - title: Text( - '${cls.name}.${method.name}', - style: const TextStyle( - fontWeight: FontWeight.w600, - fontFamily: 'monospace', - fontSize: 13, - ), - ), - subtitle: Padding( - padding: const EdgeInsets.only(top: 4), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - method.description, - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - const SizedBox(height: 6), - SupportBadgesRow( - supportedPlatforms: method.supportedPlatforms, - compact: true, - ), - ], - ), - ), - trailing: SizedBox( - width: 80, - height: 32, - child: ElevatedButton( - onPressed: isExecuting - ? null - : () => _executeMethod(cls, method), - style: ElevatedButton.styleFrom( - padding: EdgeInsets.zero, - textStyle: const TextStyle(fontSize: 11), - ), - child: isExecuting - ? const SizedBox( - width: 16, - height: 16, - child: CircularProgressIndicator(strokeWidth: 2), - ) - : const Text('Execute'), - ), - ), - ), - - if (historyEntries.isNotEmpty) - Padding( - padding: const EdgeInsets.fromLTRB(12, 0, 12, 12), - child: MethodResultHistory( - entries: historyEntries, - selectedIndex: _selectedHistoryIndex[key], - onSelected: (index) { - setState(() => _selectedHistoryIndex[key] = index); - }, - ), - ), - ], - ), - ); - } -} diff --git a/flutter_inappwebview/example/lib/widgets/webview/user_script_tester_widget.dart b/flutter_inappwebview/example/lib/widgets/webview/user_script_tester_widget.dart deleted file mode 100644 index 1c2db183bd..0000000000 --- a/flutter_inappwebview/example/lib/widgets/webview/user_script_tester_widget.dart +++ /dev/null @@ -1,304 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; - -/// Widget to test user script injection -class UserScriptTesterWidget extends StatefulWidget { - final Future Function(UserScript script) onAddScript; - final Future Function(UserScript script) onRemoveScript; - final List? scripts; - - const UserScriptTesterWidget({ - super.key, - required this.onAddScript, - required this.onRemoveScript, - this.scripts, - }); - - @override - State createState() => _UserScriptTesterWidgetState(); -} - -class _UserScriptTesterWidgetState extends State { - final TextEditingController _sourceController = TextEditingController(); - UserScriptInjectionTime _injectionTime = - UserScriptInjectionTime.AT_DOCUMENT_START; - bool _forMainFrameOnly = false; - bool _isAdding = false; - - @override - void dispose() { - _sourceController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return CustomScrollView( - slivers: [ - SliverToBoxAdapter(child: _buildHeader()), - SliverToBoxAdapter(child: _buildForm()), - _buildScriptList(), - ], - ); - } - - Widget _buildHeader() { - return Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: Colors.grey.shade100, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: const Row( - children: [ - Text( - 'User Scripts', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), - ), - ], - ), - ); - } - - Widget _buildForm() { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - border: Border(bottom: BorderSide(color: Colors.grey.shade300)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Add User Script', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14), - ), - const SizedBox(height: 4), - TextField( - controller: _sourceController, - decoration: const InputDecoration( - hintText: 'Enter JavaScript source code', - border: OutlineInputBorder(), - contentPadding: EdgeInsets.all(12), - ), - maxLines: 2, - onChanged: (_) => setState(() {}), - ), - const SizedBox(height: 4), - Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Injection Time', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 4), - DropdownButton( - value: _injectionTime, - isExpanded: true, - items: UserScriptInjectionTime.values.map((time) { - return DropdownMenuItem( - value: time, - child: Text( - time.toString().split('.').last, - style: const TextStyle(fontSize: 12), - ), - ); - }).toList(), - onChanged: (value) { - if (value != null) { - setState(() { - _injectionTime = value; - }); - } - }, - ), - ], - ), - ), - const SizedBox(width: 16), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Main Frame Only', - style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold), - ), - Switch( - value: _forMainFrameOnly, - onChanged: (value) { - setState(() { - _forMainFrameOnly = value; - }); - }, - ), - ], - ), - ], - ), - const SizedBox(height: 12), - SizedBox( - width: double.infinity, - child: ElevatedButton( - onPressed: _sourceController.text.trim().isEmpty || _isAdding - ? null - : _addScript, - child: _isAdding - ? const SizedBox( - height: 16, - width: 16, - child: CircularProgressIndicator(strokeWidth: 2), - ) - : const Text('Add Script'), - ), - ), - ], - ), - ); - } - - Widget _buildScriptList() { - final scripts = widget.scripts ?? []; - - if (scripts.isEmpty) { - return const SliverFillRemaining( - hasScrollBody: false, - child: Center( - child: Text( - 'No user scripts added', - style: TextStyle(color: Colors.grey), - ), - ), - ); - } - - return SliverList( - delegate: SliverChildBuilderDelegate((context, index) { - final script = scripts[index]; - return _buildScriptItem(script, index); - }, childCount: scripts.length), - ); - } - - Widget _buildScriptItem(UserScript script, int index) { - return Card( - margin: const EdgeInsets.all(8), - child: Padding( - padding: const EdgeInsets.all(12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - child: Text( - 'Script ${index + 1}', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - ), - ), - ), - IconButton( - icon: const Icon(Icons.delete, color: Colors.red), - tooltip: 'Remove', - onPressed: () => _removeScript(script), - ), - ], - ), - const SizedBox(height: 8), - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.grey.shade100, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - script.source, - style: const TextStyle(fontSize: 11, fontFamily: 'monospace'), - maxLines: 3, - overflow: TextOverflow.ellipsis, - ), - ), - const SizedBox(height: 8), - Wrap( - spacing: 8, - children: [ - Chip( - label: Text( - script.injectionTime.toString().split('.').last, - style: const TextStyle(fontSize: 10), - ), - backgroundColor: Colors.blue.shade100, - padding: EdgeInsets.zero, - ), - if (script.forMainFrameOnly) - Chip( - label: const Text( - 'Main Frame Only', - style: TextStyle(fontSize: 10), - ), - backgroundColor: Colors.green.shade100, - padding: EdgeInsets.zero, - ), - ], - ), - ], - ), - ), - ); - } - - Future _addScript() async { - final source = _sourceController.text.trim(); - if (source.isEmpty) return; - - setState(() { - _isAdding = true; - }); - - try { - final script = UserScript( - source: source, - injectionTime: _injectionTime, - forMainFrameOnly: _forMainFrameOnly, - ); - - await widget.onAddScript(script); - - setState(() { - _sourceController.clear(); - _isAdding = false; - }); - } catch (e) { - setState(() { - _isAdding = false; - }); - - if (mounted) { - ScaffoldMessenger.of( - context, - ).showSnackBar(SnackBar(content: Text('Failed to add script: $e'))); - } - } - } - - Future _removeScript(UserScript script) async { - try { - await widget.onRemoveScript(script); - } catch (e) { - if (mounted) { - ScaffoldMessenger.of( - context, - ).showSnackBar(SnackBar(content: Text('Failed to remove script: $e'))); - } - } - } -} diff --git a/flutter_inappwebview/example/linux/.gitignore b/flutter_inappwebview/example/linux/.gitignore deleted file mode 100644 index d3896c9844..0000000000 --- a/flutter_inappwebview/example/linux/.gitignore +++ /dev/null @@ -1 +0,0 @@ -flutter/ephemeral diff --git a/flutter_inappwebview/example/linux/CMakeLists.txt b/flutter_inappwebview/example/linux/CMakeLists.txt deleted file mode 100644 index 8b5f1854d3..0000000000 --- a/flutter_inappwebview/example/linux/CMakeLists.txt +++ /dev/null @@ -1,128 +0,0 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.13) -project(runner LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "flutter_inappwebview_example") -# The unique GTK application identifier for this application. See: -# https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.pichillilorenzo.flutter_inappwebview_example") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(SET CMP0063 NEW) - -# Load bundled libraries from the lib/ directory relative to the binary. -set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") - -# Root filesystem for cross-building. -if(FLUTTER_TARGET_PLATFORM_SYSROOT) - set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endif() - -# Define build configuration options. -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") -endif() - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_14) - target_compile_options(${TARGET} PRIVATE -Wall -Werror) - target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") - target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) - -# Application build; see runner/CMakeLists.txt. -add_subdirectory("runner") - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) - -# Only the install-generated bundle's copy of the executable will launch -# correctly, since the resources must in the right relative locations. To avoid -# people trying to run the unbundled copy, put it in a subdirectory instead of -# the default top-level location. -set_target_properties(${BINARY_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" -) - - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# By default, "installing" just makes a relocatable bundle in the build -# directory. -set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -# Start with a clean build bundle directory every time. -install(CODE " - file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") - " COMPONENT Runtime) - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) - install(FILES "${bundled_library}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endforeach(bundled_library) - -# Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") -install(DIRECTORY "${NATIVE_ASSETS_DIR}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") - install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() diff --git a/flutter_inappwebview/example/linux/flutter/CMakeLists.txt b/flutter_inappwebview/example/linux/flutter/CMakeLists.txt deleted file mode 100644 index d5bd01648a..0000000000 --- a/flutter_inappwebview/example/linux/flutter/CMakeLists.txt +++ /dev/null @@ -1,88 +0,0 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.10) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. - -# Serves the same purpose as list(TRANSFORM ... PREPEND ...), -# which isn't available in 3.10. -function(list_prepend LIST_NAME PREFIX) - set(NEW_LIST "") - foreach(element ${${LIST_NAME}}) - list(APPEND NEW_LIST "${PREFIX}${element}") - endforeach(element) - set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) -endfunction() - -# === Flutter Library === -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) -pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) - -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "fl_basic_message_channel.h" - "fl_binary_codec.h" - "fl_binary_messenger.h" - "fl_dart_project.h" - "fl_engine.h" - "fl_json_message_codec.h" - "fl_json_method_codec.h" - "fl_message_codec.h" - "fl_method_call.h" - "fl_method_channel.h" - "fl_method_codec.h" - "fl_method_response.h" - "fl_plugin_registrar.h" - "fl_plugin_registry.h" - "fl_standard_message_codec.h" - "fl_standard_method_codec.h" - "fl_string_codec.h" - "fl_value.h" - "fl_view.h" - "flutter_linux.h" -) -list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") -target_link_libraries(flutter INTERFACE - PkgConfig::GTK - PkgConfig::GLIB - PkgConfig::GIO -) -add_dependencies(flutter flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CMAKE_CURRENT_BINARY_DIR}/_phony_ - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" - ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} -) diff --git a/flutter_inappwebview/example/linux/flutter/generated_plugin_registrant.cc b/flutter_inappwebview/example/linux/flutter/generated_plugin_registrant.cc deleted file mode 100644 index 3c2a0e1378..0000000000 --- a/flutter_inappwebview/example/linux/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,19 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - -#include -#include - -void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) flutter_inappwebview_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterInappwebviewLinuxPlugin"); - flutter_inappwebview_linux_plugin_register_with_registrar(flutter_inappwebview_linux_registrar); - g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); - url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); -} diff --git a/flutter_inappwebview/example/linux/flutter/generated_plugin_registrant.h b/flutter_inappwebview/example/linux/flutter/generated_plugin_registrant.h deleted file mode 100644 index e0f0a47bc0..0000000000 --- a/flutter_inappwebview/example/linux/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void fl_register_plugins(FlPluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/flutter_inappwebview/example/linux/flutter/generated_plugins.cmake b/flutter_inappwebview/example/linux/flutter/generated_plugins.cmake deleted file mode 100644 index 87e695bb98..0000000000 --- a/flutter_inappwebview/example/linux/flutter/generated_plugins.cmake +++ /dev/null @@ -1,25 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST - flutter_inappwebview_linux - url_launcher_linux -) - -list(APPEND FLUTTER_FFI_PLUGIN_LIST -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) - -foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) -endforeach(ffi_plugin) diff --git a/flutter_inappwebview/example/linux/runner/CMakeLists.txt b/flutter_inappwebview/example/linux/runner/CMakeLists.txt deleted file mode 100644 index e97dabc702..0000000000 --- a/flutter_inappwebview/example/linux/runner/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -cmake_minimum_required(VERSION 3.13) -project(runner LANGUAGES CXX) - -# Define the application target. To change its name, change BINARY_NAME in the -# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer -# work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add preprocessor definitions for the application ID. -add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") - -# Add dependency libraries. Add any application-specific dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter) -target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) - -target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/flutter_inappwebview/example/linux/runner/main.cc b/flutter_inappwebview/example/linux/runner/main.cc deleted file mode 100644 index e7c5c54370..0000000000 --- a/flutter_inappwebview/example/linux/runner/main.cc +++ /dev/null @@ -1,6 +0,0 @@ -#include "my_application.h" - -int main(int argc, char** argv) { - g_autoptr(MyApplication) app = my_application_new(); - return g_application_run(G_APPLICATION(app), argc, argv); -} diff --git a/flutter_inappwebview/example/linux/runner/my_application.cc b/flutter_inappwebview/example/linux/runner/my_application.cc deleted file mode 100644 index dc12fb766a..0000000000 --- a/flutter_inappwebview/example/linux/runner/my_application.cc +++ /dev/null @@ -1,148 +0,0 @@ -#include "my_application.h" - -#include -#ifdef GDK_WINDOWING_X11 -#include -#endif - -#include "flutter/generated_plugin_registrant.h" - -struct _MyApplication { - GtkApplication parent_instance; - char** dart_entrypoint_arguments; -}; - -G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) - -// Called when first Flutter frame received. -static void first_frame_cb(MyApplication* self, FlView* view) { - gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); -} - -// Implements GApplication::activate. -static void my_application_activate(GApplication* application) { - MyApplication* self = MY_APPLICATION(application); - GtkWindow* window = - GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); - - // Use a header bar when running in GNOME as this is the common style used - // by applications and is the setup most users will be using (e.g. Ubuntu - // desktop). - // If running on X and not using GNOME then just use a traditional title bar - // in case the window manager does more exotic layout, e.g. tiling. - // If running on Wayland assume the header bar will work (may need changing - // if future cases occur). - gboolean use_header_bar = TRUE; -#ifdef GDK_WINDOWING_X11 - GdkScreen* screen = gtk_window_get_screen(window); - if (GDK_IS_X11_SCREEN(screen)) { - const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); - if (g_strcmp0(wm_name, "GNOME Shell") != 0) { - use_header_bar = FALSE; - } - } -#endif - if (use_header_bar) { - GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); - gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "flutter_inappwebview_example"); - gtk_header_bar_set_show_close_button(header_bar, TRUE); - gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); - } else { - gtk_window_set_title(window, "flutter_inappwebview_example"); - } - - gtk_window_set_default_size(window, 1280, 720); - - g_autoptr(FlDartProject) project = fl_dart_project_new(); - fl_dart_project_set_dart_entrypoint_arguments( - project, self->dart_entrypoint_arguments); - - FlView* view = fl_view_new(project); - GdkRGBA background_color; - // Background defaults to black, override it here if necessary, e.g. #00000000 - // for transparent. - gdk_rgba_parse(&background_color, "#000000"); - fl_view_set_background_color(view, &background_color); - gtk_widget_show(GTK_WIDGET(view)); - gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); - - // Show the window when Flutter renders. - // Requires the view to be realized so we can start rendering. - g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), - self); - gtk_widget_realize(GTK_WIDGET(view)); - - fl_register_plugins(FL_PLUGIN_REGISTRY(view)); - - gtk_widget_grab_focus(GTK_WIDGET(view)); -} - -// Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, - gchar*** arguments, - int* exit_status) { - MyApplication* self = MY_APPLICATION(application); - // Strip out the first argument as it is the binary name. - self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); - - g_autoptr(GError) error = nullptr; - if (!g_application_register(application, nullptr, &error)) { - g_warning("Failed to register: %s", error->message); - *exit_status = 1; - return TRUE; - } - - g_application_activate(application); - *exit_status = 0; - - return TRUE; -} - -// Implements GApplication::startup. -static void my_application_startup(GApplication* application) { - // MyApplication* self = MY_APPLICATION(object); - - // Perform any actions required at application startup. - - G_APPLICATION_CLASS(my_application_parent_class)->startup(application); -} - -// Implements GApplication::shutdown. -static void my_application_shutdown(GApplication* application) { - // MyApplication* self = MY_APPLICATION(object); - - // Perform any actions required at application shutdown. - - G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); -} - -// Implements GObject::dispose. -static void my_application_dispose(GObject* object) { - MyApplication* self = MY_APPLICATION(object); - g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); - G_OBJECT_CLASS(my_application_parent_class)->dispose(object); -} - -static void my_application_class_init(MyApplicationClass* klass) { - G_APPLICATION_CLASS(klass)->activate = my_application_activate; - G_APPLICATION_CLASS(klass)->local_command_line = - my_application_local_command_line; - G_APPLICATION_CLASS(klass)->startup = my_application_startup; - G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; - G_OBJECT_CLASS(klass)->dispose = my_application_dispose; -} - -static void my_application_init(MyApplication* self) {} - -MyApplication* my_application_new() { - // Set the program name to the application ID, which helps various systems - // like GTK and desktop environments map this running application to its - // corresponding .desktop file. This ensures better integration by allowing - // the application to be recognized beyond its binary name. - g_set_prgname(APPLICATION_ID); - - return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, "flags", - G_APPLICATION_NON_UNIQUE, nullptr)); -} diff --git a/flutter_inappwebview/example/linux/runner/my_application.h b/flutter_inappwebview/example/linux/runner/my_application.h deleted file mode 100644 index db16367a77..0000000000 --- a/flutter_inappwebview/example/linux/runner/my_application.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef FLUTTER_MY_APPLICATION_H_ -#define FLUTTER_MY_APPLICATION_H_ - -#include - -G_DECLARE_FINAL_TYPE(MyApplication, - my_application, - MY, - APPLICATION, - GtkApplication) - -/** - * my_application_new: - * - * Creates a new Flutter-based application. - * - * Returns: a new #MyApplication. - */ -MyApplication* my_application_new(); - -#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/flutter_inappwebview/example/macos/.gitignore b/flutter_inappwebview/example/macos/.gitignore deleted file mode 100644 index 746adbb6b9..0000000000 --- a/flutter_inappwebview/example/macos/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Flutter-related -**/Flutter/ephemeral/ -**/Pods/ - -# Xcode-related -**/dgph -**/xcuserdata/ diff --git a/flutter_inappwebview/example/macos/Flutter/Flutter-Debug.xcconfig b/flutter_inappwebview/example/macos/Flutter/Flutter-Debug.xcconfig deleted file mode 100644 index 4b81f9b2d2..0000000000 --- a/flutter_inappwebview/example/macos/Flutter/Flutter-Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/flutter_inappwebview/example/macos/Flutter/Flutter-Release.xcconfig b/flutter_inappwebview/example/macos/Flutter/Flutter-Release.xcconfig deleted file mode 100644 index 5caa9d1579..0000000000 --- a/flutter_inappwebview/example/macos/Flutter/Flutter-Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/flutter_inappwebview/example/macos/Flutter/GeneratedPluginRegistrant.swift b/flutter_inappwebview/example/macos/Flutter/GeneratedPluginRegistrant.swift deleted file mode 100644 index 79a19297ac..0000000000 --- a/flutter_inappwebview/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// Generated file. Do not edit. -// - -import FlutterMacOS -import Foundation - -import file_picker -import flutter_inappwebview_macos -import shared_preferences_foundation -import url_launcher_macos - -func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) - InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) - SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) - UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) -} diff --git a/flutter_inappwebview/example/macos/Podfile b/flutter_inappwebview/example/macos/Podfile deleted file mode 100644 index 9ec46f8cd5..0000000000 --- a/flutter_inappwebview/example/macos/Podfile +++ /dev/null @@ -1,40 +0,0 @@ -platform :osx, '10.15' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_macos_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_macos_build_settings(target) - end -end diff --git a/flutter_inappwebview/example/macos/Runner.xcodeproj/project.pbxproj b/flutter_inappwebview/example/macos/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 71402364c7..0000000000 --- a/flutter_inappwebview/example/macos/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,638 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXAggregateTarget section */ - 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; - buildPhases = ( - 33CC111E2044C6BF0003C045 /* ShellScript */, - ); - dependencies = ( - ); - name = "Flutter Assemble"; - productName = FLX; - }; -/* End PBXAggregateTarget section */ - -/* Begin PBXBuildFile section */ - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 635B80423A5381B66E47F216 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A3C8BEF4D338BF1EDD832305 /* Pods_Runner.framework */; }; - 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC111A2044C6BA0003C045; - remoteInfo = FLX; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Bundle Framework"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* flutter_inappwebview_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = flutter_inappwebview_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; - 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; - 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; - 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 7D4269DF6E938B573DA3AB1B /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - A3C8BEF4D338BF1EDD832305 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - AC8274DF424C630859617712 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - B44881B5FC807BDF77BD81E9 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 33CC10EA2044A3C60003C045 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, - 635B80423A5381B66E47F216 /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 33BA886A226E78AF003329D5 /* Configs */ = { - isa = PBXGroup; - children = ( - 33E5194F232828860026EE4D /* AppInfo.xcconfig */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, - ); - path = Configs; - sourceTree = ""; - }; - 33CC10E42044A3C60003C045 = { - isa = PBXGroup; - children = ( - 33FAB671232836740065AC1E /* Runner */, - 33CEB47122A05771004F2AC0 /* Flutter */, - 33CC10EE2044A3C60003C045 /* Products */, - D73912EC22F37F3D000D13A0 /* Frameworks */, - DE8EF0F1212CA8BCD731BA0F /* Pods */, - ); - sourceTree = ""; - }; - 33CC10EE2044A3C60003C045 /* Products */ = { - isa = PBXGroup; - children = ( - 33CC10ED2044A3C60003C045 /* flutter_inappwebview_example.app */, - ); - name = Products; - sourceTree = ""; - }; - 33CC11242044D66E0003C045 /* Resources */ = { - isa = PBXGroup; - children = ( - 33CC10F22044A3C60003C045 /* Assets.xcassets */, - 33CC10F42044A3C60003C045 /* MainMenu.xib */, - 33CC10F72044A3C60003C045 /* Info.plist */, - ); - name = Resources; - path = ..; - sourceTree = ""; - }; - 33CEB47122A05771004F2AC0 /* Flutter */ = { - isa = PBXGroup; - children = ( - 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - ); - path = Flutter; - sourceTree = ""; - }; - 33FAB671232836740065AC1E /* Runner */ = { - isa = PBXGroup; - children = ( - 33CC10F02044A3C60003C045 /* AppDelegate.swift */, - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, - 33E51913231747F40026EE4D /* DebugProfile.entitlements */, - 33E51914231749380026EE4D /* Release.entitlements */, - 33CC11242044D66E0003C045 /* Resources */, - 33BA886A226E78AF003329D5 /* Configs */, - ); - path = Runner; - sourceTree = ""; - }; - D73912EC22F37F3D000D13A0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - A3C8BEF4D338BF1EDD832305 /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - DE8EF0F1212CA8BCD731BA0F /* Pods */ = { - isa = PBXGroup; - children = ( - AC8274DF424C630859617712 /* Pods-Runner.debug.xcconfig */, - 7D4269DF6E938B573DA3AB1B /* Pods-Runner.release.xcconfig */, - B44881B5FC807BDF77BD81E9 /* Pods-Runner.profile.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 33CC10EC2044A3C60003C045 /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 2233BC408EAD04A8B5721F92 /* [CP] Check Pods Manifest.lock */, - 33CC10E92044A3C60003C045 /* Sources */, - 33CC10EA2044A3C60003C045 /* Frameworks */, - 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, - 3399D490228B24CF009A79C7 /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - 33CC11202044C79F0003C045 /* PBXTargetDependency */, - ); - name = Runner; - packageProductDependencies = ( - 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, - ); - productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* flutter_inappwebview_example.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 33CC10E52044A3C60003C045 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 33CC10EC2044A3C60003C045 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.Sandbox = { - enabled = 1; - }; - }; - }; - 33CC111A2044C6BA0003C045 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 33CC10E42044A3C60003C045; - packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, - ); - productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 33CC10EC2044A3C60003C045 /* Runner */, - 33CC111A2044C6BA0003C045 /* Flutter Assemble */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 33CC10EB2044A3C60003C045 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 2233BC408EAD04A8B5721F92 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 3399D490228B24CF009A79C7 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; - }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, - ); - outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 33CC10E92044A3C60003C045 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; - targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 33CC10F52044A3C60003C045 /* Base */, - ); - name = MainMenu.xib; - path = Runner; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 338D0CE9231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Profile; - }; - 338D0CEA231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Profile; - }; - 338D0CEB231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Profile; - }; - 33CC10F92044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 33CC10FA2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Release; - }; - 33CC10FC2044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 33CC10FD2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 33CC111C2044C6BA0003C045 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 33CC111D2044C6BA0003C045 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10F92044A3C60003C045 /* Debug */, - 33CC10FA2044A3C60003C045 /* Release */, - 338D0CE9231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10FC2044A3C60003C045 /* Debug */, - 33CC10FD2044A3C60003C045 /* Release */, - 338D0CEA231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC111C2044C6BA0003C045 /* Debug */, - 33CC111D2044C6BA0003C045 /* Release */, - 338D0CEB231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { - isa = XCLocalSwiftPackageReference; - relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; - }; -/* End XCLocalSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { - isa = XCSwiftPackageProductDependency; - productName = FlutterGeneratedPluginSwiftPackage; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 33CC10E52044A3C60003C045 /* Project object */; -} diff --git a/flutter_inappwebview/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_inappwebview/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/flutter_inappwebview/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/flutter_inappwebview/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/flutter_inappwebview/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index eb9351a474..0000000000 --- a/flutter_inappwebview/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,14 +0,0 @@ -{ - "pins" : [ - { - "identity" : "swift-collections", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-collections.git", - "state" : { - "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", - "version" : "1.3.0" - } - } - ], - "version" : 2 -} diff --git a/flutter_inappwebview/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/flutter_inappwebview/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index be8b1c9f96..0000000000 --- a/flutter_inappwebview/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_inappwebview/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/flutter_inappwebview/example/macos/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14c7..0000000000 --- a/flutter_inappwebview/example/macos/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/flutter_inappwebview/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_inappwebview/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/flutter_inappwebview/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/flutter_inappwebview/example/macos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved b/flutter_inappwebview/example/macos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index eb9351a474..0000000000 --- a/flutter_inappwebview/example/macos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,14 +0,0 @@ -{ - "pins" : [ - { - "identity" : "swift-collections", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-collections.git", - "state" : { - "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", - "version" : "1.3.0" - } - } - ], - "version" : 2 -} diff --git a/flutter_inappwebview/example/macos/Runner/AppDelegate.swift b/flutter_inappwebview/example/macos/Runner/AppDelegate.swift deleted file mode 100644 index b3c1761412..0000000000 --- a/flutter_inappwebview/example/macos/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Cocoa -import FlutterMacOS - -@main -class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } - - override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { - return true - } -} diff --git a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index a2ec33f19f..0000000000 --- a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" - }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png deleted file mode 100644 index 82b6f9d9a3..0000000000 Binary files a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png and /dev/null differ diff --git a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png deleted file mode 100644 index 13b35eba55..0000000000 Binary files a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png and /dev/null differ diff --git a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png deleted file mode 100644 index 0a3f5fa40f..0000000000 Binary files a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png and /dev/null differ diff --git a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png deleted file mode 100644 index bdb57226d5..0000000000 Binary files a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png and /dev/null differ diff --git a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png deleted file mode 100644 index f083318e09..0000000000 Binary files a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png and /dev/null differ diff --git a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png deleted file mode 100644 index 326c0e72c9..0000000000 Binary files a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png and /dev/null differ diff --git a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png deleted file mode 100644 index 2f1632cfdd..0000000000 Binary files a/flutter_inappwebview/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png and /dev/null differ diff --git a/flutter_inappwebview/example/macos/Runner/Base.lproj/MainMenu.xib b/flutter_inappwebview/example/macos/Runner/Base.lproj/MainMenu.xib deleted file mode 100644 index 80e867a4e0..0000000000 --- a/flutter_inappwebview/example/macos/Runner/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,343 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_inappwebview/example/macos/Runner/Configs/AppInfo.xcconfig b/flutter_inappwebview/example/macos/Runner/Configs/AppInfo.xcconfig deleted file mode 100644 index 2165dd02f5..0000000000 --- a/flutter_inappwebview/example/macos/Runner/Configs/AppInfo.xcconfig +++ /dev/null @@ -1,14 +0,0 @@ -// Application-level settings for the Runner target. -// -// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the -// future. If not, the values below would default to using the project name when this becomes a -// 'flutter create' template. - -// The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = flutter_inappwebview_example - -// The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterInappwebviewExample - -// The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2022 com.pichillilorenzo. All rights reserved. diff --git a/flutter_inappwebview/example/macos/Runner/Configs/Debug.xcconfig b/flutter_inappwebview/example/macos/Runner/Configs/Debug.xcconfig deleted file mode 100644 index 36b0fd9464..0000000000 --- a/flutter_inappwebview/example/macos/Runner/Configs/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Debug.xcconfig" -#include "Warnings.xcconfig" diff --git a/flutter_inappwebview/example/macos/Runner/Configs/Release.xcconfig b/flutter_inappwebview/example/macos/Runner/Configs/Release.xcconfig deleted file mode 100644 index dff4f49561..0000000000 --- a/flutter_inappwebview/example/macos/Runner/Configs/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Release.xcconfig" -#include "Warnings.xcconfig" diff --git a/flutter_inappwebview/example/macos/Runner/Configs/Warnings.xcconfig b/flutter_inappwebview/example/macos/Runner/Configs/Warnings.xcconfig deleted file mode 100644 index 42bcbf4780..0000000000 --- a/flutter_inappwebview/example/macos/Runner/Configs/Warnings.xcconfig +++ /dev/null @@ -1,13 +0,0 @@ -WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings -GCC_WARN_UNDECLARED_SELECTOR = YES -CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES -CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES -CLANG_WARN_PRAGMA_PACK = YES -CLANG_WARN_STRICT_PROTOTYPES = YES -CLANG_WARN_COMMA = YES -GCC_WARN_STRICT_SELECTOR_MATCH = YES -CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES -GCC_WARN_SHADOW = YES -CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/flutter_inappwebview/example/macos/Runner/DebugProfile.entitlements b/flutter_inappwebview/example/macos/Runner/DebugProfile.entitlements deleted file mode 100644 index 9f2a6f0439..0000000000 --- a/flutter_inappwebview/example/macos/Runner/DebugProfile.entitlements +++ /dev/null @@ -1,22 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.device.audio-input - - com.apple.security.device.camera - - com.apple.security.files.user-selected.read-write - - com.apple.security.network.client - - com.apple.security.network.server - - com.apple.security.print - - - diff --git a/flutter_inappwebview/example/macos/Runner/Info.plist b/flutter_inappwebview/example/macos/Runner/Info.plist deleted file mode 100644 index 15f20bedca..0000000000 --- a/flutter_inappwebview/example/macos/Runner/Info.plist +++ /dev/null @@ -1,55 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - NSAppTransportSecurity - - NSAllowsLocalNetworking - - NSAllowsArbitraryLoadsInWebContent - - NSAllowsArbitraryLoads - - - NSMicrophoneUsageDescription - InAppWebView requires access to mic. - NSLocationWhenInUseUsageDescription - Need location - NSLocationAlwaysUsageDescription - Need location - NSLocationAlwaysAndWhenInUseUsageDescription - Need location - NSLocalNetworkUsageDescription - Allow Flutter tools on your computer to connect and debug your application. - NSDocumentsFolderUsageDescription - InAppWebView requires access to documents folder - NSCameraUsageDescription - InAppWebView requires access to cam. - - diff --git a/flutter_inappwebview/example/macos/Runner/MainFlutterWindow.swift b/flutter_inappwebview/example/macos/Runner/MainFlutterWindow.swift deleted file mode 100644 index 2722837ec9..0000000000 --- a/flutter_inappwebview/example/macos/Runner/MainFlutterWindow.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Cocoa -import FlutterMacOS - -class MainFlutterWindow: NSWindow { - override func awakeFromNib() { - let flutterViewController = FlutterViewController.init() - let windowFrame = self.frame - self.contentViewController = flutterViewController - self.setFrame(windowFrame, display: true) - - RegisterGeneratedPlugins(registry: flutterViewController) - - super.awakeFromNib() - } -} diff --git a/flutter_inappwebview/example/macos/Runner/Release.entitlements b/flutter_inappwebview/example/macos/Runner/Release.entitlements deleted file mode 100644 index 40c55dbcdb..0000000000 --- a/flutter_inappwebview/example/macos/Runner/Release.entitlements +++ /dev/null @@ -1,20 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.device.audio-input - - com.apple.security.device.camera - - com.apple.security.files.user-selected.read-write - - com.apple.security.network.client - - com.apple.security.network.server - - com.apple.security.print - - - diff --git a/flutter_inappwebview/example/macos/RunnerTests/RunnerTests.swift b/flutter_inappwebview/example/macos/RunnerTests/RunnerTests.swift deleted file mode 100644 index 61f3bd1fc5..0000000000 --- a/flutter_inappwebview/example/macos/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Cocoa -import FlutterMacOS -import XCTest - -class RunnerTests: XCTestCase { - - func testExample() { - // If you add code to the Runner application, consider adding tests here. - // See https://developer.apple.com/documentation/xctest for more information about using XCTest. - } - -} diff --git a/flutter_inappwebview/example/pubspec.yaml b/flutter_inappwebview/example/pubspec.yaml deleted file mode 100755 index 5a4470665b..0000000000 --- a/flutter_inappwebview/example/pubspec.yaml +++ /dev/null @@ -1,121 +0,0 @@ -name: flutter_inappwebview_example -description: Demonstrates how to use the flutter_inappwebview plugin. - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# Read more about versioning at semver.org. -version: 1.0.0+1 - -publish_to: none - -environment: - sdk: ^3.8.0 - flutter: ">=3.32.0" - -dependencies: - flutter: - sdk: flutter - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.8 - flutter_downloader: ^1.12.0 - path_provider: ^2.1.5 - permission_handler: ^12.0.1 - url_launcher: ^6.3.2 - pointer_interceptor: ^0.10.1+2 - shared_preferences: ^2.5.4 - provider: ^6.1.5 - intl: ^0.18.1 - file_picker: ^10.3.8 - # mime: ^1.0.4 - # connectivity: ^0.4.5+6 - flutter_inappwebview: - path: ../ - -dependency_overrides: - flutter_inappwebview_platform_interface: - path: ../../flutter_inappwebview_platform_interface - flutter_inappwebview_android: - path: ../../flutter_inappwebview_android - flutter_inappwebview_ios: - path: ../../flutter_inappwebview_ios - flutter_inappwebview_macos: - path: ../../flutter_inappwebview_macos - flutter_inappwebview_web: - path: ../../flutter_inappwebview_web - flutter_inappwebview_windows: - path: ../../flutter_inappwebview_windows - flutter_inappwebview_linux: - path: ../../flutter_inappwebview_linux - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_driver: - sdk: flutter - integration_test: - sdk: flutter - # integration_test: ^1.0.2+1 -# integration_test: -# git: -# url: https://github.com/flutter/plugins.git -# path: packages/integration_test - flutter_lints: ^4.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://www.dartlang.org/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - assets: - - assets/ - - assets/js/ - - assets/css/ - - assets/images/ - - assets/website/ - - test_assets/ - - test_assets/js/ - - test_assets/css/ - - test_assets/images/ - - test_assets/website/ - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.io/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.io/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.io/custom-fonts/#from-packages diff --git a/flutter_inappwebview/example/test/flutter_test_config.dart b/flutter_inappwebview/example/test/flutter_test_config.dart deleted file mode 100644 index 529de2e113..0000000000 --- a/flutter_inappwebview/example/test/flutter_test_config.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'dart:async'; - -import 'package:flutter_test/flutter_test.dart'; - -import 'test_helpers/mock_inappwebview_platform.dart'; - -Future testExecutable(FutureOr Function() testMain) async { - TestWidgetsFlutterBinding.ensureInitialized(); - MockInAppWebViewPlatform.initialize(); - await testMain(); -} diff --git a/flutter_inappwebview/example/test/models/event_log_entry_test.dart b/flutter_inappwebview/example/test/models/event_log_entry_test.dart deleted file mode 100644 index 158e2d7c8f..0000000000 --- a/flutter_inappwebview/example/test/models/event_log_entry_test.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/models/event_log_entry.dart'; - -void main() { - group('EventLogEntry', () { - test('fromMap should deserialize JSON correctly', () { - final now = DateTime.now(); - final map = { - 'timestamp': now.millisecondsSinceEpoch, - 'eventType': 'navigation', - 'message': 'Page loaded', - 'data': {'url': 'https://example.com'}, - }; - - final entry = EventLogEntry.fromMap(map); - - expect( - entry.timestamp.millisecondsSinceEpoch, - now.millisecondsSinceEpoch, - ); - expect(entry.eventType, EventType.navigation); - expect(entry.message, 'Page loaded'); - expect(entry.data, {'url': 'https://example.com'}); - }); - - test('toMap should serialize to JSON correctly', () { - final now = DateTime.now(); - final entry = EventLogEntry( - timestamp: now, - eventType: EventType.javascript, - message: 'Script executed', - data: {'result': 'success'}, - ); - - final map = entry.toMap(); - - expect(map['timestamp'], now.millisecondsSinceEpoch); - expect(map['eventType'], 'javascript'); - expect(map['message'], 'Script executed'); - expect(map['data'], {'result': 'success'}); - }); - - test('all EventType values should be serializable', () { - final now = DateTime.now(); - - for (final eventType in EventType.values) { - final entry = EventLogEntry( - timestamp: now, - eventType: eventType, - message: 'Test', - ); - - final map = entry.toMap(); - final deserialized = EventLogEntry.fromMap(map); - - expect(deserialized.eventType, eventType); - } - }); - - test('null data should be handled correctly', () { - final now = DateTime.now(); - final entry = EventLogEntry( - timestamp: now, - eventType: EventType.error, - message: 'Error occurred', - ); - - final map = entry.toMap(); - - expect(map['data'], null); - expect(entry.data, null); - }); - - test('filtering by event type should work correctly', () { - final entries = [ - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Nav 1', - ), - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.javascript, - message: 'JS 1', - ), - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Nav 2', - ), - ]; - - final navigationEntries = - entries.where((e) => e.eventType == EventType.navigation).toList(); - - expect(navigationEntries.length, 2); - expect(navigationEntries[0].message, 'Nav 1'); - expect(navigationEntries[1].message, 'Nav 2'); - }); - }); -} diff --git a/flutter_inappwebview/example/test/models/network_request_test.dart b/flutter_inappwebview/example/test/models/network_request_test.dart deleted file mode 100644 index 680176cfe5..0000000000 --- a/flutter_inappwebview/example/test/models/network_request_test.dart +++ /dev/null @@ -1,139 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/models/network_request.dart'; - -void main() { - group('NetworkRequest', () { - test('creates instance with required fields', () { - final request = NetworkRequest( - id: '1', - method: 'GET', - url: 'https://example.com', - timestamp: DateTime(2025, 1, 1), - ); - - expect(request.id, '1'); - expect(request.method, 'GET'); - expect(request.url, 'https://example.com'); - expect(request.timestamp, DateTime(2025, 1, 1)); - expect(request.headers, isNull); - expect(request.body, isNull); - expect(request.response, isNull); - expect(request.statusCode, isNull); - expect(request.duration, isNull); - }); - - test('creates instance with all fields', () { - final request = NetworkRequest( - id: '2', - method: 'POST', - url: 'https://example.com/api', - timestamp: DateTime(2025, 1, 1), - headers: {'Content-Type': 'application/json'}, - body: '{"test": true}', - response: '{"success": true}', - statusCode: 200, - duration: Duration(milliseconds: 150), - ); - - expect(request.id, '2'); - expect(request.method, 'POST'); - expect(request.url, 'https://example.com/api'); - expect(request.headers?['Content-Type'], 'application/json'); - expect(request.body, '{"test": true}'); - expect(request.response, '{"success": true}'); - expect(request.statusCode, 200); - expect(request.duration, Duration(milliseconds: 150)); - }); - - test('copyWith creates new instance with updated fields', () { - final original = NetworkRequest( - id: '3', - method: 'GET', - url: 'https://example.com', - timestamp: DateTime(2025, 1, 1), - ); - - final updated = original.copyWith( - statusCode: 200, - response: '{"data": []}', - duration: Duration(milliseconds: 200), - ); - - expect(updated.id, original.id); - expect(updated.method, original.method); - expect(updated.url, original.url); - expect(updated.timestamp, original.timestamp); - expect(updated.statusCode, 200); - expect(updated.response, '{"data": []}'); - expect(updated.duration, Duration(milliseconds: 200)); - }); - - test('toMap serializes correctly', () { - final request = NetworkRequest( - id: '4', - method: 'GET', - url: 'https://example.com', - timestamp: DateTime(2025, 1, 1), - headers: {'Accept': 'application/json'}, - statusCode: 200, - duration: Duration(milliseconds: 100), - ); - - final map = request.toMap(); - - expect(map['id'], '4'); - expect(map['method'], 'GET'); - expect(map['url'], 'https://example.com'); - expect(map['timestamp'], DateTime(2025, 1, 1).millisecondsSinceEpoch); - expect(map['headers'], {'Accept': 'application/json'}); - expect(map['statusCode'], 200); - expect(map['duration'], 100); - }); - - test('fromMap deserializes correctly', () { - final map = { - 'id': '5', - 'method': 'POST', - 'url': 'https://example.com/api', - 'timestamp': DateTime(2025, 1, 1).millisecondsSinceEpoch, - 'headers': {'Content-Type': 'application/json'}, - 'body': '{"test": true}', - 'response': '{"success": true}', - 'statusCode': 201, - 'duration': 250, - }; - - final request = NetworkRequest.fromMap(map); - - expect(request.id, '5'); - expect(request.method, 'POST'); - expect(request.url, 'https://example.com/api'); - expect(request.timestamp, DateTime(2025, 1, 1)); - expect(request.headers?['Content-Type'], 'application/json'); - expect(request.body, '{"test": true}'); - expect(request.response, '{"success": true}'); - expect(request.statusCode, 201); - expect(request.duration, Duration(milliseconds: 250)); - }); - - test('fromMap handles missing optional fields', () { - final map = { - 'id': '6', - 'method': 'GET', - 'url': 'https://example.com', - 'timestamp': DateTime(2025, 1, 1).millisecondsSinceEpoch, - }; - - final request = NetworkRequest.fromMap(map); - - expect(request.id, '6'); - expect(request.method, 'GET'); - expect(request.url, 'https://example.com'); - expect(request.headers, isNull); - expect(request.body, isNull); - expect(request.response, isNull); - expect(request.statusCode, isNull); - expect(request.duration, isNull); - }); - }); -} diff --git a/flutter_inappwebview/example/test/models/performance_metric_test.dart b/flutter_inappwebview/example/test/models/performance_metric_test.dart deleted file mode 100644 index 7d5e0da8ed..0000000000 --- a/flutter_inappwebview/example/test/models/performance_metric_test.dart +++ /dev/null @@ -1,74 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/models/performance_metric.dart'; - -void main() { - group('PerformanceMetric', () { - test('fromMap should deserialize JSON correctly', () { - final now = DateTime.now(); - final map = { - 'methodName': 'loadUrl', - 'duration': 250, - 'timestamp': now.millisecondsSinceEpoch, - 'metadata': {'url': 'https://example.com'}, - }; - - final metric = PerformanceMetric.fromMap(map); - - expect(metric.methodName, 'loadUrl'); - expect(metric.duration, const Duration(milliseconds: 250)); - expect( - metric.timestamp.millisecondsSinceEpoch, - now.millisecondsSinceEpoch, - ); - expect(metric.metadata, {'url': 'https://example.com'}); - }); - - test('toMap should serialize to JSON correctly', () { - final now = DateTime.now(); - final metric = PerformanceMetric( - methodName: 'evaluateJavascript', - duration: const Duration(milliseconds: 50), - timestamp: now, - metadata: {'script': 'console.log("test")'}, - ); - - final map = metric.toMap(); - - expect(map['methodName'], 'evaluateJavascript'); - expect(map['duration'], 50); - expect(map['timestamp'], now.millisecondsSinceEpoch); - expect(map['metadata'], {'script': 'console.log("test")'}); - }); - - test('null metadata should be handled correctly', () { - final now = DateTime.now(); - final metric = PerformanceMetric( - methodName: 'reload', - duration: const Duration(milliseconds: 100), - timestamp: now, - ); - - final map = metric.toMap(); - - expect(map['metadata'], null); - expect(metric.metadata, null); - }); - - test('timestamp handling should preserve milliseconds', () { - final originalTimestamp = DateTime.parse('2026-01-17 10:30:45.123'); - final metric = PerformanceMetric( - methodName: 'test', - duration: const Duration(milliseconds: 10), - timestamp: originalTimestamp, - ); - - final map = metric.toMap(); - final deserializedMetric = PerformanceMetric.fromMap(map); - - expect( - deserializedMetric.timestamp.millisecondsSinceEpoch, - originalTimestamp.millisecondsSinceEpoch, - ); - }); - }); -} diff --git a/flutter_inappwebview/example/test/models/test_case_test.dart b/flutter_inappwebview/example/test/models/test_case_test.dart deleted file mode 100644 index 5f6829fcbc..0000000000 --- a/flutter_inappwebview/example/test/models/test_case_test.dart +++ /dev/null @@ -1,112 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/models/test_case.dart'; -import 'package:flutter_inappwebview_example/utils/constants.dart'; - -void main() { - group('TestCase', () { - test('fromMap should deserialize JSON correctly', () { - final map = { - 'id': 'test_1', - 'title': 'Test Title', - 'description': 'Test Description', - 'supportedPlatforms': ['android', 'ios'], - 'category': 'navigation', - 'complexity': 'quick', - }; - - final testCase = TestCase.fromMap(map); - - expect(testCase.id, 'test_1'); - expect(testCase.title, 'Test Title'); - expect(testCase.description, 'Test Description'); - expect(testCase.supportedPlatforms, ['android', 'ios']); - expect(testCase.category, TestCategory.navigation); - expect(testCase.complexity, TestComplexity.quick); - }); - - test('toMap should serialize to JSON correctly', () { - final testCase = TestCase( - id: 'test_2', - title: 'Test Title 2', - description: 'Test Description 2', - supportedPlatforms: ['web', 'windows'], - category: TestCategory.javascript, - complexity: TestComplexity.medium, - execute: () async { - return null; - }, - ); - - final map = testCase.toMap(); - - expect(map['id'], 'test_2'); - expect(map['title'], 'Test Title 2'); - expect(map['description'], 'Test Description 2'); - expect(map['supportedPlatforms'], ['web', 'windows']); - expect(map['category'], 'javascript'); - expect(map['complexity'], 'medium'); - }); - - test('isSupportedOnPlatform should check platform support correctly', () { - final testCase = TestCase( - id: 'test_3', - title: 'Test', - description: 'Test', - supportedPlatforms: ['android', 'ios', 'macos'], - category: TestCategory.content, - complexity: TestComplexity.quick, - execute: () async { - return null; - }, - ); - - expect(testCase.isSupportedOnPlatform('android'), true); - expect(testCase.isSupportedOnPlatform('ios'), true); - expect(testCase.isSupportedOnPlatform('macos'), true); - expect(testCase.isSupportedOnPlatform('web'), false); - expect(testCase.isSupportedOnPlatform('windows'), false); - expect(testCase.isSupportedOnPlatform('linux'), false); - }); - - test('equality should work correctly', () { - final testCase1 = TestCase( - id: 'test_1', - title: 'Test', - description: 'Test', - supportedPlatforms: ['android'], - category: TestCategory.navigation, - complexity: TestComplexity.quick, - execute: () async { - return null; - }, - ); - - final testCase2 = TestCase( - id: 'test_1', - title: 'Test', - description: 'Test', - supportedPlatforms: ['android'], - category: TestCategory.navigation, - complexity: TestComplexity.quick, - execute: () async { - return null; - }, - ); - - final testCase3 = TestCase( - id: 'test_2', - title: 'Test', - description: 'Test', - supportedPlatforms: ['android'], - category: TestCategory.navigation, - complexity: TestComplexity.quick, - execute: () async { - return null; - }, - ); - - expect(testCase1, testCase2); - expect(testCase1, isNot(testCase3)); - }); - }); -} diff --git a/flutter_inappwebview/example/test/models/test_configuration_test.dart b/flutter_inappwebview/example/test/models/test_configuration_test.dart deleted file mode 100644 index 930a360621..0000000000 --- a/flutter_inappwebview/example/test/models/test_configuration_test.dart +++ /dev/null @@ -1,676 +0,0 @@ -import 'dart:convert'; -import 'dart:typed_data'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/models/test_configuration.dart'; -import 'package:flutter_inappwebview_example/utils/constants.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; - -void main() { - group('CustomTestStep', () { - test('creates step with required fields', () { - final step = CustomTestStep( - id: 'step_1', - name: 'Test Step', - description: 'A test step', - category: TestCategory.navigation, - action: CustomTestAction.loadUrl('https://example.com'), - ); - - expect(step.id, 'step_1'); - expect(step.name, 'Test Step'); - expect(step.description, 'A test step'); - expect(step.category, TestCategory.navigation); - expect(step.enabled, true); - expect(step.order, 0); - expect(step.expectedResultType, ExpectedResultType.any); - }); - - test('serializes to JSON', () { - final step = CustomTestStep( - id: 'step_1', - name: 'Test Step', - description: 'A test step', - category: TestCategory.navigation, - action: CustomTestAction.loadUrl('https://example.com'), - expectedResult: 'success', - expectedResultType: ExpectedResultType.contains, - enabled: true, - order: 1, - ); - - final json = step.toJson(); - expect(json['id'], 'step_1'); - expect(json['name'], 'Test Step'); - expect(json['description'], 'A test step'); - expect(json['category'], TestCategory.navigation.name); - expect(json['expectedResult'], 'success'); - expect(json['expectedResultType'], 'contains'); - expect(json['enabled'], true); - expect(json['order'], 1); - }); - - test('deserializes from JSON', () { - final json = { - 'id': 'step_1', - 'name': 'Test Step', - 'description': 'A test step', - 'category': TestCategory.navigation.name, - 'action': {'type': 'loadUrl', 'url': 'https://example.com'}, - 'parameters': {}, - 'expectedResult': 'success', - 'expectedResultType': 'contains', - 'enabled': true, - 'order': 1, - }; - - final step = CustomTestStep.fromJson(json); - expect(step.id, 'step_1'); - expect(step.name, 'Test Step'); - expect(step.description, 'A test step'); - expect(step.category, TestCategory.navigation); - expect(step.expectedResult, 'success'); - expect(step.expectedResultType, ExpectedResultType.contains); - expect(step.enabled, true); - expect(step.order, 1); - }); - - test('copyWith creates modified copy', () { - final original = CustomTestStep( - id: 'step_1', - name: 'Original', - description: 'Original description', - category: TestCategory.navigation, - action: CustomTestAction.loadUrl('https://example.com'), - ); - - final modified = original.copyWith(name: 'Modified', enabled: false); - - expect(modified.id, 'step_1'); - expect(modified.name, 'Modified'); - expect(modified.description, 'Original description'); - expect(modified.enabled, false); - }); - }); - - group('CustomTestStep validation', () { - test('validates exact match', () { - final step = CustomTestStep( - id: 'step_1', - name: 'Test', - description: '', - category: TestCategory.navigation, - action: CustomTestAction.evaluateJs(''), - expectedResult: 'hello', - expectedResultType: ExpectedResultType.exact, - ); - - expect(step.validateResult('hello'), true); - expect(step.validateResult('Hello'), false); - expect(step.validateResult('hello world'), false); - }); - - test('validates contains match', () { - final step = CustomTestStep( - id: 'step_1', - name: 'Test', - description: '', - category: TestCategory.navigation, - action: CustomTestAction.evaluateJs(''), - expectedResult: 'world', - expectedResultType: ExpectedResultType.contains, - ); - - expect(step.validateResult('hello world'), true); - expect(step.validateResult('Hello World'), false); - expect(step.validateResult('hello'), false); - }); - - test('validates containsIgnoreCase match', () { - final step = CustomTestStep( - id: 'step_1', - name: 'Test', - description: '', - category: TestCategory.navigation, - action: CustomTestAction.evaluateJs(''), - expectedResult: 'world', - expectedResultType: ExpectedResultType.containsIgnoreCase, - ); - - expect(step.validateResult('hello world'), true); - expect(step.validateResult('Hello World'), true); - expect(step.validateResult('HELLO WORLD'), true); - }); - - test('validates regex match', () { - final step = CustomTestStep( - id: 'step_1', - name: 'Test', - description: '', - category: TestCategory.navigation, - action: CustomTestAction.evaluateJs(''), - expectedResult: r'^\d{3}-\d{4}$', - expectedResultType: ExpectedResultType.regex, - ); - - expect(step.validateResult('123-4567'), true); - expect(step.validateResult('12-34567'), false); - expect(step.validateResult('abc-defg'), false); - }); - - test('validates notNull', () { - final step = CustomTestStep( - id: 'step_1', - name: 'Test', - description: '', - category: TestCategory.navigation, - action: CustomTestAction.evaluateJs(''), - expectedResultType: ExpectedResultType.notNull, - ); - - expect(step.validateResult('value'), true); - expect(step.validateResult(123), true); - expect(step.validateResult(null), false); - }); - - test('validates isNull', () { - final step = CustomTestStep( - id: 'step_1', - name: 'Test', - description: '', - category: TestCategory.navigation, - action: CustomTestAction.evaluateJs(''), - expectedResultType: ExpectedResultType.isNull, - ); - - expect(step.validateResult(null), true); - expect(step.validateResult('value'), false); - }); - - test('validates truthy', () { - final step = CustomTestStep( - id: 'step_1', - name: 'Test', - description: '', - category: TestCategory.navigation, - action: CustomTestAction.evaluateJs(''), - expectedResultType: ExpectedResultType.truthy, - ); - - expect(step.validateResult(true), true); - expect(step.validateResult('non-empty'), true); - expect(step.validateResult(1), true); - expect(step.validateResult([1, 2, 3]), true); - expect(step.validateResult({'key': 'value'}), true); - expect(step.validateResult(false), false); - expect(step.validateResult(''), false); - expect(step.validateResult(0), false); - expect(step.validateResult([]), false); - expect(step.validateResult(null), false); - }); - - test('validates falsy', () { - final step = CustomTestStep( - id: 'step_1', - name: 'Test', - description: '', - category: TestCategory.navigation, - action: CustomTestAction.evaluateJs(''), - expectedResultType: ExpectedResultType.falsy, - ); - - expect(step.validateResult(false), true); - expect(step.validateResult(''), true); - expect(step.validateResult(0), true); - expect(step.validateResult([]), true); - expect(step.validateResult(null), true); - expect(step.validateResult(true), false); - expect(step.validateResult('value'), false); - }); - - test('validates typeIs', () { - final step = CustomTestStep( - id: 'step_1', - name: 'Test', - description: '', - category: TestCategory.navigation, - action: CustomTestAction.evaluateJs(''), - expectedResult: 'String', - expectedResultType: ExpectedResultType.typeIs, - ); - - expect(step.validateResult('hello'), true); - expect(step.validateResult(123), false); - }); - - test('validates lengthEquals', () { - final step = CustomTestStep( - id: 'step_1', - name: 'Test', - description: '', - category: TestCategory.navigation, - action: CustomTestAction.evaluateJs(''), - expectedResult: '3', - expectedResultType: ExpectedResultType.lengthEquals, - ); - - expect(step.validateResult([1, 2, 3]), true); - expect(step.validateResult('abc'), true); - expect(step.validateResult({'a': 1, 'b': 2, 'c': 3}), true); - expect(step.validateResult([1, 2]), false); - }); - - test('validates greaterThan', () { - final step = CustomTestStep( - id: 'step_1', - name: 'Test', - description: '', - category: TestCategory.navigation, - action: CustomTestAction.evaluateJs(''), - expectedResult: '10', - expectedResultType: ExpectedResultType.greaterThan, - ); - - expect(step.validateResult(15), true); - expect(step.validateResult(10), false); - expect(step.validateResult(5), false); - }); - - test('validates lessThan', () { - final step = CustomTestStep( - id: 'step_1', - name: 'Test', - description: '', - category: TestCategory.navigation, - action: CustomTestAction.evaluateJs(''), - expectedResult: '10', - expectedResultType: ExpectedResultType.lessThan, - ); - - expect(step.validateResult(5), true); - expect(step.validateResult(10), false); - expect(step.validateResult(15), false); - }); - }); - - group('CustomTestAction', () { - test('creates loadUrl action', () { - final action = CustomTestAction.loadUrl('https://example.com'); - expect(action.type, CustomTestActionType.loadUrl); - expect(action.url, 'https://example.com'); - }); - - test('creates evaluateJs action', () { - final action = CustomTestAction.evaluateJs('return 1 + 1'); - expect(action.type, CustomTestActionType.evaluateJavascript); - expect(action.script, 'return 1 + 1'); - }); - - test('creates delay action', () { - final action = CustomTestAction.delay(1000); - expect(action.type, CustomTestActionType.delay); - expect(action.delayMs, 1000); - }); - - test('creates controllerMethod action', () { - final action = CustomTestAction.controllerMethod( - 'loadUrl', - parameters: {'url': 'https://example.com'}, - ); - expect(action.type, CustomTestActionType.controllerMethod); - expect(action.methodId, 'loadUrl'); - expect(action.methodParameters, {'url': 'https://example.com'}); - }); - - test('serializes to JSON', () { - final action = CustomTestAction.controllerMethod( - 'loadUrl', - parameters: { - 'url': 'https://example.com', - 'headers': {'Accept': 'text/html'}, - }, - ); - - final json = action.toJson(); - expect(json['type'], 'controllerMethod'); - expect(json['methodId'], 'loadUrl'); - expect(json['methodParameters']['url'], 'https://example.com'); - }); - - test('deserializes from JSON', () { - final json = { - 'type': 'controllerMethod', - 'methodId': 'loadUrl', - 'methodParameters': {'url': 'https://example.com'}, - }; - - final action = CustomTestAction.fromJson(json); - expect(action.type, CustomTestActionType.controllerMethod); - expect(action.methodId, 'loadUrl'); - expect(action.methodParameters?['url'], 'https://example.com'); - }); - - test('sanitizes ParameterValueHint values', () { - final action = CustomTestAction.controllerMethod( - 'loadUrl', - parameters: { - 'url': 'https://example.com', - 'body': const ParameterValueHint( - null, - ParameterValueType.bytes, - ), - }, - ); - - final json = action.toJson(); - // ParameterValueHint with null value should become null - expect(json['methodParameters']['body'], null); - }); - - test('sanitizes Uint8List values to base64', () { - final bytes = Uint8List.fromList([1, 2, 3, 4, 5]); - final action = CustomTestAction.controllerMethod( - 'postUrl', - parameters: {'url': 'https://example.com', 'postData': bytes}, - ); - - final json = action.toJson(); - expect(json['methodParameters']['postData']['_type'], 'bytes'); - expect( - json['methodParameters']['postData']['value'], - base64.encode(bytes), - ); - }); - - test('deserializes base64 bytes', () { - final originalBytes = Uint8List.fromList([1, 2, 3, 4, 5]); - final json = { - 'type': 'controllerMethod', - 'methodId': 'postUrl', - 'methodParameters': { - 'url': 'https://example.com', - 'postData': {'_type': 'bytes', 'value': base64.encode(originalBytes)}, - }, - }; - - final action = CustomTestAction.fromJson(json); - final postData = action.methodParameters?['postData']; - expect(postData, isA()); - expect(postData, equals(originalBytes)); - }); - - test('handles nested maps and lists in parameters', () { - final action = CustomTestAction.controllerMethod( - 'loadUrl', - parameters: { - 'url': 'https://example.com', - 'headers': { - 'Accept': 'text/html', - 'Custom': ['value1', 'value2'], - }, - 'options': { - 'nested': {'deep': true}, - }, - }, - ); - - final json = action.toJson(); - final deserialized = CustomTestAction.fromJson(json); - - expect(deserialized.methodParameters?['headers']['Accept'], 'text/html'); - expect( - deserialized.methodParameters?['headers']['Custom'], - equals(['value1', 'value2']), - ); - expect(deserialized.methodParameters?['options']['nested']['deep'], true); - }); - }); - - group('TestConfiguration', () { - test('creates empty configuration', () { - final config = TestConfiguration.empty(name: 'My Config'); - expect(config.name, 'My Config'); - expect(config.customSteps, isEmpty); - expect(config.webViewType, TestWebViewType.inAppWebView); - }); - - test('creates default configuration', () { - final config = TestConfiguration.defaultConfig(); - expect(config.name, 'Default Test Configuration'); - expect(config.customSteps, isNotEmpty); - }); - - test('serializes to JSON', () { - final config = TestConfiguration( - id: 'config_1', - name: 'Test Config', - description: 'A test configuration', - createdAt: DateTime(2024, 1, 1), - modifiedAt: DateTime(2024, 1, 2), - customSteps: [ - CustomTestStep( - id: 'step_1', - name: 'Step 1', - description: 'First step', - category: TestCategory.navigation, - action: CustomTestAction.loadUrl('https://example.com'), - ), - ], - webViewType: TestWebViewType.headless, - initialUrl: 'https://start.com', - ); - - final json = config.toJson(); - expect(json['id'], 'config_1'); - expect(json['name'], 'Test Config'); - expect(json['description'], 'A test configuration'); - expect(json['customSteps'], hasLength(1)); - expect(json['webViewType'], 'headless'); - expect(json['initialUrl'], 'https://start.com'); - }); - - test('deserializes from JSON', () { - final json = { - 'id': 'config_1', - 'name': 'Test Config', - 'description': 'A test configuration', - 'createdAt': '2024-01-01T00:00:00.000', - 'modifiedAt': '2024-01-02T00:00:00.000', - 'customSteps': [ - { - 'id': 'step_1', - 'name': 'Step 1', - 'description': 'First step', - 'category': TestCategory.navigation.name, - 'action': {'type': 'loadUrl', 'url': 'https://example.com'}, - 'parameters': {}, - 'expectedResultType': 'any', - 'enabled': true, - 'order': 0, - }, - ], - 'testOrdering': {}, - 'enabledBuiltInTests': [], - 'metadata': {}, - 'webViewType': 'headless', - 'initialUrl': 'https://start.com', - }; - - final config = TestConfiguration.fromJson(json); - expect(config.id, 'config_1'); - expect(config.name, 'Test Config'); - expect(config.customSteps, hasLength(1)); - expect(config.webViewType, TestWebViewType.headless); - expect(config.initialUrl, 'https://start.com'); - }); - - test('roundtrip JSON serialization', () { - final original = TestConfiguration( - id: 'config_1', - name: 'Test Config', - description: 'A test configuration', - createdAt: DateTime(2024, 1, 1), - modifiedAt: DateTime(2024, 1, 2), - customSteps: [ - CustomTestStep( - id: 'step_1', - name: 'Load URL', - description: 'Load a URL', - category: TestCategory.navigation, - action: CustomTestAction.controllerMethod( - 'loadUrl', - parameters: { - 'url': 'https://example.com', - 'headers': {'Accept': 'text/html'}, - }, - ), - expectedResult: 'success', - expectedResultType: ExpectedResultType.contains, - ), - ], - webViewType: TestWebViewType.headless, - initialUrl: 'https://start.com', - ); - - final jsonString = original.toJsonString(); - final restored = TestConfiguration.fromJsonString(jsonString); - - expect(restored.id, original.id); - expect(restored.name, original.name); - expect(restored.description, original.description); - expect(restored.customSteps.length, original.customSteps.length); - expect(restored.customSteps[0].id, original.customSteps[0].id); - expect(restored.customSteps[0].name, original.customSteps[0].name); - expect(restored.webViewType, original.webViewType); - expect(restored.initialUrl, original.initialUrl); - }); - - test('copyWith creates modified copy', () { - final original = TestConfiguration.empty(name: 'Original'); - final modified = original.copyWith( - name: 'Modified', - webViewType: TestWebViewType.headless, - ); - - expect(modified.id, original.id); - expect(modified.name, 'Modified'); - expect(modified.webViewType, TestWebViewType.headless); - }); - }); - - group('TestConfiguration bytes serialization', () { - test('handles ParameterValueHint with Uint8List in roundtrip', () { - // Simulate the scenario that caused the bug: - // A config with ParameterValueHint should serialize properly - final config = TestConfiguration( - id: 'config_1', - name: 'Test Config', - createdAt: DateTime.now(), - modifiedAt: DateTime.now(), - customSteps: [ - CustomTestStep( - id: 'step_1', - name: 'Load URL with body', - description: 'Test', - category: TestCategory.navigation, - action: CustomTestAction.controllerMethod( - 'loadUrl', - parameters: { - 'url': 'https://example.com', - 'method': 'POST', - 'headers': {}, - // This was the problematic case - ParameterValueHint with null value - 'body': const ParameterValueHint( - null, - ParameterValueType.bytes, - ), - }, - ), - ), - ], - ); - - // Serialize and deserialize - final jsonString = config.toJsonString(); - final restored = TestConfiguration.fromJsonString(jsonString); - - // The body parameter should be null, not a string representation - final restoredBody = - restored.customSteps[0].action.methodParameters?['body']; - expect(restoredBody, isNull); - }); - - test('handles actual Uint8List data in roundtrip', () { - final testData = Uint8List.fromList([72, 101, 108, 108, 111]); // "Hello" - - final config = TestConfiguration( - id: 'config_1', - name: 'Test Config', - createdAt: DateTime.now(), - modifiedAt: DateTime.now(), - customSteps: [ - CustomTestStep( - id: 'step_1', - name: 'POST with data', - description: 'Test', - category: TestCategory.navigation, - action: CustomTestAction.controllerMethod( - 'postUrl', - parameters: { - 'url': 'https://httpbin.org/post', - 'postData': testData, - }, - ), - ), - ], - ); - - // Serialize and deserialize - final jsonString = config.toJsonString(); - final restored = TestConfiguration.fromJsonString(jsonString); - - // The postData should be restored as Uint8List - final restoredData = - restored.customSteps[0].action.methodParameters?['postData']; - expect(restoredData, isA()); - expect(restoredData, equals(testData)); - }); - - test('preserves non-bytes parameters correctly', () { - final config = TestConfiguration( - id: 'config_1', - name: 'Test Config', - createdAt: DateTime.now(), - modifiedAt: DateTime.now(), - customSteps: [ - CustomTestStep( - id: 'step_1', - name: 'Load URL', - description: 'Test', - category: TestCategory.navigation, - action: CustomTestAction.controllerMethod( - 'loadUrl', - parameters: { - 'url': 'https://example.com', - 'method': 'GET', - 'headers': {'Accept': 'application/json'}, - }, - ), - ), - ], - ); - - final jsonString = config.toJsonString(); - final restored = TestConfiguration.fromJsonString(jsonString); - - expect( - restored.customSteps[0].action.methodParameters?['url'], - 'https://example.com', - ); - expect(restored.customSteps[0].action.methodParameters?['method'], 'GET'); - expect( - restored.customSteps[0].action.methodParameters?['headers']['Accept'], - 'application/json', - ); - }); - }); -} diff --git a/flutter_inappwebview/example/test/models/test_result_test.dart b/flutter_inappwebview/example/test/models/test_result_test.dart deleted file mode 100644 index 3f767dc801..0000000000 --- a/flutter_inappwebview/example/test/models/test_result_test.dart +++ /dev/null @@ -1,75 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/models/test_result.dart'; - -void main() { - group('TestResult', () { - test('fromMap should deserialize JSON correctly', () { - final map = { - 'passed': true, - 'message': 'Test passed', - 'duration': 150, - 'data': {'key': 'value'}, - }; - - final testResult = TestResult.fromMap(map); - - expect(testResult.passed, true); - expect(testResult.message, 'Test passed'); - expect(testResult.duration, const Duration(milliseconds: 150)); - expect(testResult.data, {'key': 'value'}); - }); - - test('toMap should serialize to JSON correctly', () { - final testResult = TestResult( - passed: false, - message: 'Test failed', - duration: const Duration(milliseconds: 250), - data: {'error': 'timeout'}, - ); - - final map = testResult.toMap(); - - expect(map['passed'], false); - expect(map['message'], 'Test failed'); - expect(map['duration'], 250); - expect(map['data'], {'error': 'timeout'}); - }); - - test('duration formatting should work correctly', () { - final testResult1 = TestResult( - passed: true, - message: 'Test', - duration: const Duration(milliseconds: 50), - ); - - final testResult2 = TestResult( - passed: true, - message: 'Test', - duration: const Duration(milliseconds: 1500), - ); - - final testResult3 = TestResult( - passed: true, - message: 'Test', - duration: const Duration(seconds: 65), - ); - - expect(testResult1.durationFormatted, '50ms'); - expect(testResult2.durationFormatted, '1.50s'); - expect(testResult3.durationFormatted, '1:05'); - }); - - test('null data should be handled correctly', () { - final testResult = TestResult( - passed: true, - message: 'Test passed', - duration: const Duration(milliseconds: 100), - ); - - final map = testResult.toMap(); - - expect(map['data'], null); - expect(testResult.data, null); - }); - }); -} diff --git a/flutter_inappwebview/example/test/models/test_runner_models_test.dart b/flutter_inappwebview/example/test/models/test_runner_models_test.dart deleted file mode 100644 index a74cc33b3a..0000000000 --- a/flutter_inappwebview/example/test/models/test_runner_models_test.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/models/test_result.dart'; -import 'package:flutter_inappwebview_example/models/test_runner_models.dart'; -import 'package:flutter_inappwebview_example/utils/constants.dart'; - -void main() { - test('ExtendedTestResult round-trips via JSON', () { - final now = DateTime.now(); - final original = ExtendedTestResult( - testId: 'test_1', - testTitle: 'Test Title', - category: TestCategory.navigation, - success: true, - message: 'Test passed', - duration: const Duration(milliseconds: 100), - timestamp: now, - data: {'key': 'value'}, - skipped: false, - ); - - final json = original.toJson(); - final restored = ExtendedTestResult.fromJson(json); - - expect(restored.testId, original.testId); - expect(restored.testTitle, original.testTitle); - expect(restored.category, original.category); - expect(restored.success, original.success); - expect(restored.message, original.message); - expect(restored.data?['key'], 'value'); - }); - - test('ExecutableTestCase exposes metadata', () { - final testCase = ExecutableTestCase( - id: 'case_1', - title: 'Case 1', - description: 'Desc', - category: TestCategory.content, - execute: (controller) async => - TestResult(passed: true, message: 'ok', duration: Duration.zero), - supportedPlatforms: const ['android', 'ios'], - ); - - expect(testCase.id, 'case_1'); - expect(testCase.supportedPlatforms, containsAll(['android', 'ios'])); - }); - - test('TestCategoryGroup exposes display name and description', () { - final group = TestCategoryGroup( - category: TestCategory.navigation, - tests: const [], - ); - - expect(group.name, TestCategory.navigation.displayName); - expect(group.description, TestCategory.navigation.description); - }); -} diff --git a/flutter_inappwebview/example/test/providers/event_log_provider_test.dart b/flutter_inappwebview/example/test/providers/event_log_provider_test.dart deleted file mode 100644 index 4df9f8c7da..0000000000 --- a/flutter_inappwebview/example/test/providers/event_log_provider_test.dart +++ /dev/null @@ -1,217 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/models/event_log_entry.dart'; - -void main() { - group('EventLogProvider', () { - late EventLogProvider provider; - - setUp(() { - provider = EventLogProvider(); - }); - - test('addEvent should add event to list', () { - final entry = EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Test event', - ); - - provider.addEvent(entry); - - expect(provider.events.length, 1); - expect(provider.events[0], entry); - }); - - test('adding 1001 events should keep only last 1000', () { - for (int i = 0; i < 1001; i++) { - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Event $i', - ), - ); - } - - expect(provider.events.length, 1000); - expect(provider.events[0].message, 'Event 1'); - expect(provider.events[999].message, 'Event 1000'); - }); - - test('filterByType should filter events by type', () { - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Nav 1', - ), - ); - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.javascript, - message: 'JS 1', - ), - ); - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Nav 2', - ), - ); - - final filtered = provider.filterByType(EventType.navigation); - - expect(filtered.length, 2); - expect(filtered[0].message, 'Nav 1'); - expect(filtered[1].message, 'Nav 2'); - }); - - test('filterByType with null should return all events', () { - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Nav 1', - ), - ); - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.javascript, - message: 'JS 1', - ), - ); - - final filtered = provider.filterByType(null); - - expect(filtered.length, 2); - }); - - test('search should filter events by message content', () { - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Page loaded successfully', - ), - ); - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.error, - message: 'Network error occurred', - ), - ); - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Navigation started', - ), - ); - - final searchResults = provider.search('error'); - - expect(searchResults.length, 1); - expect(searchResults[0].message, 'Network error occurred'); - }); - - test('search should be case-insensitive', () { - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Page Loaded Successfully', - ), - ); - - final searchResults = provider.search('loaded'); - - expect(searchResults.length, 1); - expect(searchResults[0].message, 'Page Loaded Successfully'); - }); - - test('search with empty string should return all events', () { - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Event 1', - ), - ); - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.javascript, - message: 'Event 2', - ), - ); - - final searchResults = provider.search(''); - - expect(searchResults.length, 2); - }); - - test('clear should remove all events', () { - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Event 1', - ), - ); - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.javascript, - message: 'Event 2', - ), - ); - - expect(provider.events.length, 2); - - provider.clear(); - - expect(provider.events.length, 0); - }); - - test('provider should notify listeners on addEvent', () { - int notifyCount = 0; - provider.addListener(() { - notifyCount++; - }); - - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Test', - ), - ); - - expect(notifyCount, 1); - }); - - test('provider should notify listeners on clear', () { - int notifyCount = 0; - provider.addListener(() { - notifyCount++; - }); - - provider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Test', - ), - ); - - provider.clear(); - - expect(notifyCount, 2); // Once for add, once for clear - }); - }); -} diff --git a/flutter_inappwebview/example/test/providers/network_monitor_test.dart b/flutter_inappwebview/example/test/providers/network_monitor_test.dart deleted file mode 100644 index 4b077d0d2b..0000000000 --- a/flutter_inappwebview/example/test/providers/network_monitor_test.dart +++ /dev/null @@ -1,188 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/models/network_request.dart'; -import 'package:flutter_inappwebview_example/providers/network_monitor.dart'; - -void main() { - group('NetworkMonitor', () { - late NetworkMonitor monitor; - - setUp(() { - monitor = NetworkMonitor(); - }); - - test('initial state has empty requests and monitoring disabled', () { - expect(monitor.requests, isEmpty); - expect(monitor.isMonitoring, false); - }); - - test('toggleMonitoring changes monitoring state', () { - expect(monitor.isMonitoring, false); - - monitor.toggleMonitoring(); - expect(monitor.isMonitoring, true); - - monitor.toggleMonitoring(); - expect(monitor.isMonitoring, false); - }); - - test('addRequest adds request to list', () { - final request = NetworkRequest( - id: '1', - method: 'GET', - url: 'https://example.com', - timestamp: DateTime.now(), - ); - - monitor.addRequest(request); - - expect(monitor.requests.length, 1); - expect(monitor.requests.first, request); - }); - - test('addRequest notifies listeners', () { - var notified = false; - monitor.addListener(() { - notified = true; - }); - - final request = NetworkRequest( - id: '1', - method: 'GET', - url: 'https://example.com', - timestamp: DateTime.now(), - ); - - monitor.addRequest(request); - - expect(notified, true); - }); - - test('updateRequest updates existing request', () { - final request = NetworkRequest( - id: '1', - method: 'GET', - url: 'https://example.com', - timestamp: DateTime.now(), - ); - - monitor.addRequest(request); - - monitor.updateRequest( - '1', - response: '{"success": true}', - statusCode: 200, - duration: Duration(milliseconds: 150), - ); - - expect(monitor.requests.length, 1); - expect(monitor.requests.first.id, '1'); - expect(monitor.requests.first.statusCode, 200); - expect(monitor.requests.first.response, '{"success": true}'); - expect(monitor.requests.first.duration, Duration(milliseconds: 150)); - }); - - test('updateRequest does nothing for non-existent request', () { - monitor.updateRequest( - 'non-existent', - response: '{"success": true}', - statusCode: 200, - ); - - expect(monitor.requests, isEmpty); - }); - - test('updateRequest notifies listeners', () { - final request = NetworkRequest( - id: '1', - method: 'GET', - url: 'https://example.com', - timestamp: DateTime.now(), - ); - - monitor.addRequest(request); - - var notified = false; - monitor.addListener(() { - notified = true; - }); - - monitor.updateRequest('1', statusCode: 200); - - expect(notified, true); - }); - - test('clearRequests removes all requests', () { - final request1 = NetworkRequest( - id: '1', - method: 'GET', - url: 'https://example.com', - timestamp: DateTime.now(), - ); - final request2 = NetworkRequest( - id: '2', - method: 'POST', - url: 'https://example.com/api', - timestamp: DateTime.now(), - ); - - monitor.addRequest(request1); - monitor.addRequest(request2); - - expect(monitor.requests.length, 2); - - monitor.clearRequests(); - - expect(monitor.requests, isEmpty); - }); - - test('clearRequests notifies listeners', () { - final request = NetworkRequest( - id: '1', - method: 'GET', - url: 'https://example.com', - timestamp: DateTime.now(), - ); - - monitor.addRequest(request); - - var notified = false; - monitor.addListener(() { - notified = true; - }); - - monitor.clearRequests(); - - expect(notified, true); - }); - - test('multiple requests are stored in order', () { - final request1 = NetworkRequest( - id: '1', - method: 'GET', - url: 'https://example.com/1', - timestamp: DateTime.now(), - ); - final request2 = NetworkRequest( - id: '2', - method: 'POST', - url: 'https://example.com/2', - timestamp: DateTime.now(), - ); - final request3 = NetworkRequest( - id: '3', - method: 'PUT', - url: 'https://example.com/3', - timestamp: DateTime.now(), - ); - - monitor.addRequest(request1); - monitor.addRequest(request2); - monitor.addRequest(request3); - - expect(monitor.requests.length, 3); - expect(monitor.requests[0].id, '1'); - expect(monitor.requests[1].id, '2'); - expect(monitor.requests[2].id, '3'); - }); - }); -} diff --git a/flutter_inappwebview/example/test/providers/settings_manager_test.dart b/flutter_inappwebview/example/test/providers/settings_manager_test.dart deleted file mode 100644 index 1bed8f9c88..0000000000 --- a/flutter_inappwebview/example/test/providers/settings_manager_test.dart +++ /dev/null @@ -1,78 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; - -void main() { - group('SettingsManager', () { - setUp(() { - SharedPreferences.setMockInitialValues({}); - }); - - test('selecting a settings profile updates current settings', () async { - final manager = SettingsManager(); - await manager.init(); - - final profile = await manager.createProfile( - 'Profile A', - settings: {'javaScriptEnabled': false}, - ); - - final startRevision = manager.settingsRevision; - await manager.loadProfile(profile.id); - - expect(manager.currentProfileId, profile.id); - expect(manager.getSetting('javaScriptEnabled'), false); - expect(manager.settingsRevision, startRevision + 1); - }); - - test('editing and removing a settings profile updates state', () async { - final manager = SettingsManager(); - await manager.init(); - - final profile = await manager.createProfile('Old', settings: {}); - await manager.updateProfile(profile.id, name: 'New'); - - expect(manager.profiles.single.name, 'New'); - - await manager.loadProfile(profile.id); - await manager.deleteProfile(profile.id); - - expect(manager.currentProfileId, isNull); - expect(manager.profiles, isEmpty); - }); - - test('environment profile selection recreates environment state', () async { - var createCalls = 0; - final manager = SettingsManager( - environmentSupportChecker: () => true, - environmentFactory: (settings) async { - createCalls++; - return null; - }, - ); - await manager.init(); - - final profile = await manager.createEnvironmentProfile( - 'Env', - settings: {'userDataFolder': 'test'}, - ); - - final startRevision = manager.environmentRevision; - await manager.loadEnvironmentProfile(profile.id); - - expect(manager.currentEnvironmentProfileId, profile.id); - expect(createCalls, 1); - expect(manager.environmentRevision, startRevision + 1); - - await manager.updateEnvironmentProfile( - profile.id, - settings: {'userDataFolder': 'new'}, - ); - - expect(createCalls, 2); - - await manager.deleteEnvironmentProfile(profile.id); - expect(manager.currentEnvironmentProfileId, isNull); - }); - }); -} diff --git a/flutter_inappwebview/example/test/providers/test_runner_test.dart b/flutter_inappwebview/example/test/providers/test_runner_test.dart deleted file mode 100644 index 21e06f9d0f..0000000000 --- a/flutter_inappwebview/example/test/providers/test_runner_test.dart +++ /dev/null @@ -1,287 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/providers/test_runner.dart'; -import 'package:flutter_inappwebview_example/models/test_configuration.dart'; -import 'package:flutter_inappwebview_example/models/test_result.dart'; -import 'package:flutter_inappwebview_example/models/test_runner_models.dart'; -import 'package:flutter_inappwebview_example/utils/constants.dart'; - -void main() { - group('TestRunner', () { - late TestRunner testRunner; - - setUp(() { - testRunner = TestRunner(); - }); - - group('Initial State', () { - test('starts with idle status', () { - expect(testRunner.status, TestStatus.idle); - }); - - test('starts with no results', () { - expect(testRunner.results, isEmpty); - }); - - test('starts with zero progress', () { - expect(testRunner.progress, 0); - expect(testRunner.total, 0); - }); - - test('starts with no current test', () { - expect(testRunner.currentTest, isNull); - }); - - test('successRate is 0 when no tests', () { - expect(testRunner.successRate, 0.0); - }); - }); - - group('Test Categories', () { - test('getTestCategories returns all categories', () { - final categories = TestRunner.getTestCategories(); - - expect(categories, isNotEmpty); - expect( - categories.map((c) => c.category), - containsAll([ - TestCategory.navigation, - TestCategory.javascript, - TestCategory.content, - TestCategory.storage, - TestCategory.advanced, - ]), - ); - }); - - test('each category has tests', () { - final categories = TestRunner.getTestCategories(); - - for (final category in categories) { - expect( - category.tests, - isNotEmpty, - reason: 'Category ${category.name} should have tests', - ); - } - }); - - test('each category has a non-empty name', () { - final categories = TestRunner.getTestCategories(); - - for (final category in categories) { - expect(category.name, isNotEmpty); - } - }); - }); - - group('Results Management', () { - test('clearResults resets state', () { - // Add some mock state - testRunner.clearResults(); - - expect(testRunner.results, isEmpty); - expect(testRunner.status, TestStatus.idle); - expect(testRunner.progress, 0); - expect(testRunner.total, 0); - }); - }); - - group('Result Statistics', () { - test('counts passed tests correctly', () { - // We can't directly add results, but we can test the calculation methods - expect(testRunner.passed, 0); - expect(testRunner.failed, 0); - expect(testRunner.skipped, 0); - }); - }); - - group('Export Functionality', () { - test('exports empty results as valid JSON', () { - final jsonString = testRunner.exportResultsAsJson(); - - expect(jsonString, isNotEmpty); - expect(() => jsonString, returnsNormally); - }); - }); - }); - - group('TestCategory', () { - test('has all expected categories', () { - expect(TestCategory.values, contains(TestCategory.navigation)); - expect(TestCategory.values, contains(TestCategory.javascript)); - expect(TestCategory.values, contains(TestCategory.content)); - expect(TestCategory.values, contains(TestCategory.storage)); - expect(TestCategory.values, contains(TestCategory.advanced)); - expect(TestCategory.values, contains(TestCategory.browsers)); - }); - }); - - group('TestStatus', () { - test('has all expected statuses', () { - expect(TestStatus.values, contains(TestStatus.idle)); - expect(TestStatus.values, contains(TestStatus.running)); - expect(TestStatus.values, contains(TestStatus.paused)); - expect(TestStatus.values, contains(TestStatus.completed)); - expect(TestStatus.values, contains(TestStatus.error)); - }); - }); - - group('ExecutableTestCase', () { - test('can be created with required fields', () { - final testCase = ExecutableTestCase( - id: 'test_1', - title: 'Test Title', - description: 'Test description', - category: TestCategory.navigation, - execute: (controller) async { - return TestResult( - passed: true, - message: 'Test passed', - duration: Duration.zero, - ); - }, - ); - - expect(testCase.id, 'test_1'); - expect(testCase.title, 'Test Title'); - expect(testCase.description, 'Test description'); - expect(testCase.category, TestCategory.navigation); - }); - - test('supports platform filtering', () { - final testCase = ExecutableTestCase( - id: 'test_1', - title: 'Test Title', - description: 'Test description', - category: TestCategory.navigation, - supportedPlatforms: ['android', 'ios'], - execute: (controller) async => TestResult( - passed: true, - message: 'Test passed', - duration: Duration.zero, - ), - ); - - expect(testCase.supportedPlatforms, containsAll(['android', 'ios'])); - }); - }); - - group('ExtendedTestResult', () { - test('can be created with required fields', () { - final result = ExtendedTestResult( - testId: 'test_1', - testTitle: 'Test Title', - category: TestCategory.navigation, - success: true, - message: 'Test passed', - duration: const Duration(milliseconds: 100), - timestamp: DateTime.now(), - ); - - expect(result.testId, 'test_1'); - expect(result.testTitle, 'Test Title'); - expect(result.category, TestCategory.navigation); - expect(result.success, true); - expect(result.message, 'Test passed'); - expect(result.skipped, false); - }); - - test('supports skipped state', () { - final result = ExtendedTestResult( - testId: 'test_1', - testTitle: 'Test Title', - category: TestCategory.navigation, - success: false, - message: 'Skipped', - duration: Duration.zero, - timestamp: DateTime.now(), - skipped: true, - skipReason: 'Platform not supported', - ); - - expect(result.skipped, true); - expect(result.skipReason, 'Platform not supported'); - }); - - test('can store additional data', () { - final result = ExtendedTestResult( - testId: 'test_1', - testTitle: 'Test Title', - category: TestCategory.navigation, - success: true, - message: 'Test passed', - duration: const Duration(milliseconds: 100), - timestamp: DateTime.now(), - data: {'key': 'value', 'count': 42}, - ); - - expect(result.data, isNotNull); - expect(result.data!['key'], 'value'); - expect(result.data!['count'], 42); - }); - }); - - group('TestCategoryGroup', () { - test('can be created with tests', () { - final group = TestCategoryGroup( - category: TestCategory.navigation, - tests: [ - ExecutableTestCase( - id: 'test_1', - title: 'Test 1', - description: 'Description', - category: TestCategory.navigation, - execute: (controller) async => TestResult( - passed: true, - message: 'Test passed', - duration: Duration.zero, - ), - ), - ], - ); - - expect(group.name, TestCategory.navigation.displayName); - expect(group.description, TestCategory.navigation.description); - expect(group.category, TestCategory.navigation); - expect(group.tests, hasLength(1)); - }); - }); - - group('TestConfiguration Integration', () { - test('TestWebViewType enum values', () { - expect(TestWebViewType.values, contains(TestWebViewType.inAppWebView)); - expect(TestWebViewType.values, contains(TestWebViewType.headless)); - }); - - test('ExpectedResultType enum has all validators', () { - expect(ExpectedResultType.values, contains(ExpectedResultType.any)); - expect(ExpectedResultType.values, contains(ExpectedResultType.exact)); - expect(ExpectedResultType.values, contains(ExpectedResultType.contains)); - expect(ExpectedResultType.values, contains(ExpectedResultType.regex)); - expect(ExpectedResultType.values, contains(ExpectedResultType.notNull)); - expect(ExpectedResultType.values, contains(ExpectedResultType.isNull)); - expect(ExpectedResultType.values, contains(ExpectedResultType.truthy)); - expect(ExpectedResultType.values, contains(ExpectedResultType.falsy)); - }); - - test('CustomTestActionType enum has all action types', () { - expect( - CustomTestActionType.values, - contains(CustomTestActionType.evaluateJavascript), - ); - expect( - CustomTestActionType.values, - contains(CustomTestActionType.loadUrl), - ); - expect( - CustomTestActionType.values, - contains(CustomTestActionType.loadHtml), - ); - expect( - CustomTestActionType.values, - contains(CustomTestActionType.controllerMethod), - ); - expect(CustomTestActionType.values, contains(CustomTestActionType.delay)); - }); - }); -} diff --git a/flutter_inappwebview/example/test/screens/category_screen_test.dart b/flutter_inappwebview/example/test/screens/category_screen_test.dart deleted file mode 100644 index 83b272ca62..0000000000 --- a/flutter_inappwebview/example/test/screens/category_screen_test.dart +++ /dev/null @@ -1,158 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/screens/category_screen.dart'; -import 'package:flutter_inappwebview_example/utils/constants.dart'; -import 'package:flutter_inappwebview_example/utils/test_registry.dart'; -import 'package:flutter_inappwebview_example/models/test_case.dart'; -import 'package:flutter_inappwebview_example/models/test_result.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; -import 'package:flutter_inappwebview_example/providers/test_runner.dart'; -import 'package:flutter_inappwebview_example/providers/network_monitor.dart'; - -void main() { - group('CategoryScreen', () { - setUp(() { - TestRegistry.clear(); - }); - - Widget createTestWidget(TestCategory category) { - return MultiProvider( - providers: [ - ChangeNotifierProvider(create: (_) => EventLogProvider()), - ChangeNotifierProvider(create: (_) => SettingsManager()), - ChangeNotifierProvider(create: (_) => TestRunner()), - ChangeNotifierProvider(create: (_) => NetworkMonitor()), - ], - child: MaterialApp(home: CategoryScreen(category: category)), - ); - } - - testWidgets('displays category name in AppBar', ( - WidgetTester tester, - ) async { - await tester.pumpWidget(createTestWidget(TestCategory.navigation)); - - expect(find.text('Navigation Tests'), findsOneWidget); - }); - - testWidgets('displays tests from registry', (WidgetTester tester) async { - // Register a test - TestRegistry.register( - TestCase( - id: 'test_1', - title: 'Test Title', - description: 'Test description', - category: TestCategory.navigation, - complexity: TestComplexity.quick, - supportedPlatforms: ['android'], - execute: () async => TestResult( - passed: true, - message: 'Test passed', - duration: Duration.zero, - ), - ), - ); - - await tester.pumpWidget(createTestWidget(TestCategory.navigation)); - - expect(find.text('Test Title'), findsOneWidget); - }); - - testWidgets('displays empty state when no tests', ( - WidgetTester tester, - ) async { - await tester.pumpWidget(createTestWidget(TestCategory.navigation)); - - expect(find.text('No tests available'), findsOneWidget); - expect( - find.text('No tests registered for this category'), - findsOneWidget, - ); - }); - - testWidgets('displays multiple tests', (WidgetTester tester) async { - TestRegistry.register( - TestCase( - id: 'test_1', - title: 'Test 1', - description: 'Description 1', - category: TestCategory.navigation, - complexity: TestComplexity.quick, - supportedPlatforms: ['android'], - execute: () async => TestResult( - passed: true, - message: 'Test passed', - duration: Duration.zero, - ), - ), - ); - - TestRegistry.register( - TestCase( - id: 'test_2', - title: 'Test 2', - description: 'Description 2', - category: TestCategory.navigation, - complexity: TestComplexity.medium, - supportedPlatforms: ['ios'], - execute: () async => TestResult( - passed: true, - message: 'Test passed', - duration: Duration.zero, - ), - ), - ); - - await tester.pumpWidget(createTestWidget(TestCategory.navigation)); - - expect(find.text('Test 1'), findsOneWidget); - expect(find.text('Test 2'), findsOneWidget); - }); - - testWidgets('has platform filter button', (WidgetTester tester) async { - TestRegistry.register( - TestCase( - id: 'test_1', - title: 'Test 1', - description: 'Description', - category: TestCategory.navigation, - complexity: TestComplexity.quick, - supportedPlatforms: ['android', 'ios'], - execute: () async => TestResult( - passed: true, - message: 'Test passed', - duration: Duration.zero, - ), - ), - ); - - await tester.pumpWidget(createTestWidget(TestCategory.navigation)); - - expect(find.byIcon(Icons.filter_list), findsOneWidget); - }); - - testWidgets('displays test count', (WidgetTester tester) async { - TestRegistry.register( - TestCase( - id: 'test_1', - title: 'Test 1', - description: 'Description', - category: TestCategory.navigation, - complexity: TestComplexity.quick, - supportedPlatforms: ['android'], - execute: () async => TestResult( - passed: true, - message: 'Test passed', - duration: Duration.zero, - ), - ), - ); - - await tester.pumpWidget(createTestWidget(TestCategory.navigation)); - - expect(find.textContaining('1 test'), findsOneWidget); - }); - }); -} diff --git a/flutter_inappwebview/example/test/screens/controllers_screen_test.dart b/flutter_inappwebview/example/test/screens/controllers_screen_test.dart deleted file mode 100644 index ea388f4e66..0000000000 --- a/flutter_inappwebview/example/test/screens/controllers_screen_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/screens/advanced/controllers_screen.dart'; -import '../test_helpers/mock_inappwebview_platform.dart'; - -void main() { - group('ControllersScreen', () { - setUp(() { - MockInAppWebViewPlatform.initialize(); - }); - - Widget createWidget() { - return MultiProvider( - providers: [ - ChangeNotifierProvider( - create: (_) => EventLogProvider(), - ), - ], - child: const MaterialApp(home: ControllersScreen()), - ); - } - - testWidgets('does not overflow on small height', (tester) async { - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(tester.takeException(), isNull); - }); - }); -} diff --git a/flutter_inappwebview/example/test/screens/headless_webview_screen_test.dart b/flutter_inappwebview/example/test/screens/headless_webview_screen_test.dart deleted file mode 100644 index 47f2fe3369..0000000000 --- a/flutter_inappwebview/example/test/screens/headless_webview_screen_test.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; -import 'package:flutter_inappwebview_example/screens/browsers/headless_webview_screen.dart'; -import '../test_helpers/test_settings_manager.dart'; - -void main() { - group('HeadlessWebViewScreen', () { - Widget createWidget() { - return MultiProvider( - providers: [ - ChangeNotifierProvider( - create: (_) => EventLogProvider(), - ), - ChangeNotifierProvider( - create: (_) => TestSettingsManager(), - ), - ], - child: const MaterialApp(home: HeadlessWebViewScreen()), - ); - } - - testWidgets('does not overflow on small height', (tester) async { - tester.binding.window.physicalSizeTestValue = const Size(320, 280); - tester.binding.window.devicePixelRatioTestValue = 1.0; - addTearDown(() { - tester.binding.window.clearPhysicalSizeTestValue(); - tester.binding.window.clearDevicePixelRatioTestValue(); - }); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(tester.takeException(), isNull); - }); - - testWidgets('test_headless_config_stacks_on_mobile', (tester) async { - tester.binding.window.physicalSizeTestValue = const Size(320, 640); - tester.binding.window.devicePixelRatioTestValue = 1.0; - addTearDown(() { - tester.binding.window.clearPhysicalSizeTestValue(); - tester.binding.window.clearDevicePixelRatioTestValue(); - }); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - final widthField = find.byKey(const Key('headless_webview_width_field')); - final heightField = find.byKey( - const Key('headless_webview_height_field'), - ); - - final mainScrollView = find - .descendant( - of: find.byKey(const Key('headless_webview_main_list')), - matching: find.byType(Scrollable), - ) - .first; - - await tester.scrollUntilVisible( - widthField, - 200, - scrollable: mainScrollView, - ); - await tester.pump(); - - expect(widthField, findsOneWidget); - expect(heightField, findsOneWidget); - - final widthTop = tester.getTopLeft(widthField).dy; - final heightTop = tester.getTopLeft(heightField).dy; - - expect(heightTop, greaterThan(widthTop)); - expect(tester.takeException(), isNull); - }); - }); -} diff --git a/flutter_inappwebview/example/test/screens/home_screen_test.dart b/flutter_inappwebview/example/test/screens/home_screen_test.dart deleted file mode 100644 index be8991622a..0000000000 --- a/flutter_inappwebview/example/test/screens/home_screen_test.dart +++ /dev/null @@ -1,104 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/screens/home_screen.dart'; -import 'package:flutter_inappwebview_example/utils/test_registry.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; -import 'package:flutter_inappwebview_example/providers/test_runner.dart'; -import 'package:flutter_inappwebview_example/providers/network_monitor.dart'; -import 'package:flutter_inappwebview_example/utils/platform_utils.dart'; - -void main() { - group('HomeScreen', () { - setUp(() { - TestRegistry.init(); - }); - - Widget createTestWidget() { - return MultiProvider( - providers: [ - ChangeNotifierProvider(create: (_) => EventLogProvider()), - ChangeNotifierProvider(create: (_) => SettingsManager()), - ChangeNotifierProvider(create: (_) => TestRunner()), - ChangeNotifierProvider(create: (_) => NetworkMonitor()), - ], - child: const MaterialApp(home: HomeScreen()), - ); - } - - testWidgets('renders app title in AppBar', (WidgetTester tester) async { - await tester.pumpWidget(createTestWidget()); - - expect(find.text('InAppWebView Test Suite'), findsOneWidget); - }); - - testWidgets('displays 6 category cards', (WidgetTester tester) async { - await tester.pumpWidget(createTestWidget()); - - // Look for category names - expect(find.text('Navigation'), findsOneWidget); - expect(find.text('JavaScript'), findsOneWidget); - expect(find.text('Content'), findsOneWidget); - expect(find.text('Storage & Cookies'), findsOneWidget); - expect(find.text('Advanced Features'), findsOneWidget); - expect(find.text('Browsers'), findsOneWidget); - }); - - testWidgets('category cards show test counts', (WidgetTester tester) async { - await tester.pumpWidget(createTestWidget()); - - // Should display test counts (format: "X tests") - expect(find.textContaining('test'), findsAtLeastNWidgets(6)); - }); - - testWidgets('category cards are tappable', (WidgetTester tester) async { - await tester.pumpWidget(createTestWidget()); - - // Find first category card - final navigationCard = find.text('Navigation'); - expect(navigationCard, findsOneWidget); - - // Cards should be wrapped in InkWell or GestureDetector - final inkWell = find.ancestor( - of: navigationCard, - matching: find.byType(InkWell), - ); - expect(inkWell, findsOneWidget); - }); - - testWidgets('has floating action button for platform info', ( - WidgetTester tester, - ) async { - await tester.pumpWidget(createTestWidget()); - - expect(find.byType(FloatingActionButton), findsOneWidget); - expect(find.byIcon(Icons.info_outline), findsOneWidget); - }); - - testWidgets('displays platform indicator', (WidgetTester tester) async { - await tester.pumpWidget(createTestWidget()); - - // Should show current platform somewhere - final platformIcon = PlatformUtils.getPlatformIcon(); - expect(find.byIcon(platformIcon), findsAny); - }); - - testWidgets('category cards have icons', (WidgetTester tester) async { - await tester.pumpWidget(createTestWidget()); - - // Navigation icon - expect(find.byIcon(Icons.navigation), findsOneWidget); - // JavaScript icon - expect(find.byIcon(Icons.code), findsOneWidget); - // Content icon - expect(find.byIcon(Icons.article), findsOneWidget); - // Storage icon - expect(find.byIcon(Icons.storage), findsOneWidget); - // Advanced icon - expect(find.byIcon(Icons.settings), findsOneWidget); - // Browsers icon - expect(find.byIcon(Icons.web), findsOneWidget); - }); - }); -} diff --git a/flutter_inappwebview/example/test/screens/inapp_browser_screen_test.dart b/flutter_inappwebview/example/test/screens/inapp_browser_screen_test.dart deleted file mode 100644 index b0cfa1ecbf..0000000000 --- a/flutter_inappwebview/example/test/screens/inapp_browser_screen_test.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; -import 'package:flutter_inappwebview_example/screens/browsers/inapp_browser_screen.dart'; -import '../test_helpers/test_settings_manager.dart'; - -void main() { - group('InAppBrowserScreen', () { - Widget createWidget() { - return MultiProvider( - providers: [ - ChangeNotifierProvider( - create: (_) => EventLogProvider(), - ), - ChangeNotifierProvider( - create: (_) => TestSettingsManager(), - ), - ], - child: const MaterialApp(home: InAppBrowserScreen()), - ); - } - - testWidgets('does not overflow on small height', (tester) async { - tester.binding.window.physicalSizeTestValue = const Size(320, 280); - tester.binding.window.devicePixelRatioTestValue = 1.0; - addTearDown(() { - tester.binding.window.clearPhysicalSizeTestValue(); - tester.binding.window.clearDevicePixelRatioTestValue(); - }); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(tester.takeException(), isNull); - }); - - testWidgets('test_inapp_browser_mobile_layout', (tester) async { - tester.binding.window.physicalSizeTestValue = const Size(320, 640); - tester.binding.window.devicePixelRatioTestValue = 1.0; - addTearDown(() { - tester.binding.window.clearPhysicalSizeTestValue(); - tester.binding.window.clearDevicePixelRatioTestValue(); - }); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - final idField = find.byKey(const Key('inapp_browser_menu_id_field')); - final titleField = find.byKey( - const Key('inapp_browser_menu_title_field'), - ); - final addButton = find.byKey(const Key('inapp_browser_menu_add_button')); - - final mainScrollView = find - .descendant( - of: find.byKey(const Key('inapp_browser_main_list')), - matching: find.byType(Scrollable), - ) - .first; - - await tester.scrollUntilVisible(idField, 200, scrollable: mainScrollView); - await tester.pump(); - - expect(idField, findsOneWidget); - expect(titleField, findsOneWidget); - expect(addButton, findsOneWidget); - - final idTop = tester.getTopLeft(idField).dy; - final titleTop = tester.getTopLeft(titleField).dy; - final addTop = tester.getTopLeft(addButton).dy; - - expect(titleTop, greaterThan(idTop)); - expect(addTop, greaterThan(titleTop)); - expect(tester.takeException(), isNull); - }); - }); -} diff --git a/flutter_inappwebview/example/test/screens/platform_info_screen_test.dart b/flutter_inappwebview/example/test/screens/platform_info_screen_test.dart deleted file mode 100644 index d200036c12..0000000000 --- a/flutter_inappwebview/example/test/screens/platform_info_screen_test.dart +++ /dev/null @@ -1,71 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/screens/platform_info_screen.dart'; -import 'package:flutter_inappwebview_example/utils/platform_utils.dart'; - -void main() { - group('PlatformInfoScreen', () { - testWidgets('renders platform information', (WidgetTester tester) async { - await tester.pumpWidget(const MaterialApp(home: PlatformInfoScreen())); - - // Check for AppBar - expect(find.text('Platform Information'), findsOneWidget); - - // Check for platform name (should appear in one of the info tiles) - final platformName = PlatformUtils.getPlatformName(); - // Platform name might appear multiple times (label + value) - expect(find.textContaining(platformName), findsWidgets); - }); - - testWidgets('displays Flutter version', (WidgetTester tester) async { - await tester.pumpWidget(const MaterialApp(home: PlatformInfoScreen())); - - // Flutter version label should be present - expect(find.text('Flutter Version'), findsOneWidget); - }); - - testWidgets('displays Dart version', (WidgetTester tester) async { - await tester.pumpWidget(const MaterialApp(home: PlatformInfoScreen())); - - // Dart version label should be present - expect(find.text('Dart Version'), findsOneWidget); - }); - - testWidgets('shows supported features section', ( - WidgetTester tester, - ) async { - await tester.pumpWidget(const MaterialApp(home: PlatformInfoScreen())); - - // Should show the Core WebView Features section - expect(find.text('Core WebView Features'), findsOneWidget); - }); - - testWidgets('has back button', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Builder( - builder: (context) => ElevatedButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (_) => const PlatformInfoScreen(), - ), - ); - }, - child: const Text('Open'), - ), - ), - ), - ), - ); - - await tester.tap(find.text('Open')); - await tester.pumpAndSettle(); - - // AppBar should have a leading widget (back button or similar) - expect(find.byType(AppBar), findsOneWidget); - }); - }); -} diff --git a/flutter_inappwebview/example/test/screens/responsive_phase7_screens_test.dart b/flutter_inappwebview/example/test/screens/responsive_phase7_screens_test.dart deleted file mode 100644 index 54d6440f96..0000000000 --- a/flutter_inappwebview/example/test/screens/responsive_phase7_screens_test.dart +++ /dev/null @@ -1,168 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/screens/advanced/service_controllers_screen.dart'; -import 'package:flutter_inappwebview_example/screens/storage/cookie_manager_screen.dart'; -import 'package:flutter_inappwebview_example/screens/support_matrix/platform_comparison_screen.dart'; -import 'package:flutter_inappwebview_example/screens/support_matrix/support_matrix_screen.dart'; - -import '../test_helpers/mock_inappwebview_platform.dart'; -import '../test_helpers/test_provider_wrapper.dart'; - -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - - setUpAll(() { - MockInAppWebViewPlatform.initialize(); - }); - - Future pumpScreen(WidgetTester tester, Widget screen) async { - MockInAppWebViewPlatform.initialize(); - await tester.pumpWidget(screen); - await tester.pump(const Duration(milliseconds: 100)); - } - - Future clearScreen(WidgetTester tester) async { - await tester.pumpWidget(const SizedBox.shrink()); - await tester.pump(const Duration(milliseconds: 50)); - } - - testWidgets('test_all_screens_mobile_no_overflow', (tester) async { - final errors = []; - final previousOnError = FlutterError.onError; - FlutterError.onError = (details) { - final message = details.exceptionAsString(); - final stack = details.stack?.toString() ?? ''; - if (stack.contains('RenderViewportBase.visitChildrenForSemantics') || - message.contains('semantics.parentDataDirty')) { - return; - } - errors.add(details); - }; - - void assertNoErrors(String label) { - if (errors.isEmpty) { - return; - } - final messages = errors - .map((detail) => detail.exceptionAsString()) - .join('\n'); - errors.clear(); - fail('Unexpected Flutter errors detected in $label:\n$messages'); - } - - addTearDown(() async { - FlutterError.onError = previousOnError; - tester.binding.window.clearPhysicalSizeTestValue(); - tester.binding.window.clearDevicePixelRatioTestValue(); - }); - - const size = Size(360, 700); - tester.binding.window.physicalSizeTestValue = size; - tester.binding.window.devicePixelRatioTestValue = 1.0; - - await pumpScreen(tester, const MaterialApp(home: SupportMatrixScreen())); - assertNoErrors('SupportMatrixScreen'); - await clearScreen(tester); - - await pumpScreen( - tester, - const MaterialApp(home: PlatformComparisonScreen()), - ); - assertNoErrors('PlatformComparisonScreen'); - await clearScreen(tester); - - await pumpScreen(tester, const MaterialApp(home: CookieManagerScreen())); - assertNoErrors('CookieManagerScreen'); - await clearScreen(tester); - - await pumpScreen( - tester, - MaterialApp( - home: TestProviderWrapper( - eventLogProvider: EventLogProvider(), - child: const ServiceControllersScreen(), - ), - ), - ); - assertNoErrors('ServiceControllersScreen'); - await clearScreen(tester); - - FlutterError.onError = previousOnError; - assertNoErrors('mobile layout'); - }); - - testWidgets('test_all_screens_tablet_layout', (tester) async { - final errors = []; - final previousOnError = FlutterError.onError; - FlutterError.onError = (details) { - final message = details.exceptionAsString(); - final stack = details.stack?.toString() ?? ''; - if (stack.contains('RenderViewportBase.visitChildrenForSemantics') || - message.contains('semantics.parentDataDirty')) { - return; - } - errors.add(details); - }; - - addTearDown(() async { - FlutterError.onError = previousOnError; - tester.binding.window.clearPhysicalSizeTestValue(); - tester.binding.window.clearDevicePixelRatioTestValue(); - }); - - const size = Size(800, 900); - tester.binding.window.physicalSizeTestValue = size; - tester.binding.window.devicePixelRatioTestValue = 1.0; - - await pumpScreen(tester, const MaterialApp(home: SupportMatrixScreen())); - expect(find.byKey(const Key('support_matrix_summary_row')), findsOneWidget); - await clearScreen(tester); - - await pumpScreen( - tester, - const MaterialApp(home: PlatformComparisonScreen()), - ); - expect( - find.byKey(const Key('platform_comparison_selectors_row')), - findsOneWidget, - ); - expect( - find.byKey(const Key('platform_comparison_stats_row')), - findsOneWidget, - ); - await clearScreen(tester); - - await pumpScreen(tester, const MaterialApp(home: CookieManagerScreen())); - expect(find.byKey(const Key('cookie_manager_url_row')), findsOneWidget); - await clearScreen(tester); - - await pumpScreen( - tester, - MaterialApp( - home: TestProviderWrapper( - eventLogProvider: EventLogProvider(), - child: const ServiceControllersScreen(), - ), - ), - ); - await tester.ensureVisible( - find.widgetWithText(ExpansionTile, 'ProxyController'), - ); - await tester.tap(find.widgetWithText(ExpansionTile, 'ProxyController')); - await tester.pump(const Duration(milliseconds: 100)); - expect( - find.byKey(const Key('service_controllers_proxy_row')), - findsOneWidget, - ); - await clearScreen(tester); - - FlutterError.onError = previousOnError; - if (errors.isNotEmpty) { - final messages = errors - .map((detail) => detail.exceptionAsString()) - .join('\n'); - fail('Unexpected Flutter errors detected:\n$messages'); - } - }); -} diff --git a/flutter_inappwebview/example/test/screens/service_controllers_screen_test.dart b/flutter_inappwebview/example/test/screens/service_controllers_screen_test.dart deleted file mode 100644 index bf42c87fd3..0000000000 --- a/flutter_inappwebview/example/test/screens/service_controllers_screen_test.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/screens/advanced/service_controllers_screen.dart'; - -import '../test_helpers/mock_inappwebview_platform.dart'; -import '../test_helpers/test_provider_wrapper.dart'; - -void main() { - setUpAll(() { - MockInAppWebViewPlatform.initialize(); - }); - - group('ServiceControllersScreen', () { - Widget createWidget() { - return MaterialApp( - home: TestProviderWrapper( - eventLogProvider: EventLogProvider(), - child: const ServiceControllersScreen(), - ), - ); - } - - testWidgets('does not overflow on small height', (tester) async { - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(tester.takeException(), isNull); - }); - }); -} diff --git a/flutter_inappwebview/example/test/screens/settings_editor_screen_test.dart b/flutter_inappwebview/example/test/screens/settings_editor_screen_test.dart deleted file mode 100644 index edb3fbe865..0000000000 --- a/flutter_inappwebview/example/test/screens/settings_editor_screen_test.dart +++ /dev/null @@ -1,137 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:flutter_inappwebview_example/screens/settings_editor_screen.dart'; -import 'package:flutter_inappwebview_example/widgets/settings/responsive_setting_tile.dart'; - -import '../test_helpers/mock_inappwebview_platform.dart'; -import '../test_helpers/test_provider_wrapper.dart'; - -void main() { - setUpAll(() { - MockInAppWebViewPlatform.initialize(); - }); - - setUp(() { - SharedPreferences.setMockInitialValues({}); - }); - - group('SettingsEditorScreen', () { - Widget createWidget({Size size = const Size(800, 600)}) { - return MaterialApp( - home: MediaQuery( - data: MediaQueryData(size: size), - child: const TestProviderWrapper(child: SettingsEditorScreen()), - ), - ); - } - - testWidgets('renders app bar title', (tester) async { - await tester.pumpWidget(createWidget()); - - expect(find.byType(AppBar), findsOneWidget); - expect(find.text('Settings Editor'), findsOneWidget); - }); - - testWidgets('shows search field after loading', (tester) async { - await tester.pumpWidget(createWidget()); - await tester.pumpAndSettle(); - - expect(find.text('Search settings...'), findsOneWidget); - expect(find.byIcon(Icons.search), findsOneWidget); - }); - - testWidgets('uses enum-like values for enumeration dropdowns', ( - tester, - ) async { - await tester.pumpWidget(createWidget()); - await tester.pumpAndSettle(); - - await tester.tap(find.byIcon(Icons.more_vert)); - await tester.pumpAndSettle(); - - await tester.tap(find.text('Expand All')); - await tester.pumpAndSettle(); - - await tester.dragUntilVisible( - find.text('Mixed Content Mode'), - find.byType(ListView), - const Offset(0, -300), - ); - await tester.pumpAndSettle(); - - final dropdownFinder = find.byType( - DropdownButton, - skipOffstage: false, - ); - expect(dropdownFinder, findsWidgets); - - final dropdown = tester.widget>( - dropdownFinder.first, - ); - final items = dropdown.items ?? []; - final nonNullItem = items.firstWhere((item) => item.value != null); - final value = nonNullItem.value; - final isEnumLike = value is Enum || _hasToNativeValue(value); - - expect(isEnumLike, isTrue); - }); - - testWidgets('test_setting_tile_mobile_layout', (tester) async { - await tester.pumpWidget(createWidget(size: const Size(375, 812))); - await tester.pumpAndSettle(); - - await tester.tap(find.byIcon(Icons.more_vert)); - await tester.pumpAndSettle(); - - await tester.tap(find.text('Expand All')); - await tester.pumpAndSettle(); - - final tileFinder = find.byType(ResponsiveSettingTile); - expect(tileFinder, findsWidgets); - - final mobileLayoutFinder = find.descendant( - of: tileFinder.first, - matching: find.byKey( - const ValueKey('responsive_setting_tile_mobile_layout'), - ), - ); - final inlineLayoutFinder = find.descendant( - of: tileFinder.first, - matching: find.byKey( - const ValueKey('responsive_setting_tile_inline_control'), - ), - ); - - expect( - mobileLayoutFinder.evaluate().isNotEmpty || - inlineLayoutFinder.evaluate().isNotEmpty, - isTrue, - ); - }); - - testWidgets('test_settings_bottom_bar_wraps', (tester) async { - await tester.pumpWidget(createWidget(size: const Size(375, 812))); - await tester.pumpAndSettle(); - - final actionsFinder = find.byKey( - const ValueKey('settings_bottom_bar_actions'), - ); - expect(actionsFinder, findsOneWidget); - - final actionsWidget = tester.widget(actionsFinder); - expect(actionsWidget, isA()); - }); - }); -} - -bool _hasToNativeValue(dynamic value) { - try { - // Only care that the method exists and is callable. - (value as dynamic).toNativeValue(); - return true; - } catch (_) { - return false; - } -} diff --git a/flutter_inappwebview/example/test/screens/test_configuration_screen_test.dart b/flutter_inappwebview/example/test/screens/test_configuration_screen_test.dart deleted file mode 100644 index 6dee7f8a8f..0000000000 --- a/flutter_inappwebview/example/test/screens/test_configuration_screen_test.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/models/test_configuration.dart'; -import 'package:flutter_inappwebview_example/screens/test_automation/test_configuration_screen.dart'; - -void main() { - group('TestConfigurationScreen', () { - Widget createWidget() { - return ChangeNotifierProvider( - create: (_) => TestConfigurationManager(), - child: const MaterialApp(home: TestConfigurationScreen()), - ); - } - - testWidgets('renders app bar and tabs', (tester) async { - await tester.pumpWidget(createWidget()); - - expect(find.byType(AppBar), findsOneWidget); - expect(find.text('Test Configuration'), findsOneWidget); - expect(find.text('Custom Steps'), findsOneWidget); - expect(find.text('Settings'), findsOneWidget); - expect(find.text('Import/Export'), findsOneWidget); - }); - }); -} diff --git a/flutter_inappwebview/example/test/screens/test_runner_screen_test.dart b/flutter_inappwebview/example/test/screens/test_runner_screen_test.dart deleted file mode 100644 index 8228b3a6d3..0000000000 --- a/flutter_inappwebview/example/test/screens/test_runner_screen_test.dart +++ /dev/null @@ -1,72 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:provider/provider.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -import 'package:flutter_inappwebview_example/models/test_configuration.dart'; -import 'package:flutter_inappwebview_example/providers/test_runner.dart'; -import 'package:flutter_inappwebview_example/screens/test_automation/test_runner_screen.dart'; - -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - - group('TestRunnerScreen', () { - Future pumpScreen( - WidgetTester tester, { - required double width, - }) async { - final now = DateTime(2024, 1, 1); - final config = TestConfiguration( - id: 'mobile_config', - name: 'Mobile Config', - createdAt: now, - modifiedAt: now, - webViewType: TestWebViewType.headless, - customSteps: const [], - ); - - SharedPreferences.setMockInitialValues({ - 'test_runner_last_config': config.toJsonString(), - 'test_runner_last_webview_type': TestWebViewType.headless.name, - 'test_saved_configs': [], - 'test_current_config': config.toJsonString(), - }); - - await tester.binding.setSurfaceSize(Size(width, 800)); - addTearDown(() async { - await tester.binding.setSurfaceSize(null); - }); - - await tester.pumpWidget( - MultiProvider( - providers: [ - ChangeNotifierProvider(create: (_) => TestRunner()), - ChangeNotifierProvider(create: (_) => TestConfigurationManager()), - ], - child: MaterialApp(home: const TestRunnerScreen()), - ), - ); - - await tester.pumpAndSettle(); - } - - testWidgets('test_test_runner_stacks_on_mobile', (tester) async { - await pumpScreen(tester, width: 500); - - final panels = find.byKey(const ValueKey('testRunnerPanels')); - expect(panels, findsOneWidget); - final flex = tester.widget(panels); - expect(flex.direction, Axis.vertical); - }); - - testWidgets('test_control_bar_wraps_on_mobile', (tester) async { - await pumpScreen(tester, width: 500); - - final wrapFinder = find.byKey(const ValueKey('testRunnerControlBarWrap')); - expect(wrapFinder, findsOneWidget); - final wrapWidget = tester.widget(wrapFinder); - expect(wrapWidget.spacing, 8); - expect(wrapWidget.runSpacing, 8); - }); - }); -} diff --git a/flutter_inappwebview/example/test/screens/webview_environment_settings_editor_screen_test.dart b/flutter_inappwebview/example/test/screens/webview_environment_settings_editor_screen_test.dart deleted file mode 100644 index f9e216a718..0000000000 --- a/flutter_inappwebview/example/test/screens/webview_environment_settings_editor_screen_test.dart +++ /dev/null @@ -1,64 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:flutter_inappwebview_example/screens/webview_environment_settings_editor_screen.dart'; -import 'package:flutter_inappwebview_example/models/environment_setting_definition.dart'; - -import '../test_helpers/mock_inappwebview_platform.dart'; -import '../test_helpers/test_provider_wrapper.dart'; - -void main() { - setUpAll(() { - MockInAppWebViewPlatform.initialize(); - }); - - setUp(() { - SharedPreferences.setMockInitialValues({}); - }); - - group('WebViewEnvironmentSettingsEditorScreen', () { - Widget createWidget() { - return const MaterialApp( - home: TestProviderWrapper( - child: WebViewEnvironmentSettingsEditorScreen(), - ), - ); - } - - testWidgets('renders app bar title', (tester) async { - debugDefaultTargetPlatformOverride = TargetPlatform.windows; - try { - await tester.pumpWidget(createWidget()); - } finally { - debugDefaultTargetPlatformOverride = null; - } - - expect(find.byType(AppBar), findsOneWidget); - expect(find.text('Environment Settings'), findsOneWidget); - }); - - testWidgets('renders release channels as multi-select chips', ( - tester, - ) async { - debugDefaultTargetPlatformOverride = TargetPlatform.windows; - try { - await tester.pumpWidget(createWidget()); - await tester.pumpAndSettle(); - } finally { - debugDefaultTargetPlatformOverride = null; - } - - await tester.ensureVisible(find.text('Release Channel')); - await tester.tap(find.text('Release Channel')); - await tester.pumpAndSettle(); - - final stableLabel = EnvironmentSettingDefinition.enumDisplayName( - EnvironmentReleaseChannels.STABLE, - ); - - expect(find.widgetWithText(FilterChip, stableLabel), findsOneWidget); - }); - }); -} diff --git a/flutter_inappwebview/example/test/screens/webview_tester_screen_test.dart b/flutter_inappwebview/example/test/screens/webview_tester_screen_test.dart deleted file mode 100644 index 2e61960712..0000000000 --- a/flutter_inappwebview/example/test/screens/webview_tester_screen_test.dart +++ /dev/null @@ -1,212 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/models/event_log_entry.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/providers/network_monitor.dart'; -import 'package:flutter_inappwebview_example/screens/webview_tester_screen.dart'; -import 'package:flutter_inappwebview_example/widgets/webview/event_console_widget.dart'; - -import '../test_helpers/mock_inappwebview_platform.dart'; -import '../test_helpers/test_provider_wrapper.dart'; - -void main() { - setUpAll(() { - MockInAppWebViewPlatform.initialize(); - }); - - group('WebViewTesterScreen', () { - late EventLogProvider eventLogProvider; - late NetworkMonitor networkMonitor; - late MockSettingsManager settingsManager; - - setUp(() { - eventLogProvider = EventLogProvider(); - networkMonitor = NetworkMonitor(); - settingsManager = MockSettingsManager(); - }); - - Widget createWidget() { - return MaterialApp( - home: TestProviderWrapper( - settingsManager: settingsManager, - eventLogProvider: eventLogProvider, - networkMonitor: networkMonitor, - child: WebViewTesterScreen(), - ), - ); - } - - testWidgets('renders app bar with title', (tester) async { - await tester.pumpWidget(createWidget()); - - expect(find.text('WebView Tester'), findsOneWidget); - expect(find.byType(AppBar), findsOneWidget); - }); - - testWidgets('renders URL input field', (tester) async { - await tester.pumpWidget(createWidget()); - - expect(find.byType(TextField), findsAtLeastNWidgets(1)); - expect(find.text('Enter URL'), findsOneWidget); - }); - - testWidgets('renders navigation controls', (tester) async { - await tester.pumpWidget(createWidget()); - - expect(find.byTooltip('Back'), findsOneWidget); - expect(find.byTooltip('Forward'), findsOneWidget); - expect(find.byTooltip('Reload'), findsOneWidget); - expect(find.byTooltip('Stop'), findsOneWidget); - }); - - testWidgets('renders Go button', (tester) async { - await tester.pumpWidget(createWidget()); - - expect(find.byTooltip('Go'), findsOneWidget); - }); - - testWidgets('shows clear events button in app bar', (tester) async { - await tester.pumpWidget(createWidget()); - - expect(find.byTooltip('Clear Events'), findsOneWidget); - }); - - testWidgets('clear button clears events', (tester) async { - eventLogProvider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Test event', - ), - ); - - await tester.pumpWidget(createWidget()); - - expect(eventLogProvider.events.length, 1); - - await tester.tap(find.byTooltip('Clear Events')); - await tester.pump(); - - expect(eventLogProvider.events.length, 0); - }); - - testWidgets('renders bottom tabs', (tester) async { - await tester.pumpWidget(createWidget()); - await tester.pump(); - - // Open bottom sheet by tapping tab bar - await tester.tap(find.widgetWithText(Tab, 'Events')); - await tester.pump(const Duration(milliseconds: 300)); - - expect(find.text('Events'), findsWidgets); - expect(find.text('Network'), findsOneWidget); - expect(find.text('Methods'), findsOneWidget); - expect(find.text('JavaScript'), findsOneWidget); - expect(find.text('UserScripts'), findsOneWidget); - }); - - testWidgets('URL field updates when text entered', (tester) async { - await tester.pumpWidget(createWidget()); - - final urlField = find.ancestor( - of: find.text('Enter URL'), - matching: find.byType(TextField), - ); - - await tester.enterText(urlField, 'https://example.com'); - await tester.pump(); - - expect(find.text('https://example.com'), findsOneWidget); - }); - - testWidgets('navigation buttons initially disabled', (tester) async { - await tester.pumpWidget(createWidget()); - - final backButton = tester.widget( - find.ancestor( - of: find.byTooltip('Back'), - matching: find.byType(IconButton), - ), - ); - final forwardButton = tester.widget( - find.ancestor( - of: find.byTooltip('Forward'), - matching: find.byType(IconButton), - ), - ); - - expect(backButton.onPressed, isNull); - expect(forwardButton.onPressed, isNull); - }); - - testWidgets('shows progress indicator during page load', (tester) async { - await tester.pumpWidget(createWidget()); - await tester.pump(); - - // Note: This test assumes InAppWebView would show a progress indicator - // The actual implementation would need to track loading state - }); - - testWidgets('switching tabs changes visible content', (tester) async { - await tester.pumpWidget(createWidget()); - await tester.pump(); - - await tester.ensureVisible(find.widgetWithText(Tab, 'Events')); - await tester.tap(find.widgetWithText(Tab, 'Events')); - await tester.pump(const Duration(milliseconds: 400)); - - expect(find.byType(EventConsoleWidget), findsOneWidget); - - // Switch to Network tab - await tester.ensureVisible(find.widgetWithText(Tab, 'Network')); - await tester.tap(find.widgetWithText(Tab, 'Network')); - await tester.pump(const Duration(milliseconds: 400)); - - final tabBar = tester.widget(find.byType(TabBar)); - expect(tabBar.controller?.index, 1); - }); - - testWidgets('does not overflow on small height', (tester) async { - tester.binding.window.physicalSizeTestValue = const Size(320, 280); - tester.binding.window.devicePixelRatioTestValue = 1.0; - addTearDown(() { - tester.binding.window.clearPhysicalSizeTestValue(); - tester.binding.window.clearDevicePixelRatioTestValue(); - }); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(tester.takeException(), isNull); - }); - - testWidgets('test_webview_tester_mobile_layout', (tester) async { - tester.binding.window.physicalSizeTestValue = const Size(360, 640); - tester.binding.window.devicePixelRatioTestValue = 1.0; - addTearDown(() { - tester.binding.window.clearPhysicalSizeTestValue(); - tester.binding.window.clearDevicePixelRatioTestValue(); - }); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(tester.takeException(), isNull); - }); - - testWidgets('test_tabbar_is_scrollable_on_mobile', (tester) async { - tester.binding.window.physicalSizeTestValue = const Size(360, 700); - tester.binding.window.devicePixelRatioTestValue = 1.0; - addTearDown(() { - tester.binding.window.clearPhysicalSizeTestValue(); - tester.binding.window.clearDevicePixelRatioTestValue(); - }); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - final tabBar = tester.widget(find.byType(TabBar)); - expect(tabBar.isScrollable, isTrue); - }); - }); -} diff --git a/flutter_inappwebview/example/test/test_helpers/mock_inappwebview_platform.dart b/flutter_inappwebview/example/test/test_helpers/mock_inappwebview_platform.dart deleted file mode 100644 index abb70f6d80..0000000000 --- a/flutter_inappwebview/example/test/test_helpers/mock_inappwebview_platform.dart +++ /dev/null @@ -1,945 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; - -/// A mock InAppWebViewPlatform for testing purposes. -/// This allows widget tests to run without requiring a real platform implementation. -class MockInAppWebViewPlatform extends InAppWebViewPlatform - with MockPlatformInterfaceMixin { - static final MockInAppWebViewPlatform _instance = - MockInAppWebViewPlatform._(); - - MockInAppWebViewPlatform._(); - - /// Initialize the mock platform for testing. - /// Call this in setUp() or at the start of your tests. - static void initialize() { - InAppWebViewPlatform.instance = _instance; - } - - /// Reset the platform instance. - /// Call this in tearDown() to clean up after tests. - static void reset() { - // Note: We can't actually set instance to null, but we can leave it as the mock - // for subsequent tests. The mock is stateless so this is fine. - } - - @override - PlatformInAppWebViewController createPlatformInAppWebViewControllerStatic() { - return MockPlatformInAppWebViewControllerStatic( - const PlatformInAppWebViewControllerCreationParams(id: 'mock_controller'), - ); - } - - @override - PlatformCookieManager createPlatformCookieManagerStatic() { - return MockPlatformCookieManagerStatic( - PlatformCookieManagerCreationParams(), - ); - } - - @override - PlatformCookieManager createPlatformCookieManager( - PlatformCookieManagerCreationParams params, - ) { - return MockPlatformCookieManager(params); - } - - @override - PlatformInAppWebViewWidget createPlatformInAppWebViewWidget( - PlatformInAppWebViewWidgetCreationParams params, - ) { - return MockPlatformInAppWebViewWidget(params); - } - - @override - PlatformInAppWebViewWidget createPlatformInAppWebViewWidgetStatic() { - return MockPlatformInAppWebViewWidget( - PlatformInAppWebViewWidgetCreationParams(), - ); - } - - @override - PlatformInAppWebViewController createPlatformInAppWebViewController( - PlatformInAppWebViewControllerCreationParams params, - ) { - return MockPlatformInAppWebViewController(params); - } - - @override - PlatformServiceWorkerController createPlatformServiceWorkerController( - PlatformServiceWorkerControllerCreationParams params, - ) { - return MockPlatformServiceWorkerController(params); - } - - @override - PlatformServiceWorkerController - createPlatformServiceWorkerControllerStatic() { - return MockPlatformServiceWorkerController( - const PlatformServiceWorkerControllerCreationParams(), - ); - } - - @override - PlatformProxyController createPlatformProxyController( - PlatformProxyControllerCreationParams params, - ) { - return MockPlatformProxyController(params); - } - - @override - PlatformProxyController createPlatformProxyControllerStatic() { - return MockPlatformProxyController( - const PlatformProxyControllerCreationParams(), - ); - } - - @override - PlatformTracingController createPlatformTracingController( - PlatformTracingControllerCreationParams params, - ) { - return MockPlatformTracingController(params); - } - - @override - PlatformTracingController createPlatformTracingControllerStatic() { - return MockPlatformTracingController( - const PlatformTracingControllerCreationParams(), - ); - } - - @override - PlatformWebViewEnvironment createPlatformWebViewEnvironment( - PlatformWebViewEnvironmentCreationParams params, - ) { - return MockPlatformWebViewEnvironment(params); - } - - @override - PlatformWebViewEnvironment createPlatformWebViewEnvironmentStatic() { - return MockPlatformWebViewEnvironment( - const PlatformWebViewEnvironmentCreationParams(), - ); - } - - @override - PlatformProcessGlobalConfig createPlatformProcessGlobalConfig( - PlatformProcessGlobalConfigCreationParams params, - ) { - return MockPlatformProcessGlobalConfig(params); - } - - @override - PlatformProcessGlobalConfig createPlatformProcessGlobalConfigStatic() { - return MockPlatformProcessGlobalConfig( - const PlatformProcessGlobalConfigCreationParams(), - ); - } - - @override - PlatformFindInteractionController createPlatformFindInteractionController( - PlatformFindInteractionControllerCreationParams params, - ) { - return MockPlatformFindInteractionController(params); - } - - @override - PlatformFindInteractionController - createPlatformFindInteractionControllerStatic() { - return MockPlatformFindInteractionController( - const PlatformFindInteractionControllerCreationParams(), - ); - } - - @override - PlatformPullToRefreshController createPlatformPullToRefreshController( - PlatformPullToRefreshControllerCreationParams params, - ) { - return MockPlatformPullToRefreshController(params); - } - - @override - PlatformPullToRefreshController - createPlatformPullToRefreshControllerStatic() { - return MockPlatformPullToRefreshController( - PlatformPullToRefreshControllerCreationParams(), - ); - } - - @override - PlatformWebMessageChannel createPlatformWebMessageChannel( - PlatformWebMessageChannelCreationParams params, - ) { - return MockPlatformWebMessageChannel(params); - } - - @override - PlatformWebMessageChannel createPlatformWebMessageChannelStatic() { - final port1 = MockPlatformWebMessagePort( - const PlatformWebMessagePortCreationParams(index: 0), - ); - final port2 = MockPlatformWebMessagePort( - const PlatformWebMessagePortCreationParams(index: 1), - ); - return MockPlatformWebMessageChannel( - PlatformWebMessageChannelCreationParams( - id: 'mock_channel', - port1: port1, - port2: port2, - ), - ); - } - - @override - PlatformHeadlessInAppWebView createPlatformHeadlessInAppWebView( - PlatformHeadlessInAppWebViewCreationParams params, - ) { - return MockPlatformHeadlessInAppWebView(params); - } - - @override - PlatformHeadlessInAppWebView createPlatformHeadlessInAppWebViewStatic() { - return MockPlatformHeadlessInAppWebView( - const PlatformHeadlessInAppWebViewCreationParams(), - ); - } - - @override - PlatformInAppBrowser createPlatformInAppBrowser( - PlatformInAppBrowserCreationParams params, - ) { - return MockPlatformInAppBrowser(params); - } - - @override - PlatformInAppBrowser createPlatformInAppBrowserStatic() { - return MockPlatformInAppBrowser(const PlatformInAppBrowserCreationParams()); - } - - @override - PlatformChromeSafariBrowser createPlatformChromeSafariBrowser( - PlatformChromeSafariBrowserCreationParams params, - ) { - return MockPlatformChromeSafariBrowser(params); - } - - @override - PlatformChromeSafariBrowser createPlatformChromeSafariBrowserStatic() { - return MockPlatformChromeSafariBrowser( - const PlatformChromeSafariBrowserCreationParams(), - ); - } - - @override - PlatformPrintJobController createPlatformPrintJobController( - PlatformPrintJobControllerCreationParams params, - ) { - return MockPlatformPrintJobController(params); - } - - @override - PlatformPrintJobController createPlatformPrintJobControllerStatic() { - return MockPlatformPrintJobController( - const PlatformPrintJobControllerCreationParams(id: 'mock_print_job'), - ); - } - - @override - PlatformWebAuthenticationSession createPlatformWebAuthenticationSession( - PlatformWebAuthenticationSessionCreationParams params, - ) { - return MockPlatformWebAuthenticationSession(params); - } - - @override - PlatformWebAuthenticationSession - createPlatformWebAuthenticationSessionStatic() { - return MockPlatformWebAuthenticationSession( - const PlatformWebAuthenticationSessionCreationParams(), - ); - } - - @override - PlatformHttpAuthCredentialDatabase createPlatformHttpAuthCredentialDatabase( - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) { - return MockPlatformHttpAuthCredentialDatabase(params); - } - - @override - PlatformHttpAuthCredentialDatabase - createPlatformHttpAuthCredentialDatabaseStatic() { - return MockPlatformHttpAuthCredentialDatabase( - const PlatformHttpAuthCredentialDatabaseCreationParams(), - ); - } - - @override - PlatformWebStorage createPlatformWebStorage( - PlatformWebStorageCreationParams params, - ) { - return MockPlatformWebStorage(params); - } - - @override - PlatformWebStorage createPlatformWebStorageStatic() { - final localStorage = MockPlatformLocalStorage( - PlatformLocalStorageCreationParams( - const PlatformStorageCreationParams( - controller: null, - webStorageType: WebStorageType.LOCAL_STORAGE, - ), - ), - ); - final sessionStorage = MockPlatformSessionStorage( - PlatformSessionStorageCreationParams( - const PlatformStorageCreationParams( - controller: null, - webStorageType: WebStorageType.SESSION_STORAGE, - ), - ), - ); - return MockPlatformWebStorage( - PlatformWebStorageCreationParams( - localStorage: localStorage, - sessionStorage: sessionStorage, - ), - ); - } - - @override - PlatformLocalStorage createPlatformLocalStorage( - PlatformLocalStorageCreationParams params, - ) { - return MockPlatformLocalStorage(params); - } - - @override - PlatformLocalStorage createPlatformLocalStorageStatic() { - return MockPlatformLocalStorage( - PlatformLocalStorageCreationParams( - const PlatformStorageCreationParams( - controller: null, - webStorageType: WebStorageType.LOCAL_STORAGE, - ), - ), - ); - } - - @override - PlatformSessionStorage createPlatformSessionStorage( - PlatformSessionStorageCreationParams params, - ) { - return MockPlatformSessionStorage(params); - } - - @override - PlatformSessionStorage createPlatformSessionStorageStatic() { - return MockPlatformSessionStorage( - PlatformSessionStorageCreationParams( - const PlatformStorageCreationParams( - controller: null, - webStorageType: WebStorageType.SESSION_STORAGE, - ), - ), - ); - } -} - -/// Mock static controller for testing -class MockPlatformInAppWebViewControllerStatic - extends PlatformInAppWebViewController - with MockPlatformInterfaceMixin { - MockPlatformInAppWebViewControllerStatic(super.params) - : super.implementation(); - - @override - bool isMethodSupported( - PlatformInAppWebViewControllerMethod method, { - TargetPlatform? platform, - }) { - // Return true for all methods in tests - return true; - } -} - -class MockPlatformInAppWebViewController extends PlatformInAppWebViewController - with MockPlatformInterfaceMixin { - MockPlatformInAppWebViewController(super.params) : super.implementation(); - - @override - bool isMethodSupported( - PlatformInAppWebViewControllerMethod method, { - TargetPlatform? platform, - }) => true; - - @override - Future loadUrl({ - required URLRequest urlRequest, - @Deprecated('Use allowingReadAccessTo instead') - Uri? iosAllowingReadAccessTo, - WebUri? allowingReadAccessTo, - }) async {} - - @override - Future reload() async {} - - @override - Future stopLoading() async {} - - @override - Future canGoBack() async => false; - - @override - Future canGoForward() async => false; - - @override - Future goBack() async {} - - @override - Future goForward() async {} - - @override - Future getTitle() async => 'Mock Title'; - - @override - int? getViewId() => 1; - - @override - Future evaluateJavascript({ - required String source, - ContentWorld? contentWorld, - }) async => null; - - @override - Future callAsyncJavaScript({ - required String functionBody, - Map? arguments, - ContentWorld? contentWorld, - }) async => null; - - @override - Future addUserScript({required UserScript userScript}) async {} - - @override - Future removeUserScript({required UserScript userScript}) async => true; - - @override - Future createWebMessageChannel() async { - final port1 = MockPlatformWebMessagePort( - const PlatformWebMessagePortCreationParams(index: 0), - ); - final port2 = MockPlatformWebMessagePort( - const PlatformWebMessagePortCreationParams(index: 1), - ); - return MockPlatformWebMessageChannel( - PlatformWebMessageChannelCreationParams( - id: 'controller_channel', - port1: port1, - port2: port2, - ), - ); - } -} - -class MockPlatformInAppWebViewWidget extends PlatformInAppWebViewWidget - with MockPlatformInterfaceMixin { - MockPlatformInAppWebViewWidget(super.params) : super.implementation(); - - @override - T controllerFromPlatform(PlatformInAppWebViewController controller) { - return controller as T; - } - - @override - void dispose() {} - - @override - Widget build(BuildContext context) { - return const SizedBox.shrink(); - } -} - -/// Mock static cookie manager for testing -class MockPlatformCookieManagerStatic extends PlatformCookieManager - with MockPlatformInterfaceMixin { - MockPlatformCookieManagerStatic(super.params) : super.implementation(); - - @override - bool isMethodSupported( - PlatformCookieManagerMethod method, { - TargetPlatform? platform, - }) { - return true; - } -} - -class MockPlatformCookieManager extends PlatformCookieManager - with MockPlatformInterfaceMixin { - MockPlatformCookieManager(super.params) : super.implementation(); - - @override - bool isMethodSupported( - PlatformCookieManagerMethod method, { - TargetPlatform? platform, - }) => true; -} - -class MockPlatformServiceWorkerController - extends PlatformServiceWorkerController - with MockPlatformInterfaceMixin { - MockPlatformServiceWorkerController(super.params) : super.implementation(); - - @override - bool isMethodSupported( - PlatformServiceWorkerControllerMethod method, { - TargetPlatform? platform, - }) => true; - - @override - Future getAllowContentAccess() async => true; - - @override - Future getAllowFileAccess() async => true; - - @override - Future getBlockNetworkLoads() async => false; - - @override - Future getCacheMode() async => CacheMode.LOAD_DEFAULT; - - @override - Future setAllowContentAccess(bool value) async {} - - @override - Future setAllowFileAccess(bool value) async {} - - @override - Future setBlockNetworkLoads(bool value) async {} - - @override - Future setCacheMode(CacheMode? mode) async {} - - @override - ServiceWorkerClient? get serviceWorkerClient => null; -} - -class MockPlatformProxyController extends PlatformProxyController - with MockPlatformInterfaceMixin { - MockPlatformProxyController(super.params) : super.implementation(); - - @override - bool isMethodSupported( - PlatformProxyControllerMethod method, { - TargetPlatform? platform, - }) => true; - - @override - Future setProxyOverride({required ProxySettings settings}) async {} - - @override - Future clearProxyOverride() async {} -} - -class MockPlatformTracingController extends PlatformTracingController - with MockPlatformInterfaceMixin { - MockPlatformTracingController(super.params) : super.implementation(); - - @override - bool isMethodSupported( - PlatformTracingControllerMethod method, { - TargetPlatform? platform, - }) => true; - - @override - Future start({required TracingSettings settings}) async {} - - @override - Future stop({String? filePath}) async => true; -} - -class MockPlatformWebViewEnvironment extends PlatformWebViewEnvironment - with MockPlatformInterfaceMixin { - MockPlatformWebViewEnvironment(super.params) : super.implementation(); - - @override - bool isMethodSupported( - PlatformWebViewEnvironmentMethod method, { - TargetPlatform? platform, - }) => true; - - @override - Future getAvailableVersion({ - String? browserExecutableFolder, - }) async => null; - - @override - Future> getBrowserProcessInfo() async => []; -} - -class MockPlatformProcessGlobalConfig extends PlatformProcessGlobalConfig - with MockPlatformInterfaceMixin { - MockPlatformProcessGlobalConfig(super.params) : super.implementation(); - - @override - bool isMethodSupported( - PlatformProcessGlobalConfigMethod method, { - TargetPlatform? platform, - }) => true; - - @override - Future setDataDirectorySuffix({required String suffix}) async {} -} - -class MockPlatformFindInteractionController - extends PlatformFindInteractionController - with MockPlatformInterfaceMixin { - MockPlatformFindInteractionController(super.params) : super.implementation(); - - @override - bool isMethodSupported( - PlatformFindInteractionControllerMethod method, { - TargetPlatform? platform, - }) => true; - - @override - Future findAll({String? find}) async {} - - @override - Future findNext({bool forward = true}) async {} - - @override - Future clearMatches() async {} - - @override - Future setSearchText(String? searchText) async {} - - @override - Future getSearchText() async => ''; - - @override - Future presentFindNavigator() async {} - - @override - Future dismissFindNavigator() async {} - - @override - Future isFindNavigatorVisible() async => false; - - @override - Future getActiveFindSession() async => null; - - @override - void dispose({bool isKeepAlive = false}) {} -} - -class MockPlatformPullToRefreshController - extends PlatformPullToRefreshController - with MockPlatformInterfaceMixin { - bool _enabled = true; - - MockPlatformPullToRefreshController(super.params) : super.implementation(); - - @override - bool isMethodSupported( - PlatformPullToRefreshControllerMethod method, { - TargetPlatform? platform, - }) => true; - - @override - Future setEnabled(bool enabled) async { - _enabled = enabled; - } - - @override - Future isEnabled() async => _enabled; - - @override - Future beginRefreshing() async {} - - @override - Future endRefreshing() async {} - - @override - Future isRefreshing() async => false; - - @override - Future setColor(Color color) async {} - - @override - Future setBackgroundColor(Color color) async {} - - @override - Future getDefaultSlingshotDistance() async => 0; - - @override - void dispose({bool isKeepAlive = false}) {} -} - -class MockPlatformWebMessageChannel extends PlatformWebMessageChannel - with MockPlatformInterfaceMixin { - MockPlatformWebMessageChannel(super.params) : super.implementation(); - - @override - PlatformWebMessagePort get port1 => params.port1; - - @override - PlatformWebMessagePort get port2 => params.port2; - - @override - Future dispose() async {} -} - -class MockPlatformWebMessagePort extends PlatformWebMessagePort - with MockPlatformInterfaceMixin { - MockPlatformWebMessagePort(super.params) : super.implementation(); - - @override - Future setWebMessageCallback(WebMessageCallback? onMessage) async {} - - @override - Future postMessage(WebMessage message) async {} - - @override - Future close() async {} - - @override - Map toMap({EnumMethod? enumMethod}) => {}; - - @override - Map toJson() => toMap(); -} - -class MockPlatformHeadlessInAppWebView extends PlatformHeadlessInAppWebView - with MockPlatformInterfaceMixin { - MockPlatformHeadlessInAppWebView(super.params) : super.implementation(); - - @override - String get id => 'mock_headless'; - - @override - PlatformInAppWebViewController? get webViewController => - MockPlatformInAppWebViewController( - const PlatformInAppWebViewControllerCreationParams( - id: 'mock_headless_controller', - ), - ); - - @override - Future run() async {} - - @override - bool isRunning() => false; - - @override - Future setSize(Size size) async {} - - @override - Future getSize() async => null; - - @override - Future dispose() async {} -} - -class MockPlatformInAppBrowser extends PlatformInAppBrowser - with MockPlatformInterfaceMixin { - MockPlatformInAppBrowser(super.params) : super.implementation(); - - @override - String get id => 'mock_inapp_browser'; - - @override - PlatformInAppWebViewController? get webViewController => - MockPlatformInAppWebViewController( - const PlatformInAppWebViewControllerCreationParams( - id: 'mock_inapp_browser_controller', - ), - ); - - @override - Future openUrlRequest({ - required URLRequest urlRequest, - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) async {} - - @override - Future openFile({ - required String assetFilePath, - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) async {} - - @override - Future openData({ - required String data, - String mimeType = 'text/html', - String encoding = 'utf8', - WebUri? baseUrl, - @Deprecated('Use historyUrl instead') Uri? androidHistoryUrl, - WebUri? historyUrl, - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) async {} - - @override - Future show() async {} - - @override - Future hide() async {} - - @override - Future close() async {} - - @override - Future isHidden() async => false; - - @override - Future setSettings({ - required InAppBrowserClassSettings settings, - }) async {} - - @override - Future getSettings() async => - InAppBrowserClassSettings(); - - @override - bool isOpened() => true; - - @override - void dispose() { - super.dispose(); - } -} - -class MockPlatformChromeSafariBrowser extends PlatformChromeSafariBrowser - with MockPlatformInterfaceMixin { - MockPlatformChromeSafariBrowser(super.params) : super.implementation(); - - @override - String get id => 'mock_chrome_safari_browser'; - - @override - Future open({ - WebUri? url, - Map? headers, - List? otherLikelyURLs, - WebUri? referrer, - @Deprecated('Use settings instead') - ChromeSafariBrowserClassOptions? options, - ChromeSafariBrowserSettings? settings, - }) async {} - - @override - Future launchUrl({ - required WebUri url, - Map? headers, - List? otherLikelyURLs, - WebUri? referrer, - }) async {} - - @override - Future mayLaunchUrl({ - WebUri? url, - List? otherLikelyURLs, - }) async => true; - - @override - Future validateRelationship({ - required CustomTabsRelationType relation, - required WebUri origin, - }) async => true; - - @override - Future close() async {} - - @override - void dispose() { - eventHandler = null; - } -} - -class MockPlatformPrintJobController extends PlatformPrintJobController - with MockPlatformInterfaceMixin { - MockPlatformPrintJobController(super.params) : super.implementation(); - - @override - Future cancel() async {} - - @override - Future restart() async {} - - @override - Future dismiss({bool animated = true}) async {} - - @override - Future getInfo() async => null; - - @override - void dispose() {} -} - -class MockPlatformWebAuthenticationSession - extends PlatformWebAuthenticationSession - with MockPlatformInterfaceMixin { - MockPlatformWebAuthenticationSession(super.params) : super.implementation(); - - @override - bool isMethodSupported( - PlatformWebAuthenticationSessionMethod method, { - TargetPlatform? platform, - }) => true; -} - -class MockPlatformHttpAuthCredentialDatabase - extends PlatformHttpAuthCredentialDatabase - with MockPlatformInterfaceMixin { - MockPlatformHttpAuthCredentialDatabase(super.params) : super.implementation(); - - @override - bool isMethodSupported( - PlatformHttpAuthCredentialDatabaseMethod method, { - TargetPlatform? platform, - }) => true; -} - -class MockPlatformWebStorage extends PlatformWebStorage - with MockPlatformInterfaceMixin { - MockPlatformWebStorage(super.params) : super.implementation(); - - @override - PlatformLocalStorage get localStorage => params.localStorage; - - @override - PlatformSessionStorage get sessionStorage => params.sessionStorage; -} - -class MockPlatformLocalStorage extends PlatformLocalStorage - with MockPlatformInterfaceMixin { - MockPlatformLocalStorage(super.params) : super.implementation(); - - @override - PlatformInAppWebViewController? get controller => params.controller; - - @override - bool isMethodSupported( - PlatformLocalStorageMethod method, { - TargetPlatform? platform, - }) => true; -} - -class MockPlatformSessionStorage extends PlatformSessionStorage - with MockPlatformInterfaceMixin { - MockPlatformSessionStorage(super.params) : super.implementation(); - - @override - PlatformInAppWebViewController? get controller => params.controller; - - @override - bool isMethodSupported( - PlatformSessionStorageMethod method, { - TargetPlatform? platform, - }) => true; -} diff --git a/flutter_inappwebview/example/test/test_helpers/test_provider_wrapper.dart b/flutter_inappwebview/example/test/test_helpers/test_provider_wrapper.dart deleted file mode 100644 index b1d34081e0..0000000000 --- a/flutter_inappwebview/example/test/test_helpers/test_provider_wrapper.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/providers/network_monitor.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; - -import 'mock_inappwebview_platform.dart'; - -/// Creates a mock SettingsManager for testing. -/// This bypasses the SharedPreferences and WebViewEnvironment dependencies. -class MockSettingsManager extends SettingsManager { - MockSettingsManager() - : super( - environmentFactory: (_) async => null, - environmentSupportChecker: () => false, - ); - - @override - WebViewEnvironmentSettings buildEnvironmentSettings() => - WebViewEnvironmentSettings( - releaseChannels: EnvironmentReleaseChannels.STABLE, - ); - - @override - InAppWebViewSettings buildSettings() => InAppWebViewSettings(); -} - -/// A wrapper widget that provides all common providers needed for testing. -class TestProviderWrapper extends StatelessWidget { - final Widget child; - final SettingsManager? settingsManager; - final EventLogProvider? eventLogProvider; - final NetworkMonitor? networkMonitor; - - const TestProviderWrapper({ - super.key, - required this.child, - this.settingsManager, - this.eventLogProvider, - this.networkMonitor, - }); - - @override - Widget build(BuildContext context) { - return MultiProvider( - providers: [ - ChangeNotifierProvider.value( - value: settingsManager ?? MockSettingsManager(), - ), - ChangeNotifierProvider.value( - value: eventLogProvider ?? EventLogProvider(), - ), - ChangeNotifierProvider.value( - value: networkMonitor ?? NetworkMonitor(), - ), - ], - child: child, - ); - } -} - -/// Helper to set up tests that require the InAppWebViewPlatform mock. -void setUpMockPlatform() { - MockInAppWebViewPlatform.initialize(); -} diff --git a/flutter_inappwebview/example/test/test_helpers/test_settings_manager.dart b/flutter_inappwebview/example/test/test_helpers/test_settings_manager.dart deleted file mode 100644 index 8b616e79c7..0000000000 --- a/flutter_inappwebview/example/test/test_helpers/test_settings_manager.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; - -/// Lightweight settings manager for widget tests. -class TestSettingsManager extends SettingsManager { - TestSettingsManager() - : super( - environmentFactory: (_) async => null, - environmentSupportChecker: () => false, - ); - - @override - Future init() async {} - - @override - InAppWebViewSettings buildSettings() => InAppWebViewSettings(); - - @override - WebViewEnvironmentSettings buildEnvironmentSettings() => - WebViewEnvironmentSettings( - releaseChannels: EnvironmentReleaseChannels.STABLE, - ); - - @override - WebViewEnvironment? get webViewEnvironment => null; - - @override - int get environmentRevision => 0; - - @override - int get settingsRevision => 0; -} diff --git a/flutter_inappwebview/example/test/utils/controller_methods_registry_test.dart b/flutter_inappwebview/example/test/utils/controller_methods_registry_test.dart deleted file mode 100644 index 48be9f8d32..0000000000 --- a/flutter_inappwebview/example/test/utils/controller_methods_registry_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/utils/controller_methods_registry.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; - -void main() { - group('controller_methods_registry helpers', () { - test('extractParam unwraps hinted values', () { - const hint = ParameterValueHint(7, ParameterValueType.number); - - expect(extractParam(hint), 7); - expect(extractParam('value'), 'value'); - expect(extractParam('value'), isNull); - expect(extractParam(null), isNull); - }); - - test('ControllerMethodEntry.toJson serializes hint and bytes', () { - final entry = ControllerMethodEntry( - methodEnum: PlatformInAppWebViewControllerMethod.loadUrl, - description: 'test', - parameters: { - 'count': const ParameterValueHint(3, ParameterValueType.number), - 'bytes': Uint8List.fromList([1, 2, 3]), - }, - requiredParameters: const ['count'], - execute: (_, __) async => null, - ); - - final json = entry.toJson(); - final params = json['parameters'] as Map; - - expect(params['count'], { - '_type': 'hint', - 'valueType': ParameterValueType.number.name, - 'value': 3, - }); - expect(params['bytes'], { - '_type': 'bytes', - 'value': base64.encode([1, 2, 3]), - }); - }); - }); -} diff --git a/flutter_inappwebview/example/test/utils/parameter_dialog_utils_test.dart b/flutter_inappwebview/example/test/utils/parameter_dialog_utils_test.dart deleted file mode 100644 index 4ce4de0b1f..0000000000 --- a/flutter_inappwebview/example/test/utils/parameter_dialog_utils_test.dart +++ /dev/null @@ -1,103 +0,0 @@ -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview_example/utils/parameter_dialog_utils.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - group('ParameterDialogUtils', () { - test('deepCloneMap creates new nested copies', () { - final bytes = Uint8List.fromList([1, 2, 3]); - final original = { - 'name': 'value', - 'list': [ - 1, - 2, - {'inner': 'ok'}, - ], - 'bytes': bytes, - 'color': Colors.red, - }; - - final clone = ParameterDialogUtils.deepCloneMap(original); - - expect(clone, isNot(same(original))); - expect(clone['list'], isNot(same(original['list']))); - expect(clone['bytes'], isNot(same(original['bytes']))); - expect(clone['color'], isA()); - - (clone['list'] as List)[2]['inner'] = 'changed'; - expect(original['list'][2]['inner'], 'ok'); - }); - - test('parseNumber returns null for invalid values', () { - expect(ParameterDialogUtils.parseNumber('abc'), isNull); - expect(ParameterDialogUtils.parseNumber(''), isNull); - expect(ParameterDialogUtils.parseNumber('12.5'), 12.5); - }); - - test('parseBytes decodes base64 when prefixed', () { - final data = Uint8List.fromList([10, 20, 30]); - final encoded = base64.encode(data); - - final parsed = ParameterDialogUtils.parseBytes('base64:$encoded'); - - expect(parsed, isNotNull); - expect(parsed, data); - }); - - test('parseBytes decodes data URI base64 payloads', () { - final data = Uint8List.fromList([3, 4, 5, 6]); - final encoded = base64.encode(data); - - final parsed = ParameterDialogUtils.parseBytes( - 'data:application/octet-stream;base64,$encoded', - ); - - expect(parsed, isNotNull); - expect(parsed, data); - }); - - test('parseBytes returns null on invalid base64 input with prefix', () { - final parsed = ParameterDialogUtils.parseBytes('base64:===='); - expect(parsed, isNull); - }); - - test('parseBytes falls back to utf8 for non-base64', () { - final parsed = ParameterDialogUtils.parseBytes('hello'); - expect(parsed, Uint8List.fromList(utf8.encode('hello'))); - }); - - test('parseBytes treats base64-like text as utf8 without prefix', () { - final parsed = ParameterDialogUtils.parseBytes('dGVzdA=='); - expect(parsed, Uint8List.fromList(utf8.encode('dGVzdA=='))); - }); - - test('getValueAtPath and setValueAtPath work for nested structures', () { - final data = { - 'root': { - 'items': [ - {'value': 1}, - ], - }, - }; - - ParameterDialogUtils.setValueAtPath(data, [ - 'root', - 'items', - 0, - 'value', - ], 42); - - final result = ParameterDialogUtils.getValueAtPath(data, [ - 'root', - 'items', - 0, - 'value', - ]); - - expect(result, 42); - }); - }); -} diff --git a/flutter_inappwebview/example/test/utils/platform_utils_test.dart b/flutter_inappwebview/example/test/utils/platform_utils_test.dart deleted file mode 100644 index a974c69209..0000000000 --- a/flutter_inappwebview/example/test/utils/platform_utils_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/utils/platform_utils.dart'; - -void main() { - group('PlatformUtils', () { - test('getPlatformName returns non-empty string', () { - final platformName = PlatformUtils.getPlatformName(); - expect(platformName, isNotEmpty); - expect(platformName, isA()); - }); - - test('getFlutterVersion returns non-empty string', () { - final flutterVersion = PlatformUtils.getFlutterVersion(); - expect(flutterVersion, isNotEmpty); - expect(flutterVersion, isA()); - }); - - test('getDartVersion returns non-empty string', () { - final dartVersion = PlatformUtils.getDartVersion(); - expect(dartVersion, isNotEmpty); - expect(dartVersion, isA()); - }); - - test('isWebPlatform returns boolean', () { - final isWeb = PlatformUtils.isWebPlatform(); - expect(isWeb, isA()); - }); - - test('isMobilePlatform returns boolean', () { - final isMobile = PlatformUtils.isMobilePlatform(); - expect(isMobile, isA()); - }); - - test('isDesktopPlatform returns boolean', () { - final isDesktop = PlatformUtils.isDesktopPlatform(); - expect(isDesktop, isA()); - }); - - test('platform type methods are mutually exclusive', () { - final isWeb = PlatformUtils.isWebPlatform(); - final isMobile = PlatformUtils.isMobilePlatform(); - final isDesktop = PlatformUtils.isDesktopPlatform(); - - // At most one should be true (could be none in test environment) - final trueCount = [isWeb, isMobile, isDesktop].where((e) => e).length; - expect(trueCount, lessThanOrEqualTo(1)); - }); - - test('getPlatformIcon returns icon data', () { - final icon = PlatformUtils.getPlatformIcon(); - expect(icon, isNotNull); - }); - }); -} diff --git a/flutter_inappwebview/example/test/utils/responsive_utils_test.dart b/flutter_inappwebview/example/test/utils/responsive_utils_test.dart deleted file mode 100644 index 9fe5a1a875..0000000000 --- a/flutter_inappwebview/example/test/utils/responsive_utils_test.dart +++ /dev/null @@ -1,96 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/utils/responsive_utils.dart'; - -void main() { - group('ResponsiveBreakpoints', () { - test('test_responsive_breakpoint_detection', () { - expect(ResponsiveBreakpoints.fromWidth(599), ResponsiveBreakpoint.mobile); - expect(ResponsiveBreakpoints.fromWidth(600), ResponsiveBreakpoint.tablet); - expect(ResponsiveBreakpoints.fromWidth(900), ResponsiveBreakpoint.tablet); - expect( - ResponsiveBreakpoints.fromWidth(901), - ResponsiveBreakpoint.desktop, - ); - expect(ResponsiveBreakpoints.isMobileWidth(320), isTrue); - expect(ResponsiveBreakpoints.isTabletWidth(700), isTrue); - expect(ResponsiveBreakpoints.isDesktopWidth(1280), isTrue); - }); - }); - - group('ResponsiveBuildContext', () { - testWidgets('test_responsive_build_context_getters', (tester) async { - late bool isMobile; - late bool isTablet; - late bool isDesktop; - - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(320, 800)), - child: Builder( - builder: (context) { - isMobile = context.isMobile; - isTablet = context.isTablet; - isDesktop = context.isDesktop; - return const SizedBox.shrink(); - }, - ), - ), - ); - - expect(isMobile, isTrue); - expect(isTablet, isFalse); - expect(isDesktop, isFalse); - }); - - testWidgets('test_responsive_build_context_getters_tablet', (tester) async { - late bool isMobile; - late bool isTablet; - late bool isDesktop; - - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(700, 800)), - child: Builder( - builder: (context) { - isMobile = context.isMobile; - isTablet = context.isTablet; - isDesktop = context.isDesktop; - return const SizedBox.shrink(); - }, - ), - ), - ); - - expect(isMobile, isFalse); - expect(isTablet, isTrue); - expect(isDesktop, isFalse); - }); - - testWidgets('test_responsive_build_context_getters_desktop', ( - tester, - ) async { - late bool isMobile; - late bool isTablet; - late bool isDesktop; - - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(1200, 800)), - child: Builder( - builder: (context) { - isMobile = context.isMobile; - isTablet = context.isTablet; - isDesktop = context.isDesktop; - return const SizedBox.shrink(); - }, - ), - ), - ); - - expect(isMobile, isFalse); - expect(isTablet, isFalse); - expect(isDesktop, isTrue); - }); - }); -} diff --git a/flutter_inappwebview/example/test/utils/settings_defaults_test.dart b/flutter_inappwebview/example/test/utils/settings_defaults_test.dart deleted file mode 100644 index fb46e8c014..0000000000 --- a/flutter_inappwebview/example/test/utils/settings_defaults_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/utils/settings_defaults.dart'; - -void main() { - setUp(() { - debugDefaultTargetPlatformOverride = null; - }); - - tearDown(() { - debugDefaultTargetPlatformOverride = null; - }); - - test('default settings map matches constructor defaults', () { - final defaults = defaultInAppWebViewSettings().toMap( - enumMethod: EnumMethod.nativeValue, - ); - final expected = InAppWebViewSettings().toMap( - enumMethod: EnumMethod.nativeValue, - ); - - expect(defaults, expected); - }); - - test('default environment settings map matches constructor defaults', () { - final defaults = defaultWebViewEnvironmentSettings().toMap( - enumMethod: EnumMethod.nativeValue, - ); - final expected = WebViewEnvironmentSettings().toMap( - enumMethod: EnumMethod.nativeValue, - ); - - expect(defaults, expected); - }); -} diff --git a/flutter_inappwebview/example/test/utils/settings_definitions_test.dart b/flutter_inappwebview/example/test/utils/settings_definitions_test.dart deleted file mode 100644 index 356514a98c..0000000000 --- a/flutter_inappwebview/example/test/utils/settings_definitions_test.dart +++ /dev/null @@ -1,145 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/models/setting_definition.dart'; -import 'package:flutter_inappwebview_example/utils/environment_settings_definitions.dart'; -import 'package:flutter_inappwebview_example/utils/settings_definitions.dart'; - -List _enumValuesForPlatform( - TargetPlatform platform, - Iterable Function() getter, -) { - final previousPlatform = debugDefaultTargetPlatformOverride; - debugDefaultTargetPlatformOverride = platform; - try { - return getter().toList(); - } catch (_) { - return []; - } finally { - debugDefaultTargetPlatformOverride = previousPlatform; - } -} - -T _withPlatform(TargetPlatform platform, T Function() body) { - final previousPlatform = debugDefaultTargetPlatformOverride; - debugDefaultTargetPlatformOverride = platform; - try { - return body(); - } finally { - debugDefaultTargetPlatformOverride = previousPlatform; - } -} - -void main() { - test('getSettingDefinitions returns expected categories', () { - final definitions = getSettingDefinitions(); - - expect(definitions, isNotEmpty); - expect(definitions.keys, containsAll(['General', 'Security', 'Cache'])); - }); - - test('definitions contain expected types', () { - final definitions = getSettingDefinitions(); - final general = definitions['General']; - - expect(general, isNotNull); - expect(general!.first.type, SettingType.boolean); - }); - - test('enum-like setting definitions use enum values lists', () { - final definitions = getSettingDefinitions(); - final security = definitions['Security']; - final cache = definitions['Cache']; - - expect(security, isNotNull); - expect(cache, isNotNull); - - final mixedContent = security!.firstWhere( - (definition) => - definition.property == InAppWebViewSettingsProperty.mixedContentMode, - ); - final cacheMode = cache!.firstWhere( - (definition) => - definition.property == InAppWebViewSettingsProperty.cacheMode, - ); - - expect(mixedContent.enumValues, unorderedEquals(MixedContentMode.values)); - expect(cacheMode.enumValues, unorderedEquals(CacheMode.values)); - }); - - test('enumValues fields are lists when provided', () { - final definitions = getSettingDefinitions(); - - for (final category in definitions.values) { - for (final definition in category) { - expect(definition.enumValues, anyOf(isNull, isA())); - } - } - - final environmentDefinitions = getEnvironmentSettingDefinitions(); - for (final category in environmentDefinitions.values) { - for (final definition in category) { - expect(definition.enumValues, anyOf(isNull, isA())); - } - } - }); - - test('enum-like environment setting definitions use enum values lists', () { - final definitions = _withPlatform( - TargetPlatform.windows, - getEnvironmentSettingDefinitions, - ); - final releaseChannel = definitions['Release Channel']; - final appearance = definitions['Appearance']; - final cache = definitions['Cache']; - - expect(releaseChannel, isNotNull); - expect(appearance, isNotNull); - expect(cache, isNotNull); - - final channelSearchKind = releaseChannel!.firstWhere( - (definition) => - definition.property == - WebViewEnvironmentSettingsProperty.channelSearchKind, - ); - final releaseChannels = releaseChannel.firstWhere( - (definition) => - definition.property == - WebViewEnvironmentSettingsProperty.releaseChannels, - ); - final scrollbarStyle = appearance!.firstWhere( - (definition) => - definition.property == - WebViewEnvironmentSettingsProperty.scrollbarStyle, - ); - final cacheModel = cache!.firstWhere( - (definition) => - definition.property == WebViewEnvironmentSettingsProperty.cacheModel, - ); - - final expectedChannelKinds = _enumValuesForPlatform( - TargetPlatform.windows, - () => EnvironmentChannelSearchKind.values, - ); - final expectedReleaseChannels = _enumValuesForPlatform( - TargetPlatform.windows, - () => EnvironmentReleaseChannels.values, - ); - final expectedScrollbarStyles = _enumValuesForPlatform( - TargetPlatform.windows, - () => EnvironmentScrollbarStyle.values, - ); - final expectedCacheModels = _enumValuesForPlatform( - TargetPlatform.windows, - () => CacheModel.values, - ); - - expect(channelSearchKind.enumValues, unorderedEquals(expectedChannelKinds)); - expect( - releaseChannels.enumValues, - unorderedEquals(expectedReleaseChannels), - ); - expect(scrollbarStyle.enumValues, unorderedEquals(expectedScrollbarStyles)); - expect(cacheModel.enumValues, unorderedEquals(expectedCacheModels)); - }); -} diff --git a/flutter_inappwebview/example/test/utils/support_check_helper_test.dart b/flutter_inappwebview/example/test/utils/support_check_helper_test.dart deleted file mode 100644 index 0a4e0e516d..0000000000 --- a/flutter_inappwebview/example/test/utils/support_check_helper_test.dart +++ /dev/null @@ -1,88 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; - -enum _FakeMethod { alpha } - -enum _FakeProperty { beta } - -void main() { - group('SupportCheckHelper', () { - test('targetPlatformFor maps to expected TargetPlatform', () { - expect( - SupportCheckHelper.targetPlatformFor(SupportedPlatform.android), - TargetPlatform.android, - ); - expect( - SupportCheckHelper.targetPlatformFor(SupportedPlatform.ios), - TargetPlatform.iOS, - ); - expect( - SupportCheckHelper.targetPlatformFor(SupportedPlatform.macos), - TargetPlatform.macOS, - ); - expect( - SupportCheckHelper.targetPlatformFor(SupportedPlatform.windows), - TargetPlatform.windows, - ); - expect( - SupportCheckHelper.targetPlatformFor(SupportedPlatform.linux), - TargetPlatform.linux, - ); - expect( - SupportCheckHelper.targetPlatformFor(SupportedPlatform.web), - isNull, - ); - }); - - test('isMethodSupportedForPlatform forwards target platform', () { - final calledPlatforms = []; - bool fakeChecker(_FakeMethod method, {TargetPlatform? platform}) { - calledPlatforms.add(platform); - return platform == TargetPlatform.android; - } - - final result = SupportCheckHelper.isMethodSupportedForPlatform( - platform: SupportedPlatform.android, - method: _FakeMethod.alpha, - checker: fakeChecker, - ); - - expect(result, isTrue); - expect(calledPlatforms, [TargetPlatform.android]); - }); - - test('supportedPlatformsForMethod aggregates supported platforms', () { - bool fakeChecker(_FakeMethod method, {TargetPlatform? platform}) { - return platform == TargetPlatform.android || - platform == TargetPlatform.windows; - } - - final supported = SupportCheckHelper.supportedPlatformsForMethod( - method: _FakeMethod.alpha, - checker: fakeChecker, - ); - - expect(supported, contains(SupportedPlatform.android)); - expect(supported, contains(SupportedPlatform.windows)); - expect(supported, isNot(contains(SupportedPlatform.ios))); - }); - - test('isPropertySupportedForPlatform forwards target platform', () { - final calledPlatforms = []; - bool fakeChecker(dynamic property, {TargetPlatform? platform}) { - calledPlatforms.add(platform); - return platform == TargetPlatform.macOS; - } - - final result = SupportCheckHelper.isPropertySupportedForPlatform( - platform: SupportedPlatform.macos, - property: _FakeProperty.beta, - checker: fakeChecker, - ); - - expect(result, isTrue); - expect(calledPlatforms, [TargetPlatform.macOS]); - }); - }); -} diff --git a/flutter_inappwebview/example/test/utils/support_checker_naming_test.dart b/flutter_inappwebview/example/test/utils/support_checker_naming_test.dart deleted file mode 100644 index 81ed15932d..0000000000 --- a/flutter_inappwebview/example/test/utils/support_checker_naming_test.dart +++ /dev/null @@ -1,83 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/utils/controller_methods_registry.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; - -void main() { - group('SupportChecker naming', () { - test('helper class names use Type.toString()', () { - expect( - SupportChecker.classNameOf(InAppWebViewController), - (InAppWebViewController).toString(), - ); - expect( - SupportChecker.classNameOf(HeadlessInAppWebView), - (HeadlessInAppWebView).toString(), - ); - expect( - SupportChecker.classNameOf(InAppBrowser), - (InAppBrowser).toString(), - ); - expect( - SupportChecker.eventClassNameOf(InAppWebView), - '${(InAppWebView).toString()} Events', - ); - }); - - test('API definitions use (Type).toString() class names', () { - final definitions = SupportChecker.getAllApiDefinitions(); - - final controllerDefinition = definitions.firstWhere( - (definition) => - definition.className == (InAppWebViewController).toString(), - ); - expect( - controllerDefinition.className, - (InAppWebViewController).toString(), - ); - expect(controllerDefinition.methods, isNotEmpty); - expect( - controllerDefinition.methods.every( - (method) => method.className == controllerDefinition.className, - ), - isTrue, - ); - - final eventsDefinition = definitions.firstWhere( - (definition) => - definition.className == '${(InAppWebView).toString()} Events', - ); - expect(eventsDefinition.className, '${(InAppWebView).toString()} Events'); - expect( - eventsDefinition.events.every( - (event) => event.className == eventsDefinition.className, - ), - isTrue, - ); - }); - }); - - group('ControllerMethodsRegistry naming', () { - test('method entries use enum .name for id and name', () { - final registry = ControllerMethodsRegistry.instance; - final methods = registry.allMethods; - - expect(methods, isNotEmpty); - - for (final entry in methods) { - expect(entry.id, entry.methodEnum.name); - expect(entry.name, entry.methodEnum.name); - expect(entry.id.contains('.'), isFalse); - expect(entry.name.contains('.'), isFalse); - } - }); - - test('category ids use enum .name', () { - final registry = ControllerMethodsRegistry.instance; - for (final category in registry.categories) { - expect(category.id, category.categoryType.name); - expect(category.id.contains('.'), isFalse); - } - }); - }); -} diff --git a/flutter_inappwebview/example/test/utils/test_registry_test.dart b/flutter_inappwebview/example/test/utils/test_registry_test.dart deleted file mode 100644 index 716884f597..0000000000 --- a/flutter_inappwebview/example/test/utils/test_registry_test.dart +++ /dev/null @@ -1,155 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/models/test_case.dart'; -import 'package:flutter_inappwebview_example/models/test_result.dart'; -import 'package:flutter_inappwebview_example/utils/constants.dart'; -import 'package:flutter_inappwebview_example/utils/test_registry.dart'; - -void main() { - group('TestRegistry', () { - setUp(() { - TestRegistry.clear(); - }); - - test('registers and retrieves test by category', () { - final testCase = TestCase( - id: 'test_1', - title: 'Test Case 1', - description: 'Test description', - category: TestCategory.navigation, - complexity: TestComplexity.quick, - supportedPlatforms: ['android', 'ios'], - execute: () async => TestResult( - passed: true, - message: 'Test passed', - duration: Duration.zero, - ), - ); - - TestRegistry.register(testCase); - - final retrieved = TestRegistry.getTestsByCategory( - TestCategory.navigation, - ); - expect(retrieved, hasLength(1)); - expect(retrieved.first.id, 'test_1'); - expect(retrieved.first.title, 'Test Case 1'); - }); - - test('retrieves multiple tests for same category', () { - final testCase1 = TestCase( - id: 'test_1', - title: 'Test 1', - description: 'Description', - category: TestCategory.navigation, - complexity: TestComplexity.quick, - supportedPlatforms: ['android'], - execute: () async => TestResult( - passed: true, - message: 'Test passed', - duration: Duration.zero, - ), - ); - - final testCase2 = TestCase( - id: 'test_2', - title: 'Test 2', - description: 'Description', - category: TestCategory.navigation, - complexity: TestComplexity.medium, - supportedPlatforms: ['ios'], - execute: () async => TestResult( - passed: true, - message: 'Test passed', - duration: Duration.zero, - ), - ); - - TestRegistry.register(testCase1); - TestRegistry.register(testCase2); - - final retrieved = TestRegistry.getTestsByCategory( - TestCategory.navigation, - ); - expect(retrieved, hasLength(2)); - }); - - test('returns empty list for category with no tests', () { - final retrieved = TestRegistry.getTestsByCategory( - TestCategory.javascript, - ); - expect(retrieved, isEmpty); - }); - - test('getAllTests returns all registered tests', () { - final testCase1 = TestCase( - id: 'test_1', - title: 'Test 1', - description: 'Description', - category: TestCategory.navigation, - complexity: TestComplexity.quick, - supportedPlatforms: ['android'], - execute: () async => TestResult( - passed: true, - message: 'Test passed', - duration: Duration.zero, - ), - ); - - final testCase2 = TestCase( - id: 'test_2', - title: 'Test 2', - description: 'Description', - category: TestCategory.javascript, - complexity: TestComplexity.medium, - supportedPlatforms: ['ios'], - execute: () async => TestResult( - passed: true, - message: 'Test passed', - duration: Duration.zero, - ), - ); - - TestRegistry.register(testCase1); - TestRegistry.register(testCase2); - - final allTests = TestRegistry.getAllTests(); - expect(allTests, hasLength(2)); - }); - - test('getTestById returns correct test', () { - final testCase = TestCase( - id: 'unique_test', - title: 'Unique Test', - description: 'Description', - category: TestCategory.navigation, - complexity: TestComplexity.quick, - supportedPlatforms: ['android'], - execute: () async => TestResult( - passed: true, - message: 'Test passed', - duration: Duration.zero, - ), - ); - - TestRegistry.register(testCase); - - final retrieved = TestRegistry.getTestById('unique_test'); - expect(retrieved, isNotNull); - expect(retrieved?.id, 'unique_test'); - expect(retrieved?.title, 'Unique Test'); - }); - - test('getTestById returns null for non-existent id', () { - final retrieved = TestRegistry.getTestById('non_existent'); - expect(retrieved, isNull); - }); - - test('init registers sample tests', () { - TestRegistry.init(); - - final allTests = TestRegistry.getAllTests(); - expect(allTests.isNotEmpty, true); - expect(allTests.length, greaterThanOrEqualTo(10)); - }); - }); -} diff --git a/flutter_inappwebview/example/test/widgets/common/app_drawer_test.dart b/flutter_inappwebview/example/test/widgets/common/app_drawer_test.dart deleted file mode 100644 index de607ab263..0000000000 --- a/flutter_inappwebview/example/test/widgets/common/app_drawer_test.dart +++ /dev/null @@ -1,102 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/widgets/common/app_drawer.dart'; - -class TestNavigatorObserver extends NavigatorObserver { - int didReplaceCount = 0; - - @override - void didReplace({Route? newRoute, Route? oldRoute}) { - didReplaceCount += 1; - super.didReplace(newRoute: newRoute, oldRoute: oldRoute); - } -} - -void main() { - group('AppDrawer', () { - testWidgets('renders drawer header and sections', ( - WidgetTester tester, - ) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - appBar: AppBar(title: const Text('Home')), - drawer: AppDrawer(), - ), - ), - ); - - await tester.tap(find.byTooltip('Open navigation menu')); - await tester.pumpAndSettle(); - - expect(find.text('Test Suite'), findsOneWidget); - expect(find.text('WebView Tester'), findsOneWidget); - expect(find.text('Storage & Cookies'), findsOneWidget); - expect(find.text('Cookie Manager'), findsOneWidget); - - await tester.scrollUntilVisible( - find.text('Browsers'), - 200, - scrollable: find.byType(Scrollable), - ); - expect(find.text('Browsers'), findsOneWidget); - - await tester.scrollUntilVisible( - find.text('Documentation'), - 200, - scrollable: find.byType(Scrollable), - ); - expect(find.text('Documentation'), findsOneWidget); - }); - - testWidgets('navigates to settings editor', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - routes: { - '/': (context) => Scaffold( - appBar: AppBar(title: const Text('Home')), - drawer: AppDrawer(), - ), - '/settings': (context) => - const Scaffold(body: Text('Settings Screen')), - }, - ), - ); - - await tester.tap(find.byTooltip('Open navigation menu')); - await tester.pumpAndSettle(); - await tester.tap(find.text('Settings Editor')); - await tester.pumpAndSettle(); - - expect(find.text('Settings Screen'), findsOneWidget); - }); - - testWidgets('uses replacement for webview tester', ( - WidgetTester tester, - ) async { - final observer = TestNavigatorObserver(); - - await tester.pumpWidget( - MaterialApp( - navigatorObservers: [observer], - initialRoute: '/settings', - routes: { - '/': (context) => const Scaffold(body: Text('Home Screen')), - '/settings': (context) => Scaffold( - appBar: AppBar(title: const Text('Settings')), - drawer: AppDrawer(), - ), - }, - ), - ); - - await tester.tap(find.byTooltip('Open navigation menu')); - await tester.pumpAndSettle(); - await tester.tap(find.text('WebView Tester')); - await tester.pumpAndSettle(); - - expect(find.text('Home Screen'), findsOneWidget); - expect(observer.didReplaceCount, 1); - }); - }); -} diff --git a/flutter_inappwebview/example/test/widgets/common/method_card_test.dart b/flutter_inappwebview/example/test/widgets/common/method_card_test.dart deleted file mode 100644 index e444352c49..0000000000 --- a/flutter_inappwebview/example/test/widgets/common/method_card_test.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_card.dart'; - -void main() { - testWidgets('test_method_card_compact_on_mobile', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: MediaQuery( - data: const MediaQueryData(size: Size(320, 800)), - child: Scaffold( - body: MethodCard( - methodName: 'Test Method', - description: 'Does something useful.', - supportedPlatforms: const {SupportedPlatform.android}, - onRun: () {}, - ), - ), - ), - ), - ); - - final buttonFinder = find.byKey(const Key('method-card-run-button')); - expect(buttonFinder, findsOneWidget); - - final button = tester.widget(buttonFinder); - final style = button.style; - final minSize = style?.minimumSize?.resolve({}); - final padding = style?.padding?.resolve({}); - - expect(minSize?.height, 40); - expect(padding, const EdgeInsets.symmetric(horizontal: 12, vertical: 8)); - }); -} diff --git a/flutter_inappwebview/example/test/widgets/common/method_result_history_test.dart b/flutter_inappwebview/example/test/widgets/common/method_result_history_test.dart deleted file mode 100644 index 1224cf2a25..0000000000 --- a/flutter_inappwebview/example/test/widgets/common/method_result_history_test.dart +++ /dev/null @@ -1,205 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/widgets/common/method_result_history.dart'; - -void main() { - const platformChannel = SystemChannels.platform; - String? clipboardText; - - setUp(() { - TestWidgetsFlutterBinding.ensureInitialized(); - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(platformChannel, (call) async { - if (call.method == 'Clipboard.setData') { - clipboardText = call.arguments['text'] as String?; - return null; - } - if (call.method == 'Clipboard.getData') { - return {'text': clipboardText}; - } - return null; - }); - }); - - tearDown(() { - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(platformChannel, null); - clipboardText = null; - }); - - testWidgets('renders collapsed by default with latest result summary', ( - tester, - ) async { - final entries = [ - MethodResultEntry( - message: 'latest result', - isError: false, - timestamp: DateTime(2024, 1, 1), - value: {'key': 'json_value', 'number': 42}, - ), - MethodResultEntry( - message: 'older result', - isError: true, - timestamp: DateTime(2023, 12, 31), - ), - ]; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold(body: MethodResultHistory(entries: entries)), - ), - ); - - // Latest result should be visible in collapsed state as summary - expect(find.text('latest result'), findsOneWidget); - // Older result should NOT be visible when collapsed - expect(find.text('older result'), findsNothing); - }); - - testWidgets('expands to show all entries when tapped', (tester) async { - final entries = [ - MethodResultEntry( - message: 'latest result', - isError: false, - timestamp: DateTime(2024, 1, 1), - value: {'key': 'json_value', 'number': 42}, - ), - MethodResultEntry( - message: 'older result', - isError: true, - timestamp: DateTime(2023, 12, 31), - ), - ]; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold(body: MethodResultHistory(entries: entries)), - ), - ); - - // Tap to expand - await tester.tap(find.text('History')); - await tester.pump(); - - // Both entries should now be visible - expect(find.text('latest result'), findsOneWidget); - expect(find.text('older result'), findsOneWidget); - }); - - testWidgets('renders history entries and copies value if available', ( - tester, - ) async { - final entries = [ - MethodResultEntry( - message: 'latest result', - isError: false, - timestamp: DateTime(2024, 1, 1), - value: {'key': 'json_value', 'number': 42}, - ), - MethodResultEntry( - message: 'older result', - isError: true, - timestamp: DateTime(2023, 12, 31), - ), - ]; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: MethodResultHistory(entries: entries, initiallyExpanded: true), - ), - ), - ); - - expect(find.text('latest result'), findsOneWidget); - expect(find.text('older result'), findsOneWidget); - - await tester.tap(find.byKey(const Key('method-history-copy'))); - await tester.pumpAndSettle(); - - // Should copy JSON-encoded value, not message - expect(clipboardText, contains('"key": "json_value"')); - expect(clipboardText, contains('"number": 42')); - }); - - testWidgets('copies message when no value is available', (tester) async { - final entries = [ - MethodResultEntry( - message: 'message only', - isError: false, - timestamp: DateTime(2024, 1, 1), - ), - ]; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: MethodResultHistory(entries: entries, initiallyExpanded: true), - ), - ), - ); - - await tester.tap(find.byKey(const Key('method-history-copy'))); - await tester.pumpAndSettle(); - - expect(clipboardText, 'message only'); - }); - - testWidgets('copies selected history entry', (tester) async { - final entries = [ - MethodResultEntry( - message: 'first entry', - isError: false, - timestamp: DateTime(2024, 1, 1), - value: 'first_value', - ), - MethodResultEntry( - message: 'second entry', - isError: true, - timestamp: DateTime(2024, 1, 2), - value: 'second_value', - ), - ]; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: MethodResultHistory(entries: entries, initiallyExpanded: true), - ), - ), - ); - - await tester.tap(find.byKey(const Key('method-history-entry-1'))); - await tester.pump(); - - await tester.tap(find.byKey(const Key('method-history-copy'))); - await tester.pumpAndSettle(); - - // Should copy the JSON-encoded value "second_value" - expect(clipboardText, '"second_value"'); - }); - - testWidgets('initiallyExpanded=true shows entries immediately', ( - tester, - ) async { - final entries = [ - MethodResultEntry( - message: 'test entry', - isError: false, - timestamp: DateTime(2024, 1, 1), - ), - ]; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: MethodResultHistory(entries: entries, initiallyExpanded: true), - ), - ), - ); - - // Entry should be visible immediately - expect(find.byKey(const Key('method-history-entry-0')), findsOneWidget); - }); -} diff --git a/flutter_inappwebview/example/test/widgets/common/parameter_dialog_enum_like_test.dart b/flutter_inappwebview/example/test/widgets/common/parameter_dialog_enum_like_test.dart deleted file mode 100644 index 2c15b4ad0d..0000000000 --- a/flutter_inappwebview/example/test/widgets/common/parameter_dialog_enum_like_test.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; - -class _TestEnumLike { - final String _label; - - const _TestEnumLike._(this._label); - - String name() => _label; - - static const alpha = _TestEnumLike._('alpha'); - static const beta = _TestEnumLike._('beta'); - - static const values = [alpha, beta]; -} - -void main() { - group('ParameterDialog enum-like handling', () { - testWidgets('uses name() for enum-like display', (tester) async { - final parameters = { - 'mode': EnumParameterValueHint<_TestEnumLike>( - _TestEnumLike.alpha, - _TestEnumLike.values, - ), - }; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: ParameterDialog(title: 'Parameters', parameters: parameters), - ), - ), - ); - - await tester.tap(find.byType(DropdownButtonFormField)); - await tester.pumpAndSettle(); - - expect(find.text('alpha'), findsWidgets); - expect(find.text('beta'), findsWidgets); - }); - - testWidgets('renders multi-select enum-like values', (tester) async { - final parameters = { - 'flags': EnumParameterValueHint<_TestEnumLike>( - <_TestEnumLike>[_TestEnumLike.alpha], - _TestEnumLike.values, - isMultiSelect: true, - ), - }; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: ParameterDialog(title: 'Parameters', parameters: parameters), - ), - ), - ); - - final alphaChip = tester.widget( - find.widgetWithText(FilterChip, 'alpha'), - ); - final betaChip = tester.widget( - find.widgetWithText(FilterChip, 'beta'), - ); - - expect(alphaChip.selected, isTrue); - expect(betaChip.selected, isFalse); - - await tester.tap(find.widgetWithText(FilterChip, 'beta')); - await tester.pumpAndSettle(); - - final updatedBetaChip = tester.widget( - find.widgetWithText(FilterChip, 'beta'), - ); - expect(updatedBetaChip.selected, isTrue); - }); - }); -} diff --git a/flutter_inappwebview/example/test/widgets/common/parameter_dialog_required_paths_test.dart b/flutter_inappwebview/example/test/widgets/common/parameter_dialog_required_paths_test.dart deleted file mode 100644 index 24c069915e..0000000000 --- a/flutter_inappwebview/example/test/widgets/common/parameter_dialog_required_paths_test.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'dart:typed_data'; - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/widgets/common/parameter_dialog.dart'; - -void main() { - group('ParameterDialog required paths', () { - testWidgets( - 'shows required errors for non-text fields and accepts false boolean', - (tester) async { - final parameters = { - 'bytesValue': Uint8List(0), - 'dateValue': const ParameterValueHint( - null, - ParameterValueType.date, - ), - 'colorValue': const ParameterValueHint( - null, - ParameterValueType.color, - ), - 'listValue': [], - 'mapValue': {}, - 'boolValue': false, - }; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: ParameterDialog( - title: 'Parameters', - parameters: parameters, - requiredPaths: const [ - 'bytesValue', - 'dateValue', - 'colorValue', - 'listValue', - 'mapValue', - 'boolValue', - ], - ), - ), - ), - ); - - await tester.tap(find.text('Apply')); - await tester.pumpAndSettle(); - - expect(find.text('Required'), findsNWidgets(5)); - - final boolTile = tester.widget( - find.widgetWithText(SwitchListTile, 'boolValue'), - ); - expect(boolTile.value, isFalse); - }, - ); - }); -} diff --git a/flutter_inappwebview/example/test/widgets/common/platform_filter_test.dart b/flutter_inappwebview/example/test/widgets/common/platform_filter_test.dart deleted file mode 100644 index 2ef625b767..0000000000 --- a/flutter_inappwebview/example/test/widgets/common/platform_filter_test.dart +++ /dev/null @@ -1,156 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/widgets/common/platform_filter.dart'; -import 'package:flutter_inappwebview_example/utils/support_checker.dart'; - -void main() { - group('PlatformFilter', () { - testWidgets('should render 6 checkboxes for all platforms', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: PlatformFilter( - selectedPlatforms: const [], - onChanged: (_) {}, - ), - ), - ), - ); - - await tester.pumpAndSettle(); - - // Should find 6 checkboxes (one for each platform) - expect(find.byType(CheckboxListTile), findsNWidgets(6)); - - // Verify platform names are displayed - for (final platform in SupportedPlatform.values) { - expect(find.text(platform.displayName), findsOneWidget); - } - }); - - testWidgets('should show selected platforms as checked', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: PlatformFilter( - selectedPlatforms: const [ - SupportedPlatform.android, - SupportedPlatform.ios, - ], - onChanged: (_) {}, - ), - ), - ), - ); - - await tester.pumpAndSettle(); - - // Find checkboxes - final checkboxes = tester.widgetList( - find.byType(CheckboxListTile), - ); - - int checkedCount = 0; - for (final checkbox in checkboxes) { - if (checkbox.value == true) { - checkedCount++; - } - } - - expect(checkedCount, 2); - }); - - testWidgets('should call onChanged when checkbox is tapped', ( - tester, - ) async { - List? changedSelection; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: PlatformFilter( - selectedPlatforms: const [SupportedPlatform.android], - onChanged: (selection) { - changedSelection = selection; - }, - ), - ), - ), - ); - - await tester.pumpAndSettle(); - - // Tap the iOS checkbox - await tester.tap(find.text('iOS')); - await tester.pumpAndSettle(); - - expect(changedSelection, isNotNull); - expect(changedSelection, contains(SupportedPlatform.android)); - expect(changedSelection, contains(SupportedPlatform.ios)); - }); - - testWidgets('should remove platform when unchecking', (tester) async { - List? changedSelection; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: PlatformFilter( - selectedPlatforms: const [ - SupportedPlatform.android, - SupportedPlatform.ios, - ], - onChanged: (selection) { - changedSelection = selection; - }, - ), - ), - ), - ); - - await tester.pumpAndSettle(); - - // Tap the Android checkbox to uncheck it - await tester.tap(find.text('Android')); - await tester.pumpAndSettle(); - - expect(changedSelection, isNotNull); - expect(changedSelection, isNot(contains(SupportedPlatform.android))); - expect(changedSelection, contains(SupportedPlatform.ios)); - }); - - testWidgets('should support selecting all platforms', (tester) async { - List selection = []; - - await tester.pumpWidget( - StatefulBuilder( - builder: (context, setState) { - return MaterialApp( - home: Scaffold( - body: PlatformFilter( - selectedPlatforms: selection, - onChanged: (newSelection) { - setState(() { - selection = newSelection; - }); - }, - ), - ), - ); - }, - ), - ); - - await tester.pumpAndSettle(); - - // Tap all checkboxes - for (final platform in SupportedPlatform.values) { - await tester.tap(find.text(platform.displayName)); - await tester.pumpAndSettle(); - } - - expect(selection, containsAll(SupportedPlatform.values)); - expect(selection.length, SupportedPlatform.values.length); - }); - }); -} diff --git a/flutter_inappwebview/example/test/widgets/common/profile_selector_card_test.dart b/flutter_inappwebview/example/test/widgets/common/profile_selector_card_test.dart deleted file mode 100644 index 3537db1a26..0000000000 --- a/flutter_inappwebview/example/test/widgets/common/profile_selector_card_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:provider/provider.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:flutter_inappwebview_example/providers/settings_manager.dart'; -import 'package:flutter_inappwebview_example/widgets/common/profile_selector_card.dart'; - -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - - testWidgets('test_profile_card_mobile_padding', (tester) async { - SharedPreferences.setMockInitialValues({}); - final settingsManager = SettingsManager( - environmentFactory: (_) async => null, - environmentSupportChecker: () => false, - ); - await settingsManager.init(); - - await tester.pumpWidget( - MaterialApp( - home: MediaQuery( - data: const MediaQueryData(size: Size(320, 800)), - child: ChangeNotifierProvider.value( - value: settingsManager, - child: Scaffold( - body: ProfileSelectorCard( - onEditSettingsProfile: () {}, - onEditEnvironmentProfile: () {}, - ), - ), - ), - ), - ), - ); - - await tester.pumpAndSettle(); - - final paddingFinder = find.byKey( - const Key('profile-selector-card-padding'), - ); - expect(paddingFinder, findsOneWidget); - - final paddingWidget = tester.widget(paddingFinder); - expect(paddingWidget.padding, const EdgeInsets.all(12)); - }); -} diff --git a/flutter_inappwebview/example/test/widgets/common/responsive_row_test.dart b/flutter_inappwebview/example/test/widgets/common/responsive_row_test.dart deleted file mode 100644 index 2af9181105..0000000000 --- a/flutter_inappwebview/example/test/widgets/common/responsive_row_test.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/widgets/common/responsive_row.dart'; - -void main() { - testWidgets('test_responsive_row_switches_to_column', (tester) async { - await tester.pumpWidget( - const MaterialApp( - home: Scaffold( - body: SizedBox( - width: 500, - child: ResponsiveRow(children: [Text('A'), Text('B')]), - ), - ), - ), - ); - - final responsiveRowFinder = find.byType(ResponsiveRow); - final columnFinder = find.descendant( - of: responsiveRowFinder, - matching: find.byType(Column), - ); - final rowFinder = find.descendant( - of: responsiveRowFinder, - matching: find.byType(Row), - ); - - expect(columnFinder, findsOneWidget); - expect(rowFinder, findsNothing); - }); - - testWidgets('test_responsive_row_switches_to_row', (tester) async { - await tester.pumpWidget( - const MaterialApp( - home: Scaffold( - body: SizedBox( - width: 600, - child: ResponsiveRow(children: [Text('A'), Text('B')]), - ), - ), - ), - ); - - final responsiveRowFinder = find.byType(ResponsiveRow); - final columnFinder = find.descendant( - of: responsiveRowFinder, - matching: find.byType(Column), - ); - final rowFinder = find.descendant( - of: responsiveRowFinder, - matching: find.byType(Row), - ); - - expect(columnFinder, findsNothing); - expect(rowFinder, findsOneWidget); - }); -} diff --git a/flutter_inappwebview/example/test/widgets/common/test_card_test.dart b/flutter_inappwebview/example/test/widgets/common/test_card_test.dart deleted file mode 100644 index 8ea2771613..0000000000 --- a/flutter_inappwebview/example/test/widgets/common/test_card_test.dart +++ /dev/null @@ -1,155 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/widgets/common/test_card.dart'; -import 'package:flutter_inappwebview_example/models/test_case.dart'; -import 'package:flutter_inappwebview_example/utils/constants.dart'; - -void main() { - group('TestCard', () { - late TestCase testCase; - - setUp(() { - testCase = TestCase( - id: 'test_1', - title: 'Test Title', - description: 'Test Description', - supportedPlatforms: ['android', 'ios'], - category: TestCategory.navigation, - complexity: TestComplexity.quick, - execute: () async => null, - ); - }); - - testWidgets('should render title, description, and run button', ( - tester, - ) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: TestCard(testCase: testCase, onRun: () {}), - ), - ), - ); - - await tester.pumpAndSettle(); - - expect(find.text('Test Title'), findsOneWidget); - expect(find.text('Test Description'), findsOneWidget); - expect(find.byIcon(Icons.play_arrow), findsOneWidget); - }); - - testWidgets('should call onRun when run button is tapped', (tester) async { - bool runCalled = false; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: TestCard( - testCase: testCase, - onRun: () { - runCalled = true; - }, - ), - ), - ), - ); - - await tester.pumpAndSettle(); - - // Tap the run button - await tester.tap(find.byIcon(Icons.play_arrow)); - await tester.pumpAndSettle(); - - expect(runCalled, true); - }); - - testWidgets('should expand and collapse details on tap', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: TestCard(testCase: testCase, onRun: () {}), - ), - ), - ); - - await tester.pumpAndSettle(); - - // Initially collapsed - details should not be visible - expect(find.text('Category:'), findsNothing); - - // Tap the card to expand - await tester.tap(find.byType(Card)); - await tester.pumpAndSettle(); - - // Details should now be visible - expect(find.text('Category:'), findsOneWidget); - expect(find.text('Complexity:'), findsOneWidget); - - // Tap again to collapse - await tester.tap(find.byType(Card)); - await tester.pumpAndSettle(); - - // Details should be hidden again - expect(find.text('Category:'), findsNothing); - }); - - testWidgets('should display status indicator when status is provided', ( - tester, - ) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: TestCard( - testCase: testCase, - onRun: () {}, - status: TestStatus.passed, - ), - ), - ), - ); - - await tester.pumpAndSettle(); - - // Should find a success/passed indicator - expect(find.byIcon(Icons.check_circle), findsOneWidget); - }); - - testWidgets('should display failed status indicator', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: TestCard( - testCase: testCase, - onRun: () {}, - status: TestStatus.failed, - ), - ), - ), - ); - - await tester.pumpAndSettle(); - - // Should find a failed indicator - expect(find.byIcon(Icons.error), findsOneWidget); - }); - - testWidgets('should display running status indicator', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: TestCard( - testCase: testCase, - onRun: () {}, - status: TestStatus.running, - ), - ), - ), - ); - - await tester.pump(); - - // Should find a running/progress indicator - expect(find.byType(CircularProgressIndicator), findsOneWidget); - }); - }); -} diff --git a/flutter_inappwebview/example/test/widgets/webview/event_console_widget_test.dart b/flutter_inappwebview/example/test/widgets/webview/event_console_widget_test.dart deleted file mode 100644 index db45059936..0000000000 --- a/flutter_inappwebview/example/test/widgets/webview/event_console_widget_test.dart +++ /dev/null @@ -1,224 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/models/event_log_entry.dart'; -import 'package:flutter_inappwebview_example/providers/event_log_provider.dart'; -import 'package:flutter_inappwebview_example/widgets/webview/event_console_widget.dart'; - -void main() { - group('EventConsoleWidget', () { - late EventLogProvider eventLogProvider; - - setUp(() { - eventLogProvider = EventLogProvider(); - }); - - Widget createWidget() { - return MaterialApp( - home: ChangeNotifierProvider.value( - value: eventLogProvider, - child: Scaffold(body: EventConsoleWidget()), - ), - ); - } - - testWidgets('renders empty state when no events', (tester) async { - await tester.pumpWidget(createWidget()); - - expect(find.text('No events logged yet'), findsOneWidget); - expect(find.byType(ListView), findsNothing); - }); - - testWidgets('displays events in list', (tester) async { - eventLogProvider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Page loaded', - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(find.text('Page loaded'), findsOneWidget); - expect(find.byType(ListView), findsOneWidget); - }); - - testWidgets('shows clear button in header', (tester) async { - await tester.pumpWidget(createWidget()); - - expect(find.byTooltip('Clear'), findsOneWidget); - }); - - testWidgets('clear button clears events', (tester) async { - eventLogProvider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Event 1', - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(find.text('Event 1'), findsOneWidget); - - await tester.tap(find.byTooltip('Clear')); - await tester.pump(); - - expect(find.text('Event 1'), findsNothing); - expect(find.text('No events logged yet'), findsOneWidget); - }); - - testWidgets('displays filter dropdown', (tester) async { - await tester.pumpWidget(createWidget()); - - expect(find.byType(DropdownButton), findsOneWidget); - }); - - testWidgets('filter dropdown shows all event types', (tester) async { - await tester.pumpWidget(createWidget()); - - await tester.tap(find.byType(DropdownButton)); - await tester.pumpAndSettle(); - - expect(find.text('All Events'), findsWidgets); - for (final type in EventType.values) { - expect(find.text(type.name), findsOneWidget); - } - }); - - testWidgets('filters events by type', (tester) async { - eventLogProvider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Navigation event', - ), - ); - eventLogProvider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.error, - message: 'Error event', - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - // Initially shows both - expect(find.text('Navigation event'), findsOneWidget); - expect(find.text('Error event'), findsOneWidget); - - // Filter by navigation - await tester.tap(find.byType(DropdownButton)); - await tester.pumpAndSettle(); - await tester.tap(find.text('navigation').last); - await tester.pumpAndSettle(); - - expect(find.text('Navigation event'), findsOneWidget); - expect(find.text('Error event'), findsNothing); - }); - - testWidgets('event item displays timestamp and type', (tester) async { - final timestamp = DateTime(2025, 1, 1, 12, 30); - eventLogProvider.addEvent( - EventLogEntry( - timestamp: timestamp, - eventType: EventType.javascript, - message: 'JS executed', - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(find.text('JS executed'), findsOneWidget); - expect(find.textContaining('12:30'), findsOneWidget); - expect(find.text('javascript'), findsOneWidget); - }); - - testWidgets('event item can be expanded for details', (tester) async { - final data = {'url': 'https://example.com', 'duration': '150ms'}; - eventLogProvider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.network, - message: 'Request completed', - data: data, - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - // Initially data is hidden - expect(find.text('url'), findsNothing); - - // Find and tap the expansion tile - await tester.tap(find.byType(ExpansionTile)); - await tester.pumpAndSettle(); - - // Now data should be visible - expect(find.textContaining('url'), findsOneWidget); - expect(find.textContaining('https://example.com'), findsOneWidget); - }); - - testWidgets('multiple events are displayed in order', (tester) async { - eventLogProvider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Event 1', - ), - ); - eventLogProvider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Event 2', - ), - ); - eventLogProvider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.navigation, - message: 'Event 3', - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(find.text('Event 1'), findsOneWidget); - expect(find.text('Event 2'), findsOneWidget); - expect(find.text('Event 3'), findsOneWidget); - }); - - testWidgets('event types have different colors', (tester) async { - eventLogProvider.addEvent( - EventLogEntry( - timestamp: DateTime.now(), - eventType: EventType.error, - message: 'Error message', - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - // Find Container with error color - final container = tester.widget( - find - .ancestor(of: find.text('error'), matching: find.byType(Container)) - .first, - ); - - final decoration = container.decoration as BoxDecoration; - expect(decoration.color, Colors.red.shade50); - }); - }); -} diff --git a/flutter_inappwebview/example/test/widgets/webview/javascript_console_widget_test.dart b/flutter_inappwebview/example/test/widgets/webview/javascript_console_widget_test.dart deleted file mode 100644 index bf9b0e51f8..0000000000 --- a/flutter_inappwebview/example/test/widgets/webview/javascript_console_widget_test.dart +++ /dev/null @@ -1,280 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/widgets/webview/javascript_console_widget.dart'; - -void main() { - group('JavaScriptConsoleWidget', () { - testWidgets('renders JavaScript input field', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: JavaScriptConsoleWidget( - onExecute: (code) async => {'value': 'test result'}, - ), - ), - ), - ); - - expect(find.byType(TextField), findsOneWidget); - expect(find.text('Enter JavaScript code'), findsOneWidget); - }); - - testWidgets('renders execute and async execute buttons', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: JavaScriptConsoleWidget(onExecute: (code) async => null), - ), - ), - ); - - expect(find.widgetWithText(ElevatedButton, 'Execute'), findsOneWidget); - expect( - find.widgetWithText(ElevatedButton, 'Execute Async'), - findsOneWidget, - ); - }); - - testWidgets('executes JavaScript code on button press', (tester) async { - String? executedCode; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: JavaScriptConsoleWidget( - onExecute: (code) async { - executedCode = code; - return {'value': 42}; - }, - ), - ), - ), - ); - - // Enter code - await tester.enterText(find.byType(TextField), 'console.log("test")'); - await tester.pump(); - - // Execute - await tester.tap(find.widgetWithText(ElevatedButton, 'Execute')); - await tester.pump(); - - expect(executedCode, 'console.log("test")'); - }); - - testWidgets('executes async JavaScript code', (tester) async { - String? executedCode; - bool isAsync = false; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: JavaScriptConsoleWidget( - onExecute: (code) async { - executedCode = code; - return {'value': 'sync result'}; - }, - onExecuteAsync: (code) async { - executedCode = code; - isAsync = true; - return {'value': 'async result'}; - }, - ), - ), - ), - ); - - // Enter code - await tester.enterText(find.byType(TextField), 'await fetch("/api")'); - await tester.pump(); - - // Execute async - await tester.tap(find.widgetWithText(ElevatedButton, 'Execute Async')); - await tester.pump(); - - expect(executedCode, 'await fetch("/api")'); - expect(isAsync, true); - }); - - testWidgets('displays execution result', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: JavaScriptConsoleWidget( - onExecute: (code) async { - return {'value': 'Hello World'}; - }, - ), - ), - ), - ); - - // Enter and execute code - await tester.enterText(find.byType(TextField), 'return "test"'); - await tester.pump(); - await tester.tap(find.widgetWithText(ElevatedButton, 'Execute')); - await tester.pumpAndSettle(); - - expect(find.textContaining('Hello World'), findsOneWidget); - }); - - testWidgets('displays execution error', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: JavaScriptConsoleWidget( - onExecute: (code) async { - throw Exception('Syntax error'); - }, - ), - ), - ), - ); - - // Enter and execute code - await tester.enterText(find.byType(TextField), 'invalid code'); - await tester.pump(); - await tester.tap(find.widgetWithText(ElevatedButton, 'Execute')); - await tester.pumpAndSettle(); - - expect(find.textContaining('Error'), findsOneWidget); - expect(find.textContaining('Syntax error'), findsOneWidget); - }); - - testWidgets('shows clear button', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: JavaScriptConsoleWidget(onExecute: (code) async => null), - ), - ), - ); - - expect(find.widgetWithIcon(IconButton, Icons.clear), findsOneWidget); - }); - - testWidgets('clear button clears input and results', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: JavaScriptConsoleWidget( - onExecute: (code) async { - return {'value': 'result'}; - }, - ), - ), - ), - ); - - // Enter and execute code - await tester.enterText(find.byType(TextField), 'test code'); - await tester.pump(); - await tester.tap(find.widgetWithText(ElevatedButton, 'Execute')); - await tester.pumpAndSettle(); - - expect(find.textContaining('result'), findsOneWidget); - - // Clear - await tester.tap(find.byTooltip('Clear')); - await tester.pump(); - - final textField = tester.widget(find.byType(TextField)); - expect(textField.controller?.text, isEmpty); - expect(find.text('Execute JavaScript to see results'), findsOneWidget); - }); - - testWidgets('maintains history of executed scripts', (tester) async { - int executionCount = 0; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: JavaScriptConsoleWidget( - onExecute: (code) async { - executionCount++; - return {'value': 'result $executionCount'}; - }, - ), - ), - ), - ); - - // Execute first script - await tester.enterText(find.byType(TextField), 'script 1'); - await tester.pump(); - await tester.tap(find.widgetWithText(ElevatedButton, 'Execute')); - await tester.pumpAndSettle(); - - // Execute second script - await tester.enterText(find.byType(TextField), 'script 2'); - await tester.pump(); - await tester.tap(find.widgetWithText(ElevatedButton, 'Execute')); - await tester.pumpAndSettle(); - - // Both results should be visible - expect(find.textContaining('result 1'), findsOneWidget); - expect(find.textContaining('result 2'), findsOneWidget); - }); - - testWidgets('disables buttons when no code entered', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: JavaScriptConsoleWidget(onExecute: (code) async => null), - ), - ), - ); - - final executeButton = tester.widget( - find.widgetWithText(ElevatedButton, 'Execute'), - ); - - expect(executeButton.onPressed, isNull); - }); - - testWidgets('enables buttons when code is entered', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: JavaScriptConsoleWidget(onExecute: (code) async => null), - ), - ), - ); - - // Enter code - await tester.enterText(find.byType(TextField), 'test'); - await tester.pump(); - - final executeButton = tester.widget( - find.widgetWithText(ElevatedButton, 'Execute'), - ); - - expect(executeButton.onPressed, isNotNull); - }); - - testWidgets('formats JSON results', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: JavaScriptConsoleWidget( - onExecute: (code) async { - return { - 'value': {'name': 'John', 'age': 30, 'active': true}, - }; - }, - ), - ), - ), - ); - - await tester.enterText(find.byType(TextField), 'return user'); - await tester.pump(); - await tester.tap(find.widgetWithText(ElevatedButton, 'Execute')); - await tester.pumpAndSettle(); - - // Should display formatted JSON - expect(find.textContaining('name'), findsOneWidget); - expect(find.textContaining('John'), findsOneWidget); - }); - }); -} diff --git a/flutter_inappwebview/example/test/widgets/webview/method_tester_widget_test.dart b/flutter_inappwebview/example/test/widgets/webview/method_tester_widget_test.dart deleted file mode 100644 index 854a510669..0000000000 --- a/flutter_inappwebview/example/test/widgets/webview/method_tester_widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview_example/widgets/webview/method_tester_widget.dart'; - -import '../../test_helpers/mock_inappwebview_platform.dart'; - -void main() { - setUpAll(() { - MockInAppWebViewPlatform.initialize(); - }); - - group('MethodTesterWidget', () { - testWidgets('renders search input and warning when controller is null', ( - tester, - ) async { - await tester.pumpWidget( - const MaterialApp( - home: Scaffold(body: MethodTesterWidget(controller: null)), - ), - ); - - expect(find.textContaining('Method Tester'), findsOneWidget); - expect(find.byType(TextField), findsOneWidget); - expect( - find.textContaining('WebView controller not available'), - findsOneWidget, - ); - }); - }); -} diff --git a/flutter_inappwebview/example/test/widgets/webview/network_monitor_widget_test.dart b/flutter_inappwebview/example/test/widgets/webview/network_monitor_widget_test.dart deleted file mode 100644 index 6e846346c4..0000000000 --- a/flutter_inappwebview/example/test/widgets/webview/network_monitor_widget_test.dart +++ /dev/null @@ -1,253 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_inappwebview_example/models/network_request.dart'; -import 'package:flutter_inappwebview_example/providers/network_monitor.dart'; -import 'package:flutter_inappwebview_example/widgets/webview/network_monitor_widget.dart'; - -void main() { - group('NetworkMonitorWidget', () { - late NetworkMonitor networkMonitor; - - setUp(() { - networkMonitor = NetworkMonitor(); - }); - - Widget createWidget() { - return MaterialApp( - home: ChangeNotifierProvider.value( - value: networkMonitor, - child: Scaffold(body: NetworkMonitorWidget()), - ), - ); - } - - testWidgets('renders toggle button', (tester) async { - await tester.pumpWidget(createWidget()); - - expect(find.byType(Switch), findsOneWidget); - expect(find.text('Monitor Network'), findsOneWidget); - }); - - testWidgets('toggle button controls monitoring state', (tester) async { - await tester.pumpWidget(createWidget()); - - expect(networkMonitor.isMonitoring, false); - - await tester.tap(find.byType(Switch)); - await tester.pump(); - - expect(networkMonitor.isMonitoring, true); - - await tester.tap(find.byType(Switch)); - await tester.pump(); - - expect(networkMonitor.isMonitoring, false); - }); - - testWidgets('shows empty state when no requests', (tester) async { - await tester.pumpWidget(createWidget()); - - expect(find.text('No network requests yet'), findsOneWidget); - }); - - testWidgets('displays network requests in list', (tester) async { - networkMonitor.addRequest( - NetworkRequest( - id: '1', - method: 'GET', - url: 'https://example.com/api', - timestamp: DateTime.now(), - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(find.text('GET'), findsOneWidget); - expect(find.textContaining('example.com'), findsOneWidget); - }); - - testWidgets('shows clear button', (tester) async { - await tester.pumpWidget(createWidget()); - - expect(find.widgetWithIcon(IconButton, Icons.clear_all), findsOneWidget); - }); - - testWidgets('clear button clears requests', (tester) async { - networkMonitor.addRequest( - NetworkRequest( - id: '1', - method: 'GET', - url: 'https://example.com', - timestamp: DateTime.now(), - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(find.text('GET'), findsOneWidget); - - await tester.tap(find.widgetWithIcon(IconButton, Icons.clear_all)); - await tester.pump(); - - expect(find.text('GET'), findsNothing); - expect(find.text('No network requests yet'), findsOneWidget); - }); - - testWidgets('displays request method and URL', (tester) async { - networkMonitor.addRequest( - NetworkRequest( - id: '1', - method: 'POST', - url: 'https://api.example.com/users', - timestamp: DateTime.now(), - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(find.text('POST'), findsOneWidget); - expect(find.textContaining('api.example.com'), findsOneWidget); - }); - - testWidgets('displays status code when available', (tester) async { - networkMonitor.addRequest( - NetworkRequest( - id: '1', - method: 'GET', - url: 'https://example.com', - timestamp: DateTime.now(), - statusCode: 200, - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(find.text('200'), findsOneWidget); - }); - - testWidgets('displays duration when available', (tester) async { - networkMonitor.addRequest( - NetworkRequest( - id: '1', - method: 'GET', - url: 'https://example.com', - timestamp: DateTime.now(), - duration: Duration(milliseconds: 150), - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(find.textContaining('150ms'), findsOneWidget); - }); - - testWidgets('pending requests show pending indicator', (tester) async { - networkMonitor.addRequest( - NetworkRequest( - id: '1', - method: 'GET', - url: 'https://example.com', - timestamp: DateTime.now(), - // No status code = pending - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(find.text('Pending'), findsOneWidget); - }); - - testWidgets('request item can be expanded for details', (tester) async { - networkMonitor.addRequest( - NetworkRequest( - id: '1', - method: 'POST', - url: 'https://example.com/api', - timestamp: DateTime.now(), - headers: {'Content-Type': 'application/json'}, - body: '{"test": true}', - response: '{"success": true}', - statusCode: 201, - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - // Initially details are hidden - expect(find.text('Request Headers'), findsNothing); - - // Tap to expand - await tester.tap(find.byType(ExpansionTile)); - await tester.pumpAndSettle(); - - // Now details should be visible - expect(find.text('Request Headers'), findsOneWidget); - expect(find.textContaining('Content-Type'), findsOneWidget); - expect(find.textContaining('application/json'), findsOneWidget); - }); - - testWidgets('multiple requests are displayed', (tester) async { - networkMonitor.addRequest( - NetworkRequest( - id: '1', - method: 'GET', - url: 'https://example.com/1', - timestamp: DateTime.now(), - ), - ); - networkMonitor.addRequest( - NetworkRequest( - id: '2', - method: 'POST', - url: 'https://example.com/2', - timestamp: DateTime.now(), - ), - ); - networkMonitor.addRequest( - NetworkRequest( - id: '3', - method: 'PUT', - url: 'https://example.com/3', - timestamp: DateTime.now(), - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - expect(find.text('GET'), findsOneWidget); - expect(find.text('POST'), findsOneWidget); - expect(find.text('PUT'), findsOneWidget); - }); - - testWidgets('status code colors are correct', (tester) async { - networkMonitor.addRequest( - NetworkRequest( - id: '1', - method: 'GET', - url: 'https://example.com', - timestamp: DateTime.now(), - statusCode: 200, - ), - ); - - await tester.pumpWidget(createWidget()); - await tester.pump(); - - // Find the chip with status code - final chip = tester.widget( - find.ancestor(of: find.text('200'), matching: find.byType(Chip)), - ); - - expect(chip.backgroundColor, Colors.green.shade100); - }); - }); -} diff --git a/flutter_inappwebview/example/test/widgets/webview/user_script_tester_widget_test.dart b/flutter_inappwebview/example/test/widgets/webview/user_script_tester_widget_test.dart deleted file mode 100644 index 1e618caf14..0000000000 --- a/flutter_inappwebview/example/test/widgets/webview/user_script_tester_widget_test.dart +++ /dev/null @@ -1,304 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_inappwebview_example/widgets/webview/user_script_tester_widget.dart'; - -void main() { - group('UserScriptTesterWidget', () { - testWidgets('renders add script form', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: UserScriptTesterWidget( - onAddScript: (script) async {}, - onRemoveScript: (script) async {}, - ), - ), - ), - ); - - expect(find.text('Add User Script'), findsOneWidget); - expect(find.byType(TextField), findsOneWidget); - }); - - testWidgets('shows injection time dropdown', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: UserScriptTesterWidget( - onAddScript: (script) async {}, - onRemoveScript: (script) async {}, - ), - ), - ), - ); - - expect(find.text('Injection Time'), findsOneWidget); - expect( - find.byType(DropdownButton), - findsOneWidget, - ); - }); - - testWidgets('shows forMainFrameOnly switch', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: UserScriptTesterWidget( - onAddScript: (script) async {}, - onRemoveScript: (script) async {}, - ), - ), - ), - ); - - expect(find.text('Main Frame Only'), findsOneWidget); - expect(find.byType(Switch), findsOneWidget); - }); - - testWidgets('add button is disabled when source is empty', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: UserScriptTesterWidget( - onAddScript: (script) async {}, - onRemoveScript: (script) async {}, - ), - ), - ), - ); - - final addButton = tester.widget( - find.widgetWithText(ElevatedButton, 'Add Script'), - ); - - expect(addButton.onPressed, isNull); - }); - - testWidgets('add button is enabled when source is entered', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: UserScriptTesterWidget( - onAddScript: (script) async {}, - onRemoveScript: (script) async {}, - ), - ), - ), - ); - - await tester.enterText(find.byType(TextField), 'console.log("test")'); - await tester.pump(); - - final addButton = tester.widget( - find.widgetWithText(ElevatedButton, 'Add Script'), - ); - - expect(addButton.onPressed, isNotNull); - }); - - testWidgets('calls onAddScript when add button is pressed', (tester) async { - UserScript? addedScript; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: UserScriptTesterWidget( - onAddScript: (script) async { - addedScript = script; - }, - onRemoveScript: (script) async {}, - ), - ), - ), - ); - - await tester.enterText(find.byType(TextField), 'alert("Hello")'); - await tester.pump(); - - await tester.tap(find.widgetWithText(ElevatedButton, 'Add Script')); - await tester.pumpAndSettle(); - - expect(addedScript, isNotNull); - expect(addedScript!.source, 'alert("Hello")'); - }); - - testWidgets('displays list of added scripts', (tester) async { - final scripts = []; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: UserScriptTesterWidget( - onAddScript: (script) async { - scripts.add(script); - }, - onRemoveScript: (script) async {}, - scripts: scripts, - ), - ), - ), - ); - - // Add first script - await tester.enterText(find.byType(TextField), 'script 1'); - await tester.tap(find.widgetWithText(ElevatedButton, 'Add Script')); - await tester.pumpAndSettle(); - - // Should show in list - expect(find.textContaining('script 1'), findsOneWidget); - }); - - testWidgets('shows remove button for each script', (tester) async { - final script = UserScript( - source: 'console.log("test")', - injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START, - ); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: UserScriptTesterWidget( - onAddScript: (script) async {}, - onRemoveScript: (script) async {}, - scripts: [script], - ), - ), - ), - ); - - expect(find.byIcon(Icons.delete), findsOneWidget); - }); - - testWidgets('calls onRemoveScript when remove button is pressed', ( - tester, - ) async { - final script = UserScript( - source: 'console.log("test")', - injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START, - ); - - UserScript? removedScript; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: UserScriptTesterWidget( - onAddScript: (script) async {}, - onRemoveScript: (script) async { - removedScript = script; - }, - scripts: [script], - ), - ), - ), - ); - - await tester.tap(find.byIcon(Icons.delete)); - await tester.pumpAndSettle(); - - expect(removedScript, script); - }); - - testWidgets('clears form after adding script', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: UserScriptTesterWidget( - onAddScript: (script) async {}, - onRemoveScript: (script) async {}, - ), - ), - ), - ); - - await tester.enterText(find.byType(TextField), 'test code'); - await tester.pump(); - await tester.tap(find.widgetWithText(ElevatedButton, 'Add Script')); - await tester.pumpAndSettle(); - - final textField = tester.widget(find.byType(TextField)); - expect(textField.controller?.text, isEmpty); - }); - - testWidgets('displays script injection time', (tester) async { - final script = UserScript( - source: 'console.log("test")', - injectionTime: UserScriptInjectionTime.AT_DOCUMENT_END, - ); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: UserScriptTesterWidget( - onAddScript: (script) async {}, - onRemoveScript: (script) async {}, - scripts: [script], - ), - ), - ), - ); - - expect(find.text('AT_DOCUMENT_END'), findsOneWidget); - }); - - testWidgets('displays forMainFrameOnly status', (tester) async { - final script = UserScript( - source: 'console.log("test")', - injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START, - forMainFrameOnly: true, - ); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: UserScriptTesterWidget( - onAddScript: (script) async {}, - onRemoveScript: (script) async {}, - scripts: [script], - ), - ), - ), - ); - - expect(find.text('Main Frame Only'), findsWidgets); - }); - - testWidgets('shows empty state when no scripts', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: UserScriptTesterWidget( - onAddScript: (script) async {}, - onRemoveScript: (script) async {}, - scripts: [], - ), - ), - ), - ); - - expect(find.text('No user scripts added'), findsOneWidget); - }); - - testWidgets('injection time dropdown works', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: UserScriptTesterWidget( - onAddScript: (script) async {}, - onRemoveScript: (script) async {}, - ), - ), - ), - ); - - // Open dropdown - await tester.tap(find.byType(DropdownButton)); - await tester.pumpAndSettle(); - - // Should show both options - expect(find.text('AT_DOCUMENT_START').hitTestable(), findsOneWidget); - expect(find.text('AT_DOCUMENT_END').hitTestable(), findsOneWidget); - }); - }); -} diff --git a/flutter_inappwebview/example/test_assets/certificate.pfx b/flutter_inappwebview/example/test_assets/certificate.pfx deleted file mode 100755 index 0e68c6a65b..0000000000 Binary files a/flutter_inappwebview/example/test_assets/certificate.pfx and /dev/null differ diff --git a/flutter_inappwebview/example/test_assets/css/blue-body.css b/flutter_inappwebview/example/test_assets/css/blue-body.css deleted file mode 100644 index 4354204313..0000000000 --- a/flutter_inappwebview/example/test_assets/css/blue-body.css +++ /dev/null @@ -1,3 +0,0 @@ -body { - background-color: rgb(0, 0, 255); -} \ No newline at end of file diff --git a/flutter_inappwebview/example/test_assets/css/style.css b/flutter_inappwebview/example/test_assets/css/style.css deleted file mode 100755 index dd5c664fd9..0000000000 --- a/flutter_inappwebview/example/test_assets/css/style.css +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Globals - */ - -/* Links */ -a, -a:focus, -a:hover { - color: #fff; -} - -/* Custom default button */ -.btn-secondary, -.btn-secondary:hover, -.btn-secondary:focus { - color: #333; - text-shadow: none; /* Prevent inheritance from `body` */ - background-color: #fff; - border: .05rem solid #fff; -} - - -/* - * Base structure - */ - -html, -body { - height: 100%; - background-color: #333; -} - -body { - display: -ms-flexbox; - display: flex; - color: #fff; - text-shadow: 0 .05rem .1rem rgba(0, 0, 0, .5); - box-shadow: inset 0 0 5rem rgba(0, 0, 0, .5); -} - -.cover-container { - max-width: 42em; -} - - -/* - * Header - */ -.masthead { - margin-bottom: 2rem; -} - -.masthead-brand { - margin-bottom: 0; -} - -.nav-masthead .nav-link { - padding: .25rem 0; - font-weight: 700; - color: rgba(255, 255, 255, .5); - background-color: transparent; - border-bottom: .25rem solid transparent; -} - -.nav-masthead .nav-link:hover, -.nav-masthead .nav-link:focus { - border-bottom-color: rgba(255, 255, 255, .25); -} - -.nav-masthead .nav-link + .nav-link { - margin-left: 1rem; -} - -.nav-masthead .active { - color: #fff; - border-bottom-color: #fff; -} - -@media (min-width: 48em) { - .masthead-brand { - float: left; - } - .nav-masthead { - float: right; - } -} - - -/* - * Cover - */ -.cover { - padding: 0 1.5rem; -} -.cover .btn-lg { - padding: .75rem 1.25rem; - font-weight: 700; -} - - -/* - * Footer - */ -.mastfoot { - color: rgba(255, 255, 255, .5); -} \ No newline at end of file diff --git a/flutter_inappwebview/example/test_assets/favicon.ico b/flutter_inappwebview/example/test_assets/favicon.ico deleted file mode 100755 index e6adc1c6e7..0000000000 Binary files a/flutter_inappwebview/example/test_assets/favicon.ico and /dev/null differ diff --git a/flutter_inappwebview/example/test_assets/images/flutter-logo.jpg b/flutter_inappwebview/example/test_assets/images/flutter-logo.jpg deleted file mode 100644 index 6d17a4da4a..0000000000 Binary files a/flutter_inappwebview/example/test_assets/images/flutter-logo.jpg and /dev/null differ diff --git a/flutter_inappwebview/example/test_assets/images/flutter-logo.png b/flutter_inappwebview/example/test_assets/images/flutter-logo.png deleted file mode 100644 index e4cb3f825f..0000000000 Binary files a/flutter_inappwebview/example/test_assets/images/flutter-logo.png and /dev/null differ diff --git a/flutter_inappwebview/example/test_assets/images/flutter-logo.svg b/flutter_inappwebview/example/test_assets/images/flutter-logo.svg deleted file mode 100755 index 43f691bab8..0000000000 --- a/flutter_inappwebview/example/test_assets/images/flutter-logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/flutter_inappwebview/example/test_assets/in_app_webview_initial_file_test.html b/flutter_inappwebview/example/test_assets/in_app_webview_initial_file_test.html deleted file mode 100755 index 657877d776..0000000000 --- a/flutter_inappwebview/example/test_assets/in_app_webview_initial_file_test.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - InAppWebViewInitialFileTest - - - - - - -
-
-
-

InAppWebViewInitialFileTest

- -
-
- -
-

InAppWebViewInitialFileTest

- flutter logo -

- placeholder 100x50 -

- flutter_inappwebview -
-
- - \ No newline at end of file diff --git a/flutter_inappwebview/example/test_assets/in_app_webview_javascript_handler_test.html b/flutter_inappwebview/example/test_assets/in_app_webview_javascript_handler_test.html deleted file mode 100755 index 46fc3fd1e4..0000000000 --- a/flutter_inappwebview/example/test_assets/in_app_webview_javascript_handler_test.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - InAppWebViewJavaScriptHandlerTest - - -

InAppWebViewJavaScriptHandlerTest

- - - \ No newline at end of file diff --git a/flutter_inappwebview/example/test_assets/in_app_webview_on_console_message_test.html b/flutter_inappwebview/example/test_assets/in_app_webview_on_console_message_test.html deleted file mode 100755 index 1b5d1d55ea..0000000000 --- a/flutter_inappwebview/example/test_assets/in_app_webview_on_console_message_test.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - InAppWebViewOnConsoleMessageTest - - -

InAppWebViewOnConsoleMessageTest

- - - \ No newline at end of file diff --git a/flutter_inappwebview/example/test_assets/in_app_webview_on_create_window_test.html b/flutter_inappwebview/example/test_assets/in_app_webview_on_create_window_test.html deleted file mode 100755 index 87a1194f1e..0000000000 --- a/flutter_inappwebview/example/test_assets/in_app_webview_on_create_window_test.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - InAppWebViewOnCreateWindowTest - - -

InAppWebViewOnCreateWindowTest

- target blank - - - \ No newline at end of file diff --git a/flutter_inappwebview/example/test_assets/in_app_webview_on_js_before_unload.html b/flutter_inappwebview/example/test_assets/in_app_webview_on_js_before_unload.html deleted file mode 100755 index 9ce4114e51..0000000000 --- a/flutter_inappwebview/example/test_assets/in_app_webview_on_js_before_unload.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - InAppWebViewOnJsBeforeUnloadTest - - -

InAppWebViewOnJsBeforeUnloadTest

- - - \ No newline at end of file diff --git a/flutter_inappwebview/example/test_assets/in_app_webview_on_js_dialog_test.html b/flutter_inappwebview/example/test_assets/in_app_webview_on_js_dialog_test.html deleted file mode 100755 index 75b8d31f7c..0000000000 --- a/flutter_inappwebview/example/test_assets/in_app_webview_on_js_dialog_test.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - InAppWebViewOnJsDialogTest - - -

InAppWebViewOnJsDialogTest

- - - \ No newline at end of file diff --git a/flutter_inappwebview/example/test_assets/in_app_webview_on_load_resource_custom_scheme_test.html b/flutter_inappwebview/example/test_assets/in_app_webview_on_load_resource_custom_scheme_test.html deleted file mode 100755 index 56f060ff13..0000000000 --- a/flutter_inappwebview/example/test_assets/in_app_webview_on_load_resource_custom_scheme_test.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - InAppWebViewOnLoadResourceCustomSchemeTest - - -
-
-

InAppWebViewOnLoadResourceCustomSchemeTest

- flutter logo -
-
- - - \ No newline at end of file diff --git a/flutter_inappwebview/example/test_assets/in_app_webview_on_load_resource_test.html b/flutter_inappwebview/example/test_assets/in_app_webview_on_load_resource_test.html deleted file mode 100755 index d499cccc13..0000000000 --- a/flutter_inappwebview/example/test_assets/in_app_webview_on_load_resource_test.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - InAppWebViewOnLoadResourceTest - - - - -
-
-

InAppWebViewOnLoadResourceTest

- flutter logo -

- placeholder 100x50 -

-
-
- - - \ No newline at end of file diff --git a/flutter_inappwebview/example/test_assets/in_app_webview_on_navigation_state_change_test.html b/flutter_inappwebview/example/test_assets/in_app_webview_on_navigation_state_change_test.html deleted file mode 100755 index 711c614bcb..0000000000 --- a/flutter_inappwebview/example/test_assets/in_app_webview_on_navigation_state_change_test.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - InAppWebViewOnNavigationStateChangeTest - - - -

InAppWebViewOnNavigationStateChangeTest

- - - \ No newline at end of file diff --git a/flutter_inappwebview/example/test_assets/index.html b/flutter_inappwebview/example/test_assets/index.html deleted file mode 100755 index 157ce94d23..0000000000 --- a/flutter_inappwebview/example/test_assets/index.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - - Flutter InAppBrowser - - - - - - -
-
-
-

Flutter InAppBrowser

- -
-
- -
-

Inline WebView

- flutter logo -

Cover is a one-page template for building simple and beautiful home pages. Download, edit the text, and add your own fullscreen background photo to make it your own.

- - - - - - -

- placeholder 100x50 -

-
- - - - -
- - - - \ No newline at end of file diff --git a/flutter_inappwebview/example/test_assets/js/jquery-3.3.1.min.js b/flutter_inappwebview/example/test_assets/js/jquery-3.3.1.min.js deleted file mode 100644 index 49d1fcfbe2..0000000000 --- a/flutter_inappwebview/example/test_assets/js/jquery-3.3.1.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w(" - - -
-
-
-

Flutter InAppBrowser

- -
-
- -
-

Page 1

-

Cover is a one-page template for building simple and beautiful home pages. Download, edit the text, and add your own fullscreen background photo to make it your own.

-

- Learn more -

-
- - -
- - \ No newline at end of file diff --git a/flutter_inappwebview/example/test_assets/page-2.html b/flutter_inappwebview/example/test_assets/page-2.html deleted file mode 100755 index aa6d2c0fff..0000000000 --- a/flutter_inappwebview/example/test_assets/page-2.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - Flutter InAppBrowser - - - - - -
-
-
-

Flutter InAppBrowser

- -
-
- -
-

Page 2

-

Cover is a one-page template for building simple and beautiful home pages. Download, edit the text, and add your own fullscreen background photo to make it your own.

-

- Learn more -

-
- - -
- - \ No newline at end of file diff --git a/flutter_inappwebview/example/test_assets/sample_audio.ogg b/flutter_inappwebview/example/test_assets/sample_audio.ogg deleted file mode 100644 index 27e1710427..0000000000 Binary files a/flutter_inappwebview/example/test_assets/sample_audio.ogg and /dev/null differ diff --git a/flutter_inappwebview/example/test_assets/sample_video.mp4 b/flutter_inappwebview/example/test_assets/sample_video.mp4 deleted file mode 100644 index a203d0cdf1..0000000000 Binary files a/flutter_inappwebview/example/test_assets/sample_video.mp4 and /dev/null differ diff --git a/flutter_inappwebview/example/test_assets/website/index.html b/flutter_inappwebview/example/test_assets/website/index.html deleted file mode 100644 index f47d4e711a..0000000000 --- a/flutter_inappwebview/example/test_assets/website/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - WebViewAssetLoader - - -

WebViewAssetLoader

-

This is a test.

- - \ No newline at end of file diff --git a/flutter_inappwebview/example/test_driver/integration_test.dart b/flutter_inappwebview/example/test_driver/integration_test.dart deleted file mode 100644 index c75add8113..0000000000 --- a/flutter_inappwebview/example/test_driver/integration_test.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'package:flutter_driver/flutter_driver.dart'; - -Future main() async { - final FlutterDriver driver = await FlutterDriver.connect(); - final String data = - await driver.requestData(null, timeout: const Duration(minutes: 1)); - await driver.close(); - final Map result = jsonDecode(data); - exit(result['result'] == 'true' ? 0 : 1); -} diff --git a/flutter_inappwebview/example/web/favicon.png b/flutter_inappwebview/example/web/favicon.png deleted file mode 100644 index 8aaa46ac1a..0000000000 Binary files a/flutter_inappwebview/example/web/favicon.png and /dev/null differ diff --git a/flutter_inappwebview/example/web/heavy-page.html b/flutter_inappwebview/example/web/heavy-page.html deleted file mode 100644 index 2abc8c9093..0000000000 --- a/flutter_inappwebview/example/web/heavy-page.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - heavy page - - - -

Heavy Page

- Go to page 1 -
-

Loading image...

- Loading failed - - diff --git a/flutter_inappwebview/example/web/icons/Icon-192.png b/flutter_inappwebview/example/web/icons/Icon-192.png deleted file mode 100644 index b749bfef07..0000000000 Binary files a/flutter_inappwebview/example/web/icons/Icon-192.png and /dev/null differ diff --git a/flutter_inappwebview/example/web/icons/Icon-512.png b/flutter_inappwebview/example/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48dff..0000000000 Binary files a/flutter_inappwebview/example/web/icons/Icon-512.png and /dev/null differ diff --git a/flutter_inappwebview/example/web/icons/Icon-maskable-192.png b/flutter_inappwebview/example/web/icons/Icon-maskable-192.png deleted file mode 100644 index eb9b4d76e5..0000000000 Binary files a/flutter_inappwebview/example/web/icons/Icon-maskable-192.png and /dev/null differ diff --git a/flutter_inappwebview/example/web/icons/Icon-maskable-512.png b/flutter_inappwebview/example/web/icons/Icon-maskable-512.png deleted file mode 100644 index d69c56691f..0000000000 Binary files a/flutter_inappwebview/example/web/icons/Icon-maskable-512.png and /dev/null differ diff --git a/flutter_inappwebview/example/web/index.html b/flutter_inappwebview/example/web/index.html deleted file mode 100644 index 0e7eaf616e..0000000000 --- a/flutter_inappwebview/example/web/index.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - flutter_inappwebview_example - - - - - - - - - - diff --git a/flutter_inappwebview/example/web/manifest.json b/flutter_inappwebview/example/web/manifest.json deleted file mode 100644 index 13c8b581c8..0000000000 --- a/flutter_inappwebview/example/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "flutter_inappwebview_example", - "short_name": "flutter_inappwebview_example", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "Demonstrates how to use the flutter_inappwebview plugin.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} diff --git a/flutter_inappwebview/example/web/page-2.html b/flutter_inappwebview/example/web/page-2.html deleted file mode 100644 index 281a589b12..0000000000 --- a/flutter_inappwebview/example/web/page-2.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - page 2 - - - -

Simple Page 2

- Go to page 1 -
- Go to heavy-page -
- - - diff --git a/flutter_inappwebview/example/web/page.html b/flutter_inappwebview/example/web/page.html deleted file mode 100644 index c40acd826a..0000000000 --- a/flutter_inappwebview/example/web/page.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - page - - - -

Simple Page 1

- Go to page 2 -
- Go to heavy-page - - - diff --git a/flutter_inappwebview/example/windows/.gitignore b/flutter_inappwebview/example/windows/.gitignore deleted file mode 100644 index 5d57396c84..0000000000 --- a/flutter_inappwebview/example/windows/.gitignore +++ /dev/null @@ -1,19 +0,0 @@ -flutter/ephemeral/ - -# Visual Studio user-specific files. -*.suo -*.user -*.userosscache -*.sln.docstates - -# Visual Studio build-related files. -x64/ -x86/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -cmake-build-* \ No newline at end of file diff --git a/flutter_inappwebview/example/windows/CMakeLists.txt b/flutter_inappwebview/example/windows/CMakeLists.txt deleted file mode 100644 index d960948af6..0000000000 --- a/flutter_inappwebview/example/windows/CMakeLists.txt +++ /dev/null @@ -1,108 +0,0 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.14) -project(example LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "example") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(VERSION 3.14...3.25) - -# Define build configuration option. -get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(IS_MULTICONFIG) - set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" - CACHE STRING "" FORCE) -else() - if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") - endif() -endif() -# Define settings for the Profile build mode. -set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") -set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") -set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") -set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") - -# Use Unicode for all projects. -add_definitions(-DUNICODE -D_UNICODE) - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_17) - target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") - target_compile_options(${TARGET} PRIVATE /EHsc) - target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") - target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# Application build; see runner/CMakeLists.txt. -add_subdirectory("runner") - - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# Support files are copied into place next to the executable, so that it can -# run in place. This is done instead of making a separate bundle (as on Linux) -# so that building and running from within Visual Studio will work. -set(BUILD_BUNDLE_DIR "$") -# Make the "install" step default, as it's required to run. -set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -if(PLUGIN_BUNDLED_LIBRARIES) - install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() - -# Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") -install(DIRECTORY "${NATIVE_ASSETS_DIR}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - CONFIGURATIONS Profile;Release - COMPONENT Runtime) diff --git a/flutter_inappwebview/example/windows/flutter/CMakeLists.txt b/flutter_inappwebview/example/windows/flutter/CMakeLists.txt deleted file mode 100644 index 903f4899d6..0000000000 --- a/flutter_inappwebview/example/windows/flutter/CMakeLists.txt +++ /dev/null @@ -1,109 +0,0 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.14) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. -set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") - -# Set fallback configurations for older versions of the flutter tool. -if (NOT DEFINED FLUTTER_TARGET_PLATFORM) - set(FLUTTER_TARGET_PLATFORM "windows-x64") -endif() - -# === Flutter Library === -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "flutter_export.h" - "flutter_windows.h" - "flutter_messenger.h" - "flutter_plugin_registrar.h" - "flutter_texture_registrar.h" -) -list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") -add_dependencies(flutter flutter_assemble) - -# === Wrapper === -list(APPEND CPP_WRAPPER_SOURCES_CORE - "core_implementations.cc" - "standard_codec.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_PLUGIN - "plugin_registrar.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_APP - "flutter_engine.cc" - "flutter_view_controller.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") - -# Wrapper sources needed for a plugin. -add_library(flutter_wrapper_plugin STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} -) -apply_standard_settings(flutter_wrapper_plugin) -set_target_properties(flutter_wrapper_plugin PROPERTIES - POSITION_INDEPENDENT_CODE ON) -set_target_properties(flutter_wrapper_plugin PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) -target_include_directories(flutter_wrapper_plugin PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_plugin flutter_assemble) - -# Wrapper sources needed for the runner. -add_library(flutter_wrapper_app STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_APP} -) -apply_standard_settings(flutter_wrapper_app) -target_link_libraries(flutter_wrapper_app PUBLIC flutter) -target_include_directories(flutter_wrapper_app PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_app flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") -set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} - ${PHONY_OUTPUT} - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - ${FLUTTER_TARGET_PLATFORM} $ - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} -) diff --git a/flutter_inappwebview/example/windows/flutter/generated_plugin_registrant.cc b/flutter_inappwebview/example/windows/flutter/generated_plugin_registrant.cc deleted file mode 100644 index 031b869576..0000000000 --- a/flutter_inappwebview/example/windows/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,20 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - -#include -#include -#include - -void RegisterPlugins(flutter::PluginRegistry* registry) { - FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi")); - PermissionHandlerWindowsPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); - UrlLauncherWindowsRegisterWithRegistrar( - registry->GetRegistrarForPlugin("UrlLauncherWindows")); -} diff --git a/flutter_inappwebview/example/windows/flutter/generated_plugin_registrant.h b/flutter_inappwebview/example/windows/flutter/generated_plugin_registrant.h deleted file mode 100644 index dc139d85a9..0000000000 --- a/flutter_inappwebview/example/windows/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void RegisterPlugins(flutter::PluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/flutter_inappwebview/example/windows/flutter/generated_plugins.cmake b/flutter_inappwebview/example/windows/flutter/generated_plugins.cmake deleted file mode 100644 index 997d0b8030..0000000000 --- a/flutter_inappwebview/example/windows/flutter/generated_plugins.cmake +++ /dev/null @@ -1,26 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST - flutter_inappwebview_windows - permission_handler_windows - url_launcher_windows -) - -list(APPEND FLUTTER_FFI_PLUGIN_LIST -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) - -foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) -endforeach(ffi_plugin) diff --git a/flutter_inappwebview/example/windows/runner/CMakeLists.txt b/flutter_inappwebview/example/windows/runner/CMakeLists.txt deleted file mode 100644 index 394917c053..0000000000 --- a/flutter_inappwebview/example/windows/runner/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -project(runner LANGUAGES CXX) - -# Define the application target. To change its name, change BINARY_NAME in the -# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer -# work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} WIN32 - "flutter_window.cpp" - "main.cpp" - "utils.cpp" - "win32_window.cpp" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" - "Runner.rc" - "runner.exe.manifest" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add preprocessor definitions for the build version. -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") - -# Disable Windows macros that collide with C++ standard library functions. -target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") - -# Add dependency libraries and include directories. Add any application-specific -# dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) -target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") -target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/flutter_inappwebview/example/windows/runner/Runner.rc b/flutter_inappwebview/example/windows/runner/Runner.rc deleted file mode 100644 index 302ceb4ba3..0000000000 --- a/flutter_inappwebview/example/windows/runner/Runner.rc +++ /dev/null @@ -1,121 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#pragma code_page(65001) -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_APP_ICON ICON "resources\\app_icon.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) -#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD -#else -#define VERSION_AS_NUMBER 1,0,0,0 -#endif - -#if defined(FLUTTER_VERSION) -#define VERSION_AS_STRING FLUTTER_VERSION -#else -#define VERSION_AS_STRING "1.0.0" -#endif - -VS_VERSION_INFO VERSIONINFO - FILEVERSION VERSION_AS_NUMBER - PRODUCTVERSION VERSION_AS_NUMBER - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS__WINDOWS32 - FILETYPE VFT_APP - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904e4" - BEGIN - VALUE "CompanyName", "com.pichillilorenzo" "\0" - VALUE "FileDescription", "example" "\0" - VALUE "FileVersion", VERSION_AS_STRING "\0" - VALUE "InternalName", "example" "\0" - VALUE "LegalCopyright", "Copyright (C) 2023 com.pichillilorenzo. All rights reserved." "\0" - VALUE "OriginalFilename", "example.exe" "\0" - VALUE "ProductName", "example" "\0" - VALUE "ProductVersion", VERSION_AS_STRING "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1252 - END -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED diff --git a/flutter_inappwebview/example/windows/runner/flutter_window.cpp b/flutter_inappwebview/example/windows/runner/flutter_window.cpp deleted file mode 100644 index 955ee3038f..0000000000 --- a/flutter_inappwebview/example/windows/runner/flutter_window.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "flutter_window.h" - -#include - -#include "flutter/generated_plugin_registrant.h" - -FlutterWindow::FlutterWindow(const flutter::DartProject& project) - : project_(project) {} - -FlutterWindow::~FlutterWindow() {} - -bool FlutterWindow::OnCreate() { - if (!Win32Window::OnCreate()) { - return false; - } - - RECT frame = GetClientArea(); - - // The size here must match the window dimensions to avoid unnecessary surface - // creation / destruction in the startup path. - flutter_controller_ = std::make_unique( - frame.right - frame.left, frame.bottom - frame.top, project_); - // Ensure that basic setup of the controller was successful. - if (!flutter_controller_->engine() || !flutter_controller_->view()) { - return false; - } - RegisterPlugins(flutter_controller_->engine()); - SetChildContent(flutter_controller_->view()->GetNativeWindow()); - - flutter_controller_->engine()->SetNextFrameCallback([&]() { - this->Show(); - }); - - // Flutter can complete the first frame before the "show window" callback is - // registered. The following call ensures a frame is pending to ensure the - // window is shown. It is a no-op if the first frame hasn't completed yet. - flutter_controller_->ForceRedraw(); - - return true; -} - -void FlutterWindow::OnDestroy() { - if (flutter_controller_) { - flutter_controller_ = nullptr; - } - - Win32Window::OnDestroy(); -} - -LRESULT -FlutterWindow::MessageHandler(HWND hwnd, UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - // Give Flutter, including plugins, an opportunity to handle window messages. - if (flutter_controller_) { - std::optional result = - flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, - lparam); - if (result) { - return *result; - } - } - - switch (message) { - case WM_FONTCHANGE: - flutter_controller_->engine()->ReloadSystemFonts(); - break; - } - - return Win32Window::MessageHandler(hwnd, message, wparam, lparam); -} diff --git a/flutter_inappwebview/example/windows/runner/flutter_window.h b/flutter_inappwebview/example/windows/runner/flutter_window.h deleted file mode 100644 index 6da0652f05..0000000000 --- a/flutter_inappwebview/example/windows/runner/flutter_window.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef RUNNER_FLUTTER_WINDOW_H_ -#define RUNNER_FLUTTER_WINDOW_H_ - -#include -#include - -#include - -#include "win32_window.h" - -// A window that does nothing but host a Flutter view. -class FlutterWindow : public Win32Window { - public: - // Creates a new FlutterWindow hosting a Flutter view running |project|. - explicit FlutterWindow(const flutter::DartProject& project); - virtual ~FlutterWindow(); - - protected: - // Win32Window: - bool OnCreate() override; - void OnDestroy() override; - LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, - LPARAM const lparam) noexcept override; - - private: - // The project to run. - flutter::DartProject project_; - - // The Flutter instance hosted by this window. - std::unique_ptr flutter_controller_; -}; - -#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/flutter_inappwebview/example/windows/runner/main.cpp b/flutter_inappwebview/example/windows/runner/main.cpp deleted file mode 100644 index a61bf80d31..0000000000 --- a/flutter_inappwebview/example/windows/runner/main.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include - -#include "flutter_window.h" -#include "utils.h" - -int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, - _In_ wchar_t *command_line, _In_ int show_command) { - // Attach to console when present (e.g., 'flutter run') or create a - // new console when running with a debugger. - if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { - CreateAndAttachConsole(); - } - - // Initialize COM, so that it is available for use in the library and/or - // plugins. - ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - - flutter::DartProject project(L"data"); - - std::vector command_line_arguments = - GetCommandLineArguments(); - - project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); - - FlutterWindow window(project); - Win32Window::Point origin(10, 10); - Win32Window::Size size(1280, 720); - if (!window.Create(L"example", origin, size)) { - return EXIT_FAILURE; - } - window.SetQuitOnClose(true); - - ::MSG msg; - while (::GetMessage(&msg, nullptr, 0, 0)) { - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); - } - - ::CoUninitialize(); - return EXIT_SUCCESS; -} diff --git a/flutter_inappwebview/example/windows/runner/resource.h b/flutter_inappwebview/example/windows/runner/resource.h deleted file mode 100644 index 66a65d1e4a..0000000000 --- a/flutter_inappwebview/example/windows/runner/resource.h +++ /dev/null @@ -1,16 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by Runner.rc -// -#define IDI_APP_ICON 101 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/flutter_inappwebview/example/windows/runner/resources/app_icon.ico b/flutter_inappwebview/example/windows/runner/resources/app_icon.ico deleted file mode 100644 index c04e20caf6..0000000000 Binary files a/flutter_inappwebview/example/windows/runner/resources/app_icon.ico and /dev/null differ diff --git a/flutter_inappwebview/example/windows/runner/runner.exe.manifest b/flutter_inappwebview/example/windows/runner/runner.exe.manifest deleted file mode 100644 index a42ea7687c..0000000000 --- a/flutter_inappwebview/example/windows/runner/runner.exe.manifest +++ /dev/null @@ -1,20 +0,0 @@ - - - - - PerMonitorV2 - - - - - - - - - - - - - - - diff --git a/flutter_inappwebview/example/windows/runner/utils.cpp b/flutter_inappwebview/example/windows/runner/utils.cpp deleted file mode 100644 index b2b08734db..0000000000 --- a/flutter_inappwebview/example/windows/runner/utils.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "utils.h" - -#include -#include -#include -#include - -#include - -void CreateAndAttachConsole() { - if (::AllocConsole()) { - FILE *unused; - if (freopen_s(&unused, "CONOUT$", "w", stdout)) { - _dup2(_fileno(stdout), 1); - } - if (freopen_s(&unused, "CONOUT$", "w", stderr)) { - _dup2(_fileno(stdout), 2); - } - std::ios::sync_with_stdio(); - FlutterDesktopResyncOutputStreams(); - } -} - -std::vector GetCommandLineArguments() { - // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. - int argc; - wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); - if (argv == nullptr) { - return std::vector(); - } - - std::vector command_line_arguments; - - // Skip the first argument as it's the binary name. - for (int i = 1; i < argc; i++) { - command_line_arguments.push_back(Utf8FromUtf16(argv[i])); - } - - ::LocalFree(argv); - - return command_line_arguments; -} - -std::string Utf8FromUtf16(const wchar_t* utf16_string) { - if (utf16_string == nullptr) { - return std::string(); - } - int target_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - -1, nullptr, 0, nullptr, nullptr) - -1; // remove the trailing null character - int input_length = (int)wcslen(utf16_string); - std::string utf8_string; - if (target_length <= 0 || target_length > utf8_string.max_size()) { - return utf8_string; - } - utf8_string.resize(target_length); - int converted_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - input_length, utf8_string.data(), target_length, nullptr, nullptr); - if (converted_length == 0) { - return std::string(); - } - return utf8_string; -} diff --git a/flutter_inappwebview/example/windows/runner/utils.h b/flutter_inappwebview/example/windows/runner/utils.h deleted file mode 100644 index 3879d54755..0000000000 --- a/flutter_inappwebview/example/windows/runner/utils.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef RUNNER_UTILS_H_ -#define RUNNER_UTILS_H_ - -#include -#include - -// Creates a console for the process, and redirects stdout and stderr to -// it for both the runner and the Flutter library. -void CreateAndAttachConsole(); - -// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string -// encoded in UTF-8. Returns an empty std::string on failure. -std::string Utf8FromUtf16(const wchar_t* utf16_string); - -// Gets the command line arguments passed in as a std::vector, -// encoded in UTF-8. Returns an empty std::vector on failure. -std::vector GetCommandLineArguments(); - -#endif // RUNNER_UTILS_H_ diff --git a/flutter_inappwebview/example/windows/runner/win32_window.cpp b/flutter_inappwebview/example/windows/runner/win32_window.cpp deleted file mode 100644 index 786879fac0..0000000000 --- a/flutter_inappwebview/example/windows/runner/win32_window.cpp +++ /dev/null @@ -1,309 +0,0 @@ -#include "win32_window.h" - -#include -#include - -#include "resource.h" - -namespace { - - /// Window attribute that enables dark mode window decorations. - /// - /// Redefined in case the developer's machine has a Windows SDK older than - /// version 10.0.22000.0. - /// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute -#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE -#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 -#endif - - constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; - - /// Registry key for app theme preference. - /// - /// A value of 0 indicates apps should use dark mode. A non-zero or missing - /// value indicates apps should use light mode. - constexpr const wchar_t kGetPreferredBrightnessRegKey[] = - L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; - constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; - - // The number of Win32Window objects that currently exist. - static int g_active_window_count = 0; - - using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); - - // Scale helper to convert logical scaler values to physical using passed in - // scale factor - int Scale(int source, double scale_factor) - { - return static_cast(source * scale_factor); - } - - // Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. - // This API is only needed for PerMonitor V1 awareness mode. - void EnableFullDpiSupportIfAvailable(HWND hwnd) - { - HMODULE user32_module = LoadLibraryA("User32.dll"); - if (!user32_module) { - return; - } - auto enable_non_client_dpi_scaling = - reinterpret_cast( - GetProcAddress(user32_module, "EnableNonClientDpiScaling")); - if (enable_non_client_dpi_scaling != nullptr) { - enable_non_client_dpi_scaling(hwnd); - } - FreeLibrary(user32_module); - } - -} // namespace - -// Manages the Win32Window's window class registration. -class WindowClassRegistrar { -public: - ~WindowClassRegistrar() = default; - - // Returns the singleton registrar instance. - static WindowClassRegistrar* GetInstance() - { - if (!instance_) { - instance_ = new WindowClassRegistrar(); - } - return instance_; - } - - // Returns the name of the window class, registering the class if it hasn't - // previously been registered. - const wchar_t* GetWindowClass(); - - // Unregisters the window class. Should only be called if there are no - // instances of the window. - void UnregisterWindowClass(); - -private: - WindowClassRegistrar() = default; - - static WindowClassRegistrar* instance_; - - bool class_registered_ = false; -}; - -WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; - -const wchar_t* WindowClassRegistrar::GetWindowClass() -{ - if (!class_registered_) { - WNDCLASS window_class{}; - window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); - window_class.lpszClassName = kWindowClassName; - window_class.style = CS_HREDRAW | CS_VREDRAW; - window_class.cbClsExtra = 0; - window_class.cbWndExtra = 0; - window_class.hInstance = GetModuleHandle(nullptr); - window_class.hIcon = - LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); - window_class.hbrBackground = 0; - window_class.lpszMenuName = nullptr; - window_class.lpfnWndProc = Win32Window::WndProc; - RegisterClass(&window_class); - class_registered_ = true; - } - return kWindowClassName; -} - -void WindowClassRegistrar::UnregisterWindowClass() -{ - UnregisterClass(kWindowClassName, nullptr); - class_registered_ = false; -} - -Win32Window::Win32Window() -{ - ++g_active_window_count; -} - -Win32Window::~Win32Window() -{ - --g_active_window_count; - Destroy(); -} - -bool Win32Window::Create(const std::wstring& title, - const Point& origin, - const Size& size) -{ - Destroy(); - - const wchar_t* window_class = - WindowClassRegistrar::GetInstance()->GetWindowClass(); - - const POINT target_point = { static_cast(origin.x), - static_cast(origin.y) }; - HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); - UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); - double scale_factor = dpi / 96.0; - - HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW, - Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), - Scale(size.width, scale_factor), Scale(size.height, scale_factor), - nullptr, nullptr, GetModuleHandle(nullptr), this); - - if (!window) { - return false; - } - - UpdateTheme(window); - - return OnCreate(); -} - -bool Win32Window::Show() -{ - return ShowWindow(window_handle_, SW_SHOWNORMAL); -} - -// static -LRESULT CALLBACK Win32Window::WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept -{ - if (message == WM_NCCREATE) { - auto window_struct = reinterpret_cast(lparam); - SetWindowLongPtr(window, GWLP_USERDATA, - reinterpret_cast(window_struct->lpCreateParams)); - - auto that = static_cast(window_struct->lpCreateParams); - EnableFullDpiSupportIfAvailable(window); - that->window_handle_ = window; - } - else if (Win32Window* that = GetThisFromHandle(window)) { - return that->MessageHandler(window, message, wparam, lparam); - } - - return DefWindowProc(window, message, wparam, lparam); -} - -LRESULT -Win32Window::MessageHandler(HWND hwnd, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept -{ - switch (message) { - case WM_DESTROY: - window_handle_ = nullptr; - Destroy(); - if (quit_on_close_) { - PostQuitMessage(0); - } - return 0; - - case WM_DPICHANGED: { - auto newRectSize = reinterpret_cast(lparam); - LONG newWidth = newRectSize->right - newRectSize->left; - LONG newHeight = newRectSize->bottom - newRectSize->top; - - SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, - newHeight, SWP_NOZORDER | SWP_NOACTIVATE); - - return 0; - } - case WM_SIZE: { - RECT rect = GetClientArea(); - if (child_content_ != nullptr) { - // Size and position the child window. - MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top, TRUE); - } - return 0; - } - - case WM_ACTIVATE: - if (child_content_ != nullptr) { - SetFocus(child_content_); - } - return 0; - - case WM_DWMCOLORIZATIONCOLORCHANGED: - UpdateTheme(hwnd); - return 0; - } - - return DefWindowProc(window_handle_, message, wparam, lparam); -} - -void Win32Window::Destroy() -{ - OnDestroy(); - - if (window_handle_) { - DestroyWindow(window_handle_); - window_handle_ = nullptr; - } - if (g_active_window_count == 0) { - WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); - } -} - -Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept -{ - return reinterpret_cast( - GetWindowLongPtr(window, GWLP_USERDATA)); -} - -void Win32Window::SetChildContent(HWND content) -{ - child_content_ = content; - SetParent(content, window_handle_); - RECT frame = GetClientArea(); - - MoveWindow(content, frame.left, frame.top, frame.right - frame.left, - frame.bottom - frame.top, true); - - SetFocus(child_content_); -} - -RECT Win32Window::GetClientArea() -{ - RECT frame; - GetClientRect(window_handle_, &frame); - return frame; -} - -HWND Win32Window::GetHandle() -{ - return window_handle_; -} - -void Win32Window::SetQuitOnClose(bool quit_on_close) -{ - quit_on_close_ = quit_on_close; -} - -bool Win32Window::OnCreate() -{ - // No-op; provided for subclasses. - return true; -} - -void Win32Window::OnDestroy() -{ - // No-op; provided for subclasses. -} - -void Win32Window::UpdateTheme(HWND const window) -{ - DWORD light_mode; - DWORD light_mode_size = sizeof(light_mode); - LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, - kGetPreferredBrightnessRegValue, - RRF_RT_REG_DWORD, nullptr, &light_mode, - &light_mode_size); - - if (result == ERROR_SUCCESS) { - BOOL enable_dark_mode = light_mode == 0; - DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, - &enable_dark_mode, sizeof(enable_dark_mode)); - } -} diff --git a/flutter_inappwebview/example/windows/runner/win32_window.h b/flutter_inappwebview/example/windows/runner/win32_window.h deleted file mode 100644 index e901dde684..0000000000 --- a/flutter_inappwebview/example/windows/runner/win32_window.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef RUNNER_WIN32_WINDOW_H_ -#define RUNNER_WIN32_WINDOW_H_ - -#include - -#include -#include -#include - -// A class abstraction for a high DPI-aware Win32 Window. Intended to be -// inherited from by classes that wish to specialize with custom -// rendering and input handling -class Win32Window { - public: - struct Point { - unsigned int x; - unsigned int y; - Point(unsigned int x, unsigned int y) : x(x), y(y) {} - }; - - struct Size { - unsigned int width; - unsigned int height; - Size(unsigned int width, unsigned int height) - : width(width), height(height) {} - }; - - Win32Window(); - virtual ~Win32Window(); - - // Creates a win32 window with |title| that is positioned and sized using - // |origin| and |size|. New windows are created on the default monitor. Window - // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size this function will scale the inputted width and height as - // as appropriate for the default monitor. The window is invisible until - // |Show| is called. Returns true if the window was created successfully. - bool Create(const std::wstring& title, const Point& origin, const Size& size); - - // Show the current window. Returns true if the window was successfully shown. - bool Show(); - - // Release OS resources associated with window. - void Destroy(); - - // Inserts |content| into the window tree. - void SetChildContent(HWND content); - - // Returns the backing Window handle to enable clients to set icon and other - // window properties. Returns nullptr if the window has been destroyed. - HWND GetHandle(); - - // If true, closing this window will quit the application. - void SetQuitOnClose(bool quit_on_close); - - // Return a RECT representing the bounds of the current client area. - RECT GetClientArea(); - - protected: - // Processes and route salient window messages for mouse handling, - // size change and DPI. Delegates handling of these to member overloads that - // inheriting classes can handle. - virtual LRESULT MessageHandler(HWND window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Called when CreateAndShow is called, allowing subclass window-related - // setup. Subclasses should return false if setup fails. - virtual bool OnCreate(); - - // Called when Destroy is called. - virtual void OnDestroy(); - - private: - friend class WindowClassRegistrar; - - // OS callback called by message pump. Handles the WM_NCCREATE message which - // is passed when the non-client area is being created and enables automatic - // non-client DPI scaling so that the non-client area automatically - // responds to changes in DPI. All other messages are handled by - // MessageHandler. - static LRESULT CALLBACK WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Retrieves a class instance pointer for |window| - static Win32Window* GetThisFromHandle(HWND const window) noexcept; - - // Update the window frame's theme to match the system theme. - static void UpdateTheme(HWND const window); - - bool quit_on_close_ = false; - - // window handle for top level window. - HWND window_handle_ = nullptr; - - // window handle for hosted content. - HWND child_content_ = nullptr; -}; - -#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/flutter_inappwebview/lib/assets/t_rex_runner/t-rex.css b/flutter_inappwebview/lib/assets/t_rex_runner/t-rex.css deleted file mode 100755 index 697612b856..0000000000 --- a/flutter_inappwebview/lib/assets/t_rex_runner/t-rex.css +++ /dev/null @@ -1,59 +0,0 @@ -#main-frame-error { - box-sizing: border-box; - padding: 0 10%; - font-size: 1em; - line-height: 1.55; - margin: 0 auto; - max-width: 600px; - padding-top: 100px; - width: 100%; -} -#main-content { - font-size: 1em; - line-height: 1.55; - margin: 0 auto; - max-width: 600px; - padding-top: 100px; - width: 100%; -} -#t-rex-icon { - font-size: 1em; - line-height: 1.55; - background-repeat: no-repeat; - background-size: 100%; - height: 72px; - margin: 0 0 40px; - width: 72px; - display: inline-block; - content: -webkit-image-set( - url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABIAQMAAABvIyEEAAAABlBMVEUAAABTU1OoaSf/AAAAAXRSTlMAQObYZgAAAGxJREFUeF7tyMEJwkAQRuFf5ipMKxYQiJ3Z2nSwrWwBA0+DQZcdxEOueaePp9+dQZFB7GpUcURSVU66yVNFj6LFICatThZB6r/ko/pbRpUgilY0Cbw5sNmb9txGXUKyuH7eV25x39DtJXUNPQGJtWFV+BT/QAAAAABJRU5ErkJggg==) - 1x, - url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJAAAACQBAMAAAAVaP+LAAAAGFBMVEUAAABTU1NNTU1TU1NPT09SUlJSUlJTU1O8B7DEAAAAB3RSTlMAoArVKvVgBuEdKgAAAJ1JREFUeF7t1TEOwyAMQNG0Q6/UE+RMXD9d/tC6womIFSL9P+MnAYOXeTIzMzMzMzMzaz8J9Ri6HoITmuHXhISE8nEh9yxDh55aCEUoTGbbQwjqHwIkRAEiIaG0+0AA9VBMaE89Rogeoww936MQrWdBr4GN/z0IAdQ6nQ/FIpRXDwHcA+JIJcQowQAlFUA0MfQpXLlVQfkzR4igS6ENjknm/wiaGhsAAAAASUVORK5CYII=) - 2x - ); - position: relative; - visibility: hidden; -} -#offline-resources { - display: none; -} -#main-frame-error > .runner-container { - height: 150px; - max-width: 600px; - overflow: hidden; - position: absolute; - top: 35px; - width: 44px; -} -#main-frame-error > .controller { - background: rgba(247, 247, 247, 0.1); - height: 100vh; - left: 0; - position: absolute; - top: 0; - width: 100vw; - z-index: 9; -} -#main-frame-error .hidden { - display: none; -} diff --git a/flutter_inappwebview/lib/assets/t_rex_runner/t-rex.html b/flutter_inappwebview/lib/assets/t_rex_runner/t-rex.html deleted file mode 100755 index 5ca017893b..0000000000 --- a/flutter_inappwebview/lib/assets/t_rex_runner/t-rex.html +++ /dev/null @@ -1,16 +0,0 @@ -
-
-
-
-
- - - -
-
- - \ No newline at end of file diff --git a/flutter_inappwebview/lib/flutter_inappwebview.dart b/flutter_inappwebview/lib/flutter_inappwebview.dart deleted file mode 100755 index b796ace9d6..0000000000 --- a/flutter_inappwebview/lib/flutter_inappwebview.dart +++ /dev/null @@ -1,36 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * -*/ - -library flutter_inappwebview; - -export 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart' - hide - ChannelController, - InternalChannelController, - InternalInAppWebViewKeepAlive, - IdGenerator, - Color_, - Util, - UtilColor, - HexColor, - MapSize, - MapEdgeInsets; -export 'src/main.dart'; diff --git a/flutter_inappwebview/lib/src/chrome_safari_browser/chrome_safari_browser.dart b/flutter_inappwebview/lib/src/chrome_safari_browser/chrome_safari_browser.dart deleted file mode 100755 index a58221c1bd..0000000000 --- a/flutter_inappwebview/lib/src/chrome_safari_browser/chrome_safari_browser.dart +++ /dev/null @@ -1,281 +0,0 @@ -import 'dart:async'; -import 'dart:typed_data'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.supported_platforms} -class ChromeSafariBrowser implements PlatformChromeSafariBrowserEvents { - ///Constructs a [ChromeSafariBrowser]. - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.supported_platforms} - ChromeSafariBrowser() - : this.fromPlatformCreationParams( - PlatformChromeSafariBrowserCreationParams(), - ); - - /// Constructs a [ChromeSafariBrowser] from creation params for a specific - /// platform. - ChromeSafariBrowser.fromPlatformCreationParams( - PlatformChromeSafariBrowserCreationParams params, - ) : this.fromPlatform(PlatformChromeSafariBrowser(params)); - - /// Constructs a [ChromeSafariBrowser] from a specific platform - /// implementation. - ChromeSafariBrowser.fromPlatform(this.platform) { - this.platform.eventHandler = this; - } - - /// Implementation of [PlatformChromeSafariBrowser] for the current platform. - final PlatformChromeSafariBrowser platform; - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.id} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.id.supported_platforms} - String get id => platform.id; - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.open} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.open.supported_platforms} - Future open({ - WebUri? url, - Map? headers, - List? otherLikelyURLs, - WebUri? referrer, - @Deprecated('Use settings instead') - // ignore: deprecated_member_use_from_same_package - ChromeSafariBrowserClassOptions? options, - ChromeSafariBrowserSettings? settings, - }) { - this.platform.eventHandler = this; - return platform.open( - url: url, - headers: headers, - otherLikelyURLs: otherLikelyURLs, - options: options, - settings: settings, - ); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.launchUrl} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.launchUrl.supported_platforms} - Future launchUrl({ - required WebUri url, - Map? headers, - List? otherLikelyURLs, - WebUri? referrer, - }) => platform.launchUrl( - url: url, - headers: headers, - otherLikelyURLs: otherLikelyURLs, - referrer: referrer, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.mayLaunchUrl} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.mayLaunchUrl.supported_platforms} - Future mayLaunchUrl({WebUri? url, List? otherLikelyURLs}) => - platform.mayLaunchUrl(url: url, otherLikelyURLs: otherLikelyURLs); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.validateRelationship} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.validateRelationship.supported_platforms} - Future validateRelationship({ - required CustomTabsRelationType relation, - required WebUri origin, - }) => platform.validateRelationship(relation: relation, origin: origin); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.close} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.close.supported_platforms} - Future close() => platform.close(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isOpened} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isOpened.supported_platforms} - bool isOpened() => platform.isOpened(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.setActionButton} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.setActionButton.supported_platforms} - void setActionButton(ChromeSafariBrowserActionButton actionButton) => - platform.setActionButton(actionButton); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.updateActionButton} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.updateActionButton.supported_platforms} - Future updateActionButton({ - required Uint8List icon, - required String description, - }) => platform.updateActionButton(icon: icon, description: description); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.setSecondaryToolbar} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.setSecondaryToolbar.supported_platforms} - void setSecondaryToolbar( - ChromeSafariBrowserSecondaryToolbar secondaryToolbar, - ) => platform.setSecondaryToolbar(secondaryToolbar); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.updateSecondaryToolbar} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.updateSecondaryToolbar.supported_platforms} - Future updateSecondaryToolbar( - ChromeSafariBrowserSecondaryToolbar secondaryToolbar, - ) => platform.updateSecondaryToolbar(secondaryToolbar); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.addMenuItem} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.addMenuItem.supported_platforms} - void addMenuItem(ChromeSafariBrowserMenuItem menuItem) => - platform.addMenuItem(menuItem); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.addMenuItems} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.addMenuItems.supported_platforms} - void addMenuItems(List menuItems) => - platform.addMenuItems(menuItems); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.requestPostMessageChannel} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.requestPostMessageChannel.supported_platforms} - Future requestPostMessageChannel({ - required WebUri sourceOrigin, - WebUri? targetOrigin, - }) => platform.requestPostMessageChannel( - sourceOrigin: sourceOrigin, - targetOrigin: targetOrigin, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.postMessage} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.postMessage.supported_platforms} - Future postMessage(String message) => - platform.postMessage(message); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isEngagementSignalsApiAvailable} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isEngagementSignalsApiAvailable.supported_platforms} - Future isEngagementSignalsApiAvailable() => - platform.isEngagementSignalsApiAvailable(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isAvailable} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isAvailable.supported_platforms} - static Future isAvailable() => - PlatformChromeSafariBrowser.static().isAvailable(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.getMaxToolbarItems} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.getMaxToolbarItems.supported_platforms} - static Future getMaxToolbarItems() => - PlatformChromeSafariBrowser.static().getMaxToolbarItems(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.getPackageName} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.getPackageName.supported_platforms} - static Future getPackageName({ - List? packages, - bool ignoreDefault = false, - }) => PlatformChromeSafariBrowser.static().getPackageName( - packages: packages, - ignoreDefault: ignoreDefault, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.clearWebsiteData} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.clearWebsiteData.supported_platforms} - static Future clearWebsiteData() => - PlatformChromeSafariBrowser.static().clearWebsiteData(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.prewarmConnections} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.prewarmConnections.supported_platforms} - static Future prewarmConnections(List URLs) => - PlatformChromeSafariBrowser.static().prewarmConnections(URLs); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.invalidatePrewarmingToken} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.invalidatePrewarmingToken.supported_platforms} - static Future invalidatePrewarmingToken( - PrewarmingToken prewarmingToken, - ) => PlatformChromeSafariBrowser.static().invalidatePrewarmingToken( - prewarmingToken, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.dispose} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.dispose.supported_platforms} - @mustCallSuper - void dispose() => platform.dispose(); - - @override - void onClosed() {} - - @override - void onCompletedInitialLoad(bool? didLoadSuccessfully) {} - - @override - void onGreatestScrollPercentageIncreased(int scrollPercentage) {} - - @override - void onInitialLoadDidRedirect(WebUri? url) {} - - @override - void onMessageChannelReady() {} - - @override - void onNavigationEvent(CustomTabsNavigationEventType? navigationEvent) {} - - @override - void onOpened() {} - - @override - void onPostMessage(String message) {} - - @override - void onRelationshipValidationResult( - CustomTabsRelationType? relation, - WebUri? requestedOrigin, - bool result, - ) {} - - @override - void onServiceConnected() {} - - @override - void onSessionEnded(bool didUserInteract) {} - - @override - void onVerticalScrollEvent(bool isDirectionUp) {} - - @override - void onWillOpenInBrowser() {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformChromeSafariBrowser.static().isClassSupported(platform: platform); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isMethodSupported} - static bool isMethodSupported( - PlatformChromeSafariBrowserMethod property, { - TargetPlatform? platform, - }) => PlatformChromeSafariBrowser.static().isMethodSupported( - property, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.isMethodSupported} - static bool isEventMethodSupported( - PlatformChromeSafariBrowserEventsMethod method, { - TargetPlatform? platform, - }) => PlatformChromeSafariBrowserEvents.isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview/lib/src/chrome_safari_browser/main.dart b/flutter_inappwebview/lib/src/chrome_safari_browser/main.dart deleted file mode 100644 index 9a6238b706..0000000000 --- a/flutter_inappwebview/lib/src/chrome_safari_browser/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'chrome_safari_browser.dart'; diff --git a/flutter_inappwebview/lib/src/cookie_manager.dart b/flutter_inappwebview/lib/src/cookie_manager.dart deleted file mode 100755 index 07f88498df..0000000000 --- a/flutter_inappwebview/lib/src/cookie_manager.dart +++ /dev/null @@ -1,227 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import 'in_app_webview/in_app_webview_controller.dart'; -import 'webview_environment/webview_environment.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.supported_platforms} -class CookieManager { - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.supported_platforms} - CookieManager() - : this.fromPlatformCreationParams( - const PlatformCookieManagerCreationParams(), - ); - - /// Constructs a [CookieManager] from creation params for a specific - /// platform. - CookieManager.fromPlatformCreationParams( - PlatformCookieManagerCreationParams params, - ) : this.fromPlatform(PlatformCookieManager(params)); - - /// Constructs a [CookieManager] from a specific platform - /// implementation. - CookieManager.fromPlatform(this.platform); - - /// Implementation of [PlatformCookieManager] for the current platform. - final PlatformCookieManager platform; - - ///Use [CookieManager] instead. - @Deprecated("Use CookieManager instead") - IOSCookieManager ios = IOSCookieManager.instance(); - - static CookieManager? _instance; - - ///Gets the [CookieManager] shared instance. - /// - ///[webViewEnvironment] (Supported only on Windows) - Used to create the [CookieManager] using the specified environment. - static CookieManager instance({WebViewEnvironment? webViewEnvironment}) { - if (webViewEnvironment == null) { - if (_instance == null) { - _instance = CookieManager(); - } - return _instance!; - } else { - return CookieManager.fromPlatformCreationParams( - PlatformCookieManagerCreationParams( - webViewEnvironment: webViewEnvironment.platform, - ), - ); - } - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.setCookie} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.setCookie.supported_platforms} - Future setCookie({ - required WebUri url, - required String name, - required String value, - String path = "/", - String? domain, - int? expiresDate, - int? maxAge, - bool? isSecure, - bool? isHttpOnly, - HTTPCookieSameSitePolicy? sameSite, - @Deprecated("Use webViewController instead") - InAppWebViewController? iosBelow11WebViewController, - InAppWebViewController? webViewController, - }) => platform.setCookie( - url: url, - name: name, - value: value, - path: path, - domain: domain, - expiresDate: expiresDate, - maxAge: maxAge, - isSecure: isSecure, - isHttpOnly: isHttpOnly, - sameSite: sameSite, - iosBelow11WebViewController: iosBelow11WebViewController?.platform, - webViewController: webViewController?.platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.getCookies} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.getCookies.supported_platforms} - Future> getCookies({ - required WebUri url, - @Deprecated("Use webViewController instead") - InAppWebViewController? iosBelow11WebViewController, - InAppWebViewController? webViewController, - }) => platform.getCookies( - url: url, - iosBelow11WebViewController: iosBelow11WebViewController?.platform, - webViewController: webViewController?.platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.getCookie} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.getCookie.supported_platforms} - Future getCookie({ - required WebUri url, - required String name, - @Deprecated("Use webViewController instead") - InAppWebViewController? iosBelow11WebViewController, - InAppWebViewController? webViewController, - }) => platform.getCookie( - url: url, - name: name, - iosBelow11WebViewController: iosBelow11WebViewController?.platform, - webViewController: webViewController?.platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.deleteCookie} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.deleteCookie.supported_platforms} - Future deleteCookie({ - required WebUri url, - required String name, - String path = "/", - String? domain, - @Deprecated("Use webViewController instead") - InAppWebViewController? iosBelow11WebViewController, - InAppWebViewController? webViewController, - }) => platform.deleteCookie( - url: url, - name: name, - path: path, - domain: domain, - iosBelow11WebViewController: iosBelow11WebViewController?.platform, - webViewController: webViewController?.platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.deleteCookies} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.deleteCookies.supported_platforms} - Future deleteCookies({ - required WebUri url, - String path = "/", - String? domain, - @Deprecated("Use webViewController instead") - InAppWebViewController? iosBelow11WebViewController, - InAppWebViewController? webViewController, - }) => platform.deleteCookies( - url: url, - path: path, - domain: domain, - iosBelow11WebViewController: iosBelow11WebViewController?.platform, - webViewController: webViewController?.platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.deleteAllCookies} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.deleteAllCookies.supported_platforms} - Future deleteAllCookies() => platform.deleteAllCookies(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.getAllCookies} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.getAllCookies.supported_platforms} - Future> getAllCookies() => platform.getAllCookies(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.removeSessionCookies} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.removeSessionCookies.supported_platforms} - Future removeSessionCookies() => platform.removeSessionCookies(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.flush} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.flush.supported_platforms} - Future flush() => platform.flush(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManagerCreationParams.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformCookieManager.static().isClassSupported(platform: platform); - - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManagerCreationParams.isPropertySupported} - static bool isPropertySupported( - PlatformCookieManagerCreationParamsProperty property, { - TargetPlatform? platform, - }) => PlatformCookieManager.static().isPropertySupported( - property, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.isMethodSupported} - static bool isMethodSupported( - PlatformCookieManagerMethod method, { - TargetPlatform? platform, - }) => PlatformCookieManager.static().isMethodSupported( - method, - platform: platform, - ); -} - -///Class that contains only iOS-specific methods of [CookieManager]. -///Use [CookieManager] instead. -@Deprecated("Use CookieManager instead") -class IOSCookieManager { - static IOSCookieManager? _instance; - - ///Gets the [IOSCookieManager] shared instance. - static IOSCookieManager instance() { - return (_instance != null) ? _instance! : _init(); - } - - IOSCookieManager._(); - - static IOSCookieManager _init() { - _instance = IOSCookieManager._(); - return _instance!; - } - - ///Fetches all stored cookies. - /// - ///**NOTE**: available on iOS 11.0+. - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkhttpcookiestore/2882005-getallcookies - Future> getAllCookies() async { - return CookieManager.instance().getAllCookies(); - } -} diff --git a/flutter_inappwebview/lib/src/find_interaction/find_interaction_controller.dart b/flutter_inappwebview/lib/src/find_interaction/find_interaction_controller.dart deleted file mode 100644 index 802c7ceb8d..0000000000 --- a/flutter_inappwebview/lib/src/find_interaction/find_interaction_controller.dart +++ /dev/null @@ -1,131 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.supported_platforms} -class FindInteractionController { - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.supported_platforms} - FindInteractionController({ - void Function( - PlatformFindInteractionController controller, - int activeMatchOrdinal, - int numberOfMatches, - bool isDoneCounting, - )? - onFindResultReceived, - }) : this.fromPlatformCreationParams( - params: PlatformFindInteractionControllerCreationParams( - onFindResultReceived: onFindResultReceived, - ), - ); - - /// Constructs a [FindInteractionController]. - /// - /// See [FindInteractionController.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - FindInteractionController.fromPlatformCreationParams({ - required PlatformFindInteractionControllerCreationParams params, - }) : this.fromPlatform(platform: PlatformFindInteractionController(params)); - - /// Constructs a [FindInteractionController] from a specific platform implementation. - FindInteractionController.fromPlatform({required this.platform}); - - /// Implementation of [PlatformFindInteractionController] for the current platform. - final PlatformFindInteractionController platform; - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.onFindResultReceived} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.onFindResultReceived.supported_platforms} - void Function( - PlatformFindInteractionController controller, - int activeMatchOrdinal, - int numberOfMatches, - bool isDoneCounting, - )? - get onFindResultReceived => platform.onFindResultReceived; - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findAll} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findAll.supported_platforms} - Future findAll({String? find}) => platform.findAll(find: find); - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findNext} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findNext.supported_platforms} - Future findNext({bool forward = true}) => - platform.findNext(forward: forward); - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.clearMatches} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.clearMatches.supported_platforms} - Future clearMatches() => platform.clearMatches(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.setSearchText} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.setSearchText.supported_platforms} - Future setSearchText(String? searchText) => - platform.setSearchText(searchText); - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getSearchText} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getSearchText.supported_platforms} - Future getSearchText() => platform.getSearchText(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.isFindNavigatorVisible} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.isFindNavigatorVisible.supported_platforms} - Future isFindNavigatorVisible() => platform.isFindNavigatorVisible(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.updateResultCount} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.updateResultCount.supported_platforms} - Future updateResultCount() => platform.updateResultCount(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.presentFindNavigator} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.presentFindNavigator.supported_platforms} - Future presentFindNavigator() => platform.presentFindNavigator(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.dismissFindNavigator} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.dismissFindNavigator.supported_platforms} - Future dismissFindNavigator() => platform.dismissFindNavigator(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getActiveFindSession} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getActiveFindSession.supported_platforms} - Future getActiveFindSession() => - platform.getActiveFindSession(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.dispose} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.dispose.supported_platforms} - void dispose({bool isKeepAlive = false}) => platform.dispose(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionControllerCreationParams.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformFindInteractionController.static().isClassSupported( - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.isPropertySupported} - static bool isPropertySupported( - PlatformFindInteractionControllerCreationParamsProperty property, { - TargetPlatform? platform, - }) => PlatformFindInteractionController.static().isPropertySupported( - property, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.isMethodSupported} - static bool isMethodSupported( - PlatformFindInteractionControllerMethod method, { - TargetPlatform? platform, - }) => PlatformFindInteractionController.static().isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview/lib/src/find_interaction/main.dart b/flutter_inappwebview/lib/src/find_interaction/main.dart deleted file mode 100644 index 9862f9d756..0000000000 --- a/flutter_inappwebview/lib/src/find_interaction/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'find_interaction_controller.dart' show FindInteractionController; diff --git a/flutter_inappwebview/lib/src/http_auth_credentials_database.dart b/flutter_inappwebview/lib/src/http_auth_credentials_database.dart deleted file mode 100755 index c50fe83cc9..0000000000 --- a/flutter_inappwebview/lib/src/http_auth_credentials_database.dart +++ /dev/null @@ -1,106 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.supported_platforms} -class HttpAuthCredentialDatabase { - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.supported_platforms} - HttpAuthCredentialDatabase() - : this.fromPlatformCreationParams( - const PlatformHttpAuthCredentialDatabaseCreationParams(), - ); - - /// Constructs a [HttpAuthCredentialDatabase] from creation params for a specific - /// platform. - HttpAuthCredentialDatabase.fromPlatformCreationParams( - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) : this.fromPlatform(PlatformHttpAuthCredentialDatabase(params)); - - /// Constructs a [HttpAuthCredentialDatabase] from a specific platform - /// implementation. - HttpAuthCredentialDatabase.fromPlatform(this.platform); - - /// Implementation of [PlatformHttpAuthCredentialDatabase] for the current platform. - final PlatformHttpAuthCredentialDatabase platform; - - static HttpAuthCredentialDatabase? _instance; - - ///Gets the [HttpAuthCredentialDatabase] shared instance. - static HttpAuthCredentialDatabase instance() { - if (_instance == null) { - _instance = HttpAuthCredentialDatabase(); - } - return _instance!; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.getAllAuthCredentials} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.getAllAuthCredentials.supported_platforms} - Future> getAllAuthCredentials() => - platform.getAllAuthCredentials(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.getHttpAuthCredentials} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.getHttpAuthCredentials.supported_platforms} - Future> getHttpAuthCredentials({ - required URLProtectionSpace protectionSpace, - }) => platform.getHttpAuthCredentials(protectionSpace: protectionSpace); - - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.setHttpAuthCredential} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.setHttpAuthCredential.supported_platforms} - Future setHttpAuthCredential({ - required URLProtectionSpace protectionSpace, - required URLCredential credential, - }) => platform.setHttpAuthCredential( - protectionSpace: protectionSpace, - credential: credential, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.removeHttpAuthCredential} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.removeHttpAuthCredential.supported_platforms} - Future removeHttpAuthCredential({ - required URLProtectionSpace protectionSpace, - required URLCredential credential, - }) => platform.removeHttpAuthCredential( - protectionSpace: protectionSpace, - credential: credential, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.removeHttpAuthCredentials} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.removeHttpAuthCredentials.supported_platforms} - Future removeHttpAuthCredentials({ - required URLProtectionSpace protectionSpace, - }) => platform.removeHttpAuthCredentials(protectionSpace: protectionSpace); - - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.clearAllAuthCredentials} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.clearAllAuthCredentials.supported_platforms} - Future clearAllAuthCredentials() => platform.clearAllAuthCredentials(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabaseCreationParams.isClassSupported} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabaseCreationParams.isClassSupported.supported_platforms} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformHttpAuthCredentialDatabase.static().isClassSupported( - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.isMethodSupported} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase.isMethodSupported.supported_platforms} - static bool isMethodSupported( - PlatformHttpAuthCredentialDatabaseMethod method, { - TargetPlatform? platform, - }) => PlatformHttpAuthCredentialDatabase.static().isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview/lib/src/in_app_browser/in_app_browser.dart b/flutter_inappwebview/lib/src/in_app_browser/in_app_browser.dart deleted file mode 100755 index 3133a09390..0000000000 --- a/flutter_inappwebview/lib/src/in_app_browser/in_app_browser.dart +++ /dev/null @@ -1,804 +0,0 @@ -import 'dart:async'; -import 'dart:collection'; -import 'dart:typed_data'; -import 'dart:ui'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../find_interaction/find_interaction_controller.dart'; -import '../pull_to_refresh/main.dart'; - -import '../in_app_webview/in_app_webview_controller.dart'; -import '../webview_environment/webview_environment.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.supported_platforms} -class InAppBrowser implements PlatformInAppBrowserEvents { - ///Constructs a [InAppBrowser]. - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.supported_platforms} - InAppBrowser({ - ContextMenu? contextMenu, - PullToRefreshController? pullToRefreshController, - FindInteractionController? findInteractionController, - UnmodifiableListView? initialUserScripts, - int? windowId, - WebViewEnvironment? webViewEnvironment, - }) : this.fromPlatformCreationParams( - PlatformInAppBrowserCreationParams( - contextMenu: contextMenu, - pullToRefreshController: pullToRefreshController?.platform, - findInteractionController: findInteractionController?.platform, - initialUserScripts: initialUserScripts, - windowId: windowId, - webViewEnvironment: webViewEnvironment?.platform, - ), - ); - - /// Constructs a [InAppBrowser] from creation params for a specific - /// platform. - InAppBrowser.fromPlatformCreationParams( - PlatformInAppBrowserCreationParams params, - ) : this.fromPlatform(PlatformInAppBrowser(params)); - - /// Constructs a [InAppBrowser] from a specific platform - /// implementation. - InAppBrowser.fromPlatform(this.platform) { - this.platform.eventHandler = this; - } - - /// Implementation of [PlatformInAppBrowser] for the current platform. - final PlatformInAppBrowser platform; - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.id} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.id.supported_platforms} - String get id => platform.id; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.contextMenu} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.contextMenu.supported_platforms} - ContextMenu? get contextMenu => platform.contextMenu; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.pullToRefreshController} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.pullToRefreshController.supported_platforms} - PullToRefreshController? get pullToRefreshController { - final pullToRefreshControllerPlatform = platform.pullToRefreshController; - if (pullToRefreshControllerPlatform == null) { - return null; - } - return PullToRefreshController.fromPlatform( - platform: pullToRefreshControllerPlatform, - ); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.findInteractionController} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.findInteractionController.supported_platforms} - FindInteractionController? get findInteractionController { - final findInteractionControllerPlatform = - platform.findInteractionController; - if (findInteractionControllerPlatform == null) { - return null; - } - return FindInteractionController.fromPlatform( - platform: findInteractionControllerPlatform, - ); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.initialUserScripts} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.initialUserScripts.supported_platforms} - UnmodifiableListView? get initialUserScripts => - platform.initialUserScripts; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.windowId} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.windowId.supported_platforms} - int? get windowId => platform.windowId; - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.webViewController} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.webViewController.supported_platforms} - InAppWebViewController? get webViewController { - final webViewControllerPlatform = platform.webViewController; - if (webViewControllerPlatform == null) { - return null; - } - return InAppWebViewController.fromPlatform( - platform: webViewControllerPlatform, - ); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.openUrlRequest} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.openUrlRequest.supported_platforms} - Future openUrlRequest({ - required URLRequest urlRequest, - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) { - this.platform.eventHandler = this; - return platform.openUrlRequest( - urlRequest: urlRequest, - options: options, - settings: settings, - ); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.openFile} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.openFile.supported_platforms} - Future openFile({ - required String assetFilePath, - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) { - this.platform.eventHandler = this; - return platform.openFile( - assetFilePath: assetFilePath, - options: options, - settings: settings, - ); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.openData} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.openData.supported_platforms} - Future openData({ - required String data, - String mimeType = "text/html", - String encoding = "utf8", - WebUri? baseUrl, - @Deprecated("Use historyUrl instead") Uri? androidHistoryUrl, - WebUri? historyUrl, - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) { - this.platform.eventHandler = this; - return platform.openData( - data: data, - mimeType: mimeType, - encoding: encoding, - baseUrl: baseUrl, - androidHistoryUrl: androidHistoryUrl, - historyUrl: historyUrl, - options: options, - settings: settings, - ); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.openWithSystemBrowser} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.openWithSystemBrowser.supported_platforms} - static Future openWithSystemBrowser({required WebUri url}) => - PlatformInAppBrowser.static().openWithSystemBrowser(url: url); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.addMenuItem} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.addMenuItem.supported_platforms} - void addMenuItem(InAppBrowserMenuItem menuItem) => - platform.addMenuItem(menuItem); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.addMenuItems} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.addMenuItems.supported_platforms} - void addMenuItems(List menuItems) => - platform.addMenuItems(menuItems); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.removeMenuItem} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.removeMenuItem.supported_platforms} - bool removeMenuItem(InAppBrowserMenuItem menuItem) => - platform.removeMenuItem(menuItem); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.removeMenuItems} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.removeMenuItems.supported_platforms} - void removeMenuItems(List menuItems) => - platform.removeMenuItems(menuItems); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.removeAllMenuItem} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.removeAllMenuItem.supported_platforms} - void removeAllMenuItem() => platform.removeAllMenuItem(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.hasMenuItem} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.hasMenuItem.supported_platforms} - bool hasMenuItem(InAppBrowserMenuItem menuItem) => - platform.hasMenuItem(menuItem); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.show} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.show.supported_platforms} - Future show() => platform.show(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.hide} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.hide.supported_platforms} - Future hide() => platform.hide(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.close} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.close.supported_platforms} - Future close() => platform.close(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.isHidden} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.isHidden.supported_platforms} - Future isHidden() => platform.isHidden(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.setOptions} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.setOptions.supported_platforms} - @Deprecated('Use setSettings instead') - Future setOptions({required InAppBrowserClassOptions options}) => - platform.setOptions(options: options); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.getOptions} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.getOptions.supported_platforms} - @Deprecated('Use getSettings instead') - Future getOptions() => platform.getOptions(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.setSettings} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.setSettings.supported_platforms} - Future setSettings({required InAppBrowserClassSettings settings}) => - platform.setSettings(settings: settings); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.getSettings} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.getSettings.supported_platforms} - Future getSettings() => platform.getSettings(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.isOpened} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.isOpened.supported_platforms} - bool isOpened() => platform.isOpened(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.dispose} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.dispose.supported_platforms} - @mustCallSuper - void dispose() => platform.dispose(); - - ///Use [onFormResubmission] instead. - @Deprecated('Use onFormResubmission instead') - @override - FutureOr? androidOnFormResubmission(Uri? url) { - return null; - } - - ///Use [onGeolocationPermissionsHidePrompt] instead. - @Deprecated("Use onGeolocationPermissionsHidePrompt instead") - @override - void androidOnGeolocationPermissionsHidePrompt() {} - - ///Use [onGeolocationPermissionsShowPrompt] instead. - @Deprecated("Use onGeolocationPermissionsShowPrompt instead") - @override - FutureOr? - androidOnGeolocationPermissionsShowPrompt(String origin) { - return null; - } - - ///Use [onJsBeforeUnload] instead. - @Deprecated('Use onJsBeforeUnload instead') - @override - FutureOr? androidOnJsBeforeUnload( - JsBeforeUnloadRequest jsBeforeUnloadRequest, - ) { - return null; - } - - ///Use [onPermissionRequest] instead. - @Deprecated("Use onPermissionRequest instead") - @override - FutureOr? androidOnPermissionRequest( - String origin, - List resources, - ) { - return null; - } - - ///Use [onReceivedIcon] instead. - @Deprecated('Use onReceivedIcon instead') - @override - void androidOnReceivedIcon(Uint8List icon) {} - - ///Use [onReceivedLoginRequest] instead. - @Deprecated('Use onReceivedLoginRequest instead') - @override - void androidOnReceivedLoginRequest(LoginRequest loginRequest) {} - - ///Use [onReceivedTouchIconUrl] instead. - @Deprecated('Use onReceivedTouchIconUrl instead') - @override - void androidOnReceivedTouchIconUrl(Uri url, bool precomposed) {} - - ///Use [onRenderProcessGone] instead. - @Deprecated("Use onRenderProcessGone instead") - @override - void androidOnRenderProcessGone(RenderProcessGoneDetail detail) {} - - ///Use [onRenderProcessResponsive] instead. - @Deprecated("Use onRenderProcessResponsive instead") - @override - FutureOr? androidOnRenderProcessResponsive( - Uri? url, - ) { - return null; - } - - ///Use [onRenderProcessUnresponsive] instead. - @Deprecated("Use onRenderProcessUnresponsive instead") - @override - FutureOr? androidOnRenderProcessUnresponsive( - Uri? url, - ) { - return null; - } - - ///Use [onSafeBrowsingHit] instead. - @Deprecated("Use onSafeBrowsingHit instead") - @override - FutureOr? androidOnSafeBrowsingHit( - Uri url, - SafeBrowsingThreat? threatType, - ) { - return null; - } - - ///Use [onZoomScaleChanged] instead. - @Deprecated('Use onZoomScaleChanged instead') - @override - void androidOnScaleChanged(double oldScale, double newScale) {} - - ///Use [shouldInterceptRequest] instead. - @Deprecated("Use shouldInterceptRequest instead") - @override - FutureOr? androidShouldInterceptRequest( - WebResourceRequest request, - ) { - return null; - } - - ///Use [onDidReceiveServerRedirectForProvisionalNavigation] instead. - @Deprecated('Use onDidReceiveServerRedirectForProvisionalNavigation instead') - @override - void iosOnDidReceiveServerRedirectForProvisionalNavigation() {} - - ///Use [onNavigationResponse] instead. - @Deprecated('Use onNavigationResponse instead') - @override - FutureOr? iosOnNavigationResponse( - IOSWKNavigationResponse navigationResponse, - ) { - return null; - } - - ///Use [onWebContentProcessDidTerminate] instead. - @Deprecated('Use onWebContentProcessDidTerminate instead') - @override - void iosOnWebContentProcessDidTerminate() {} - - ///Use [shouldAllowDeprecatedTLS] instead. - @Deprecated('Use shouldAllowDeprecatedTLS instead') - @override - FutureOr? iosShouldAllowDeprecatedTLS( - URLAuthenticationChallenge challenge, - ) { - return null; - } - - @override - FutureOr? onAjaxProgress(AjaxRequest ajaxRequest) { - return null; - } - - @override - FutureOr? onAjaxReadyStateChange( - AjaxRequest ajaxRequest, - ) { - return null; - } - - @override - void onBrowserCreated() {} - - @override - void onCameraCaptureStateChanged( - MediaCaptureState? oldState, - MediaCaptureState? newState, - ) {} - - @override - void onCloseWindow() {} - - @override - void onConsoleMessage(ConsoleMessage consoleMessage) {} - - @override - void onContentSizeChanged(Size oldContentSize, Size newContentSize) {} - - @override - FutureOr? onCreateWindow(CreateWindowAction createWindowAction) { - return null; - } - - @override - void onDidReceiveServerRedirectForProvisionalNavigation() {} - - ///Use [onDownloadStarting] instead - @Deprecated('Use onDownloadStarting instead') - @override - void onDownloadStart(Uri url) {} - - ///Use [onDownloadStarting] instead - @Deprecated('Use onDownloadStarting instead') - @override - void onDownloadStartRequest(DownloadStartRequest downloadStartRequest) {} - - @override - FutureOr? onDownloadStarting( - DownloadStartRequest downloadStartRequest, - ) { - return null; - } - - @override - void onEnterFullscreen() {} - - @override - void onExit() {} - - @override - void onExitFullscreen() {} - - @override - void onContentLoading(WebUri? url) {} - - @override - void onDOMContentLoaded(WebUri? url) {} - - ///Use [FindInteractionController.onFindResultReceived] instead. - @Deprecated('Use FindInteractionController.onFindResultReceived instead') - @override - void onFindResultReceived( - int activeMatchOrdinal, - int numberOfMatches, - bool isDoneCounting, - ) {} - - @override - FutureOr? onFormResubmission(WebUri? url) { - return null; - } - - @override - void onGeolocationPermissionsHidePrompt() {} - - @override - FutureOr? - onGeolocationPermissionsShowPrompt(String origin) { - return null; - } - - @override - FutureOr? onJsAlert(JsAlertRequest jsAlertRequest) { - return null; - } - - @override - FutureOr? onJsBeforeUnload( - JsBeforeUnloadRequest jsBeforeUnloadRequest, - ) { - return null; - } - - @override - FutureOr? onJsConfirm(JsConfirmRequest jsConfirmRequest) { - return null; - } - - @override - FutureOr? onJsPrompt(JsPromptRequest jsPromptRequest) { - return null; - } - - ///Use [onReceivedError] instead. - @Deprecated("Use onReceivedError instead") - @override - void onLoadError(Uri? url, int code, String message) {} - - ///Use [onReceivedHttpError] instead. - @Deprecated("Use onReceivedHttpError instead") - @override - void onLoadHttpError(Uri? url, int statusCode, String description) {} - - @override - void onLoadResource(LoadedResource resource) {} - - ///Use [onLoadResourceWithCustomScheme] instead. - @Deprecated('Use onLoadResourceWithCustomScheme instead') - @override - FutureOr? onLoadResourceCustomScheme(Uri url) { - return null; - } - - @override - FutureOr? onLoadResourceWithCustomScheme( - WebResourceRequest request, - ) { - return null; - } - - @override - void onLoadStart(WebUri? url) {} - - @override - void onLoadStop(WebUri? url) {} - - @override - void onLongPressHitTestResult(InAppWebViewHitTestResult hitTestResult) {} - - @override - void onMicrophoneCaptureStateChanged( - MediaCaptureState? oldState, - MediaCaptureState? newState, - ) {} - - @override - FutureOr? onNavigationResponse( - NavigationResponse navigationResponse, - ) { - return null; - } - - @override - void onOverScrolled(int x, int y, bool clampedX, bool clampedY) {} - - @override - void onPageCommitVisible(WebUri? url) {} - - @override - FutureOr? onPermissionRequest( - PermissionRequest permissionRequest, - ) { - return null; - } - - @override - void onPermissionRequestCanceled(PermissionRequest permissionRequest) {} - - ///Use [onPrintRequest] instead - @Deprecated("Use onPrintRequest instead") - @override - void onPrint(Uri? url) {} - - @override - FutureOr? onPrintRequest( - WebUri? url, - PlatformPrintJobController? printJobController, - ) { - return null; - } - - @override - void onProgressChanged(int progress) {} - - @override - FutureOr? onReceivedClientCertRequest( - ClientCertChallenge challenge, - ) { - return null; - } - - @override - void onReceivedError(WebResourceRequest request, WebResourceError error) {} - - @override - FutureOr? onReceivedHttpAuthRequest( - HttpAuthenticationChallenge challenge, - ) { - return null; - } - - @override - void onReceivedHttpError( - WebResourceRequest request, - WebResourceResponse errorResponse, - ) {} - - ///Use [onFaviconChanged] instead. - @Deprecated('Use onFaviconChanged instead') - @override - void onReceivedIcon(Uint8List icon) {} - - @override - void onFaviconChanged(FaviconChangedRequest faviconChangedRequest) {} - - @override - void onReceivedLoginRequest(LoginRequest loginRequest) {} - - @override - FutureOr? onReceivedServerTrustAuthRequest( - ServerTrustChallenge challenge, - ) { - return null; - } - - @override - void onReceivedTouchIconUrl(WebUri url, bool precomposed) {} - - @override - FutureOr? onNotificationReceived( - NotificationReceivedRequest request, - ) { - return null; - } - - @override - FutureOr? onSaveAsUIShowing( - SaveAsUIShowingRequest request, - ) { - return null; - } - - @override - FutureOr? - onSaveFileSecurityCheckStarting( - SaveFileSecurityCheckStartingRequest request, - ) { - return null; - } - - @override - FutureOr? onScreenCaptureStarting( - ScreenCaptureStartingRequest request, - ) { - return null; - } - - @override - FutureOr? onLaunchingExternalUriScheme( - LaunchingExternalUriSchemeRequest request, - ) { - return null; - } - - @override - void onRenderProcessGone(RenderProcessGoneDetail detail) {} - - @override - FutureOr? onRenderProcessResponsive( - WebUri? url, - ) { - return null; - } - - @override - FutureOr? onRenderProcessUnresponsive( - WebUri? url, - ) { - return null; - } - - @override - void onRequestFocus() {} - - @override - FutureOr? onSafeBrowsingHit( - WebUri url, - SafeBrowsingThreat? threatType, - ) { - return null; - } - - @override - void onScrollChanged(int x, int y) {} - - @override - void onTitleChanged(String? title) {} - - @override - void onUpdateVisitedHistory(WebUri? url, bool? isReload) {} - - @override - void onWebContentProcessDidTerminate() {} - - @override - void onWindowBlur() {} - - @override - void onWindowFocus() {} - - @override - void onZoomScaleChanged(double oldScale, double newScale) {} - - @override - FutureOr? shouldAllowDeprecatedTLS( - URLAuthenticationChallenge challenge, - ) { - return null; - } - - @override - FutureOr? shouldInterceptAjaxRequest(AjaxRequest ajaxRequest) { - return null; - } - - @override - FutureOr? shouldInterceptFetchRequest( - FetchRequest fetchRequest, - ) { - return null; - } - - @override - FutureOr? shouldInterceptRequest( - WebResourceRequest request, - ) { - return null; - } - - @override - FutureOr? shouldOverrideUrlLoading( - NavigationAction navigationAction, - ) { - return null; - } - - @override - void onMainWindowWillClose() {} - - @override - void onProcessFailed(ProcessFailedDetail detail) {} - - @override - void onAcceleratorKeyPressed(AcceleratorKeyPressedDetail detail) {} - - @override - FutureOr onShowFileChooser( - ShowFileChooserRequest request, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformInAppBrowser.static().isClassSupported(platform: platform); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.isPropertySupported} - static bool isPropertySupported( - PlatformInAppBrowserProperty property, { - TargetPlatform? platform, - }) => PlatformInAppBrowser.static().isPropertySupported( - property, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.isMethodSupported} - static bool isMethodSupported( - PlatformInAppBrowserMethod property, { - TargetPlatform? platform, - }) => PlatformInAppBrowser.static().isMethodSupported( - property, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.isMethodSupported} - static bool isEventMethodSupported( - PlatformInAppBrowserEventsMethod method, { - TargetPlatform? platform, - }) => - PlatformInAppBrowserEvents.isMethodSupported(method, platform: platform); -} diff --git a/flutter_inappwebview/lib/src/in_app_browser/main.dart b/flutter_inappwebview/lib/src/in_app_browser/main.dart deleted file mode 100644 index 058f6ba749..0000000000 --- a/flutter_inappwebview/lib/src/in_app_browser/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'in_app_browser.dart'; diff --git a/flutter_inappwebview/lib/src/in_app_localhost_server.dart b/flutter_inappwebview/lib/src/in_app_localhost_server.dart deleted file mode 100755 index 35b71d7179..0000000000 --- a/flutter_inappwebview/lib/src/in_app_localhost_server.dart +++ /dev/null @@ -1,94 +0,0 @@ -import 'dart:async'; -import 'dart:io'; -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.supported_platforms} -class InAppLocalhostServer { - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer} - InAppLocalhostServer({ - int port = 8080, - String directoryIndex = 'index.html', - String documentRoot = './', - bool shared = false, - Future Function(HttpRequest request)? onData, - }) : this.fromPlatformCreationParams( - PlatformInAppLocalhostServerCreationParams( - port: port, - directoryIndex: directoryIndex, - documentRoot: documentRoot, - shared: shared, - onData: onData, - ), - ); - - /// Constructs a [InAppLocalhostServer] from creation params for a specific - /// platform. - InAppLocalhostServer.fromPlatformCreationParams( - PlatformInAppLocalhostServerCreationParams params, - ) : this.fromPlatform(PlatformInAppLocalhostServer(params)); - - /// Constructs a [InAppLocalhostServer] from a specific platform - /// implementation. - InAppLocalhostServer.fromPlatform(this.platform); - - /// Implementation of [PlatformInAppLocalhostServer] for the current platform. - final PlatformInAppLocalhostServer platform; - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.port} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.port.supported_platforms} - int get port => platform.port; - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.directoryIndex} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.directoryIndex.supported_platforms} - String get directoryIndex => platform.directoryIndex; - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.documentRoot} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.documentRoot.supported_platforms} - String get documentRoot => platform.documentRoot; - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.shared} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.shared.supported_platforms} - bool get shared => platform.shared; - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.onData} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.onData.supported_platforms} - Future Function(HttpRequest request)? get onData => platform.onData; - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.start} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.start.supported_platforms} - Future start() => platform.start(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.close} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.close.supported_platforms} - Future close() => platform.close(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.isRunning} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.isRunning.supported_platforms} - bool isRunning() => platform.isRunning(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServerCreationParams.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformInAppLocalhostServer.static().isClassSupported( - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.isMethodSupported} - static bool isMethodSupported( - PlatformInAppLocalhostServerMethod method, { - TargetPlatform? platform, - }) => PlatformInAppLocalhostServer.static().isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview/lib/src/in_app_webview/_static_channel.dart b/flutter_inappwebview/lib/src/in_app_webview/_static_channel.dart deleted file mode 100644 index add115071e..0000000000 --- a/flutter_inappwebview/lib/src/in_app_webview/_static_channel.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:flutter/services.dart'; - -const IN_APP_WEBVIEW_STATIC_CHANNEL = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_manager', -); diff --git a/flutter_inappwebview/lib/src/in_app_webview/android/in_app_webview_controller.dart b/flutter_inappwebview/lib/src/in_app_webview/android/in_app_webview_controller.dart deleted file mode 100644 index d523558240..0000000000 --- a/flutter_inappwebview/lib/src/in_app_webview/android/in_app_webview_controller.dart +++ /dev/null @@ -1,123 +0,0 @@ -import 'dart:core'; - -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../in_app_webview_controller.dart'; - -///Use [InAppWebViewController] instead. -@Deprecated("Use InAppWebViewController instead") -class AndroidInAppWebViewController { - PlatformInAppWebViewController? _controller; - - AndroidInAppWebViewController({ - required PlatformInAppWebViewController controller, - }) { - this._controller = controller; - } - - ///Use [InAppWebViewController.startSafeBrowsing] instead. - @Deprecated("Use InAppWebViewController.startSafeBrowsing instead") - Future startSafeBrowsing() async { - return await _controller?.startSafeBrowsing() ?? false; - } - - ///Use [InAppWebViewController.clearSslPreferences] instead. - @Deprecated("Use InAppWebViewController.clearSslPreferences instead") - Future clearSslPreferences() async { - await _controller?.clearSslPreferences(); - } - - ///Use [InAppWebViewController.pause] instead. - @Deprecated("Use InAppWebViewController.pause instead") - Future pause() async { - await _controller?.pause(); - } - - ///Use [InAppWebViewController.resume] instead. - @Deprecated("Use InAppWebViewController.resume instead") - Future resume() async { - await _controller?.resume(); - } - - ///Use [InAppWebViewController.pageDown] instead. - @Deprecated("Use InAppWebViewController.pageDown instead") - Future pageDown({required bool bottom}) async { - return await _controller?.pageDown(bottom: bottom) ?? false; - } - - ///Use [InAppWebViewController.pageUp] instead. - @Deprecated("Use InAppWebViewController.pageUp instead") - Future pageUp({required bool top}) async { - return await _controller?.pageUp(top: top) ?? false; - } - - ///Use [InAppWebViewController.zoomIn] instead. - @Deprecated("Use InAppWebViewController.zoomIn instead") - Future zoomIn() async { - return await _controller?.zoomIn() ?? false; - } - - ///Use [InAppWebViewController.zoomOut] instead. - @Deprecated("Use InAppWebViewController.zoomOut instead") - Future zoomOut() async { - return await _controller?.zoomOut() ?? false; - } - - ///Use [InAppWebViewController.clearHistory] instead. - @Deprecated("Use InAppWebViewController.clearHistory instead") - Future clearHistory() async { - await _controller?.clearHistory(); - } - - ///Use [InAppWebViewController.clearClientCertPreferences] instead. - @Deprecated("Use InAppWebViewController.clearClientCertPreferences instead") - static Future clearClientCertPreferences() async { - await InAppWebViewController.clearClientCertPreferences(); - } - - ///Use [InAppWebViewController.getSafeBrowsingPrivacyPolicyUrl] instead. - @Deprecated( - "Use InAppWebViewController.getSafeBrowsingPrivacyPolicyUrl instead", - ) - static Future getSafeBrowsingPrivacyPolicyUrl() async { - return await InAppWebViewController.getSafeBrowsingPrivacyPolicyUrl(); - } - - ///Use [InAppWebViewController.setSafeBrowsingWhitelist] instead. - @Deprecated("Use InAppWebViewController.setSafeBrowsingAllowlist instead") - static Future setSafeBrowsingWhitelist({ - required List hosts, - }) async { - return await InAppWebViewController.setSafeBrowsingAllowlist(hosts: hosts); - } - - ///Use [InAppWebViewController.getCurrentWebViewPackage] instead. - @Deprecated("Use InAppWebViewController.getCurrentWebViewPackage instead") - static Future getCurrentWebViewPackage() async { - Map? packageInfo = - (await InAppWebViewController.getCurrentWebViewPackage())?.toMap(); - return AndroidWebViewPackageInfo.fromMap(packageInfo); - } - - ///Use [InAppWebViewController.setWebContentsDebuggingEnabled] instead. - @Deprecated( - "Use InAppWebViewController.setWebContentsDebuggingEnabled instead", - ) - static Future setWebContentsDebuggingEnabled( - bool debuggingEnabled, - ) async { - return await InAppWebViewController.setWebContentsDebuggingEnabled( - debuggingEnabled, - ); - } - - ///Use [InAppWebViewController.getOriginalUrl] instead. - @Deprecated('Use InAppWebViewController.getOriginalUrl instead') - Future getOriginalUrl() async { - return await _controller?.getOriginalUrl(); - } - - void dispose() { - _controller = null; - } -} diff --git a/flutter_inappwebview/lib/src/in_app_webview/android/main.dart b/flutter_inappwebview/lib/src/in_app_webview/android/main.dart deleted file mode 100644 index e73ced7ba0..0000000000 --- a/flutter_inappwebview/lib/src/in_app_webview/android/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'in_app_webview_controller.dart'; diff --git a/flutter_inappwebview/lib/src/in_app_webview/apple/in_app_webview_controller.dart b/flutter_inappwebview/lib/src/in_app_webview/apple/in_app_webview_controller.dart deleted file mode 100644 index 197b27d101..0000000000 --- a/flutter_inappwebview/lib/src/in_app_webview/apple/in_app_webview_controller.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'dart:core'; -import 'dart:typed_data'; - -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../in_app_webview_controller.dart'; - -///Use [InAppWebViewController] instead. -@Deprecated("Use InAppWebViewController instead") -class IOSInAppWebViewController { - PlatformInAppWebViewController? _controller; - - IOSInAppWebViewController({ - required PlatformInAppWebViewController controller, - }) { - this._controller = controller; - } - - ///Use [InAppWebViewController.reloadFromOrigin] instead. - @Deprecated("Use InAppWebViewController.reloadFromOrigin instead") - Future reloadFromOrigin() async { - await _controller?.reloadFromOrigin(); - } - - ///Use [InAppWebViewController.createPdf] instead. - @Deprecated("Use InAppWebViewController.createPdf instead") - Future createPdf({ - @Deprecated("Use pdfConfiguration instead") - // ignore: deprecated_member_use_from_same_package - IOSWKPDFConfiguration? iosWKPdfConfiguration, - PDFConfiguration? pdfConfiguration, - }) async { - return await _controller?.createPdf( - iosWKPdfConfiguration: iosWKPdfConfiguration, - pdfConfiguration: pdfConfiguration, - ); - } - - ///Use [InAppWebViewController.createWebArchiveData] instead. - @Deprecated("Use InAppWebViewController.createWebArchiveData instead") - Future createWebArchiveData() async { - return await _controller?.createWebArchiveData(); - } - - ///Use [InAppWebViewController.hasOnlySecureContent] instead. - @Deprecated("Use InAppWebViewController.hasOnlySecureContent instead") - Future hasOnlySecureContent() async { - return await _controller?.hasOnlySecureContent() ?? false; - } - - ///Use [InAppWebViewController.handlesURLScheme] instead. - @Deprecated("Use InAppWebViewController.handlesURLScheme instead") - static Future handlesURLScheme(String urlScheme) async { - return await InAppWebViewController.handlesURLScheme(urlScheme); - } - - void dispose() { - _controller = null; - } -} diff --git a/flutter_inappwebview/lib/src/in_app_webview/apple/main.dart b/flutter_inappwebview/lib/src/in_app_webview/apple/main.dart deleted file mode 100644 index e73ced7ba0..0000000000 --- a/flutter_inappwebview/lib/src/in_app_webview/apple/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'in_app_webview_controller.dart'; diff --git a/flutter_inappwebview/lib/src/in_app_webview/headless_in_app_webview.dart b/flutter_inappwebview/lib/src/in_app_webview/headless_in_app_webview.dart deleted file mode 100644 index 6df250a22e..0000000000 --- a/flutter_inappwebview/lib/src/in_app_webview/headless_in_app_webview.dart +++ /dev/null @@ -1,944 +0,0 @@ -import 'dart:async'; -import 'dart:collection'; - -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../find_interaction/find_interaction_controller.dart'; -import '../pull_to_refresh/pull_to_refresh_controller.dart'; -import '../webview_environment/webview_environment.dart'; -import 'in_app_webview_controller.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.supported_platforms} -class HeadlessInAppWebView { - /// Constructs a [HeadlessInAppWebView]. - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView} - HeadlessInAppWebView.fromPlatformCreationParams({ - required PlatformHeadlessInAppWebViewCreationParams params, - }) : this.fromPlatform(platform: PlatformHeadlessInAppWebView(params)); - - /// Constructs a [HeadlessInAppWebView] from a specific platform implementation. - HeadlessInAppWebView.fromPlatform({required this.platform}); - - /// Implementation of [PlatformHeadlessInAppWebView] for the current platform. - final PlatformHeadlessInAppWebView platform; - - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.id} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.id.supported_platforms} - String get id => platform.id; - - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.webViewController} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.webViewController.supported_platforms} - InAppWebViewController? get webViewController { - final webViewControllerPlatform = platform.webViewController; - if (webViewControllerPlatform == null) { - return null; - } - return InAppWebViewController.fromPlatform( - platform: webViewControllerPlatform, - ); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.supported_platforms} - HeadlessInAppWebView({ - Size initialSize = const Size(-1, -1), - int? windowId, - HeadlessInAppWebView? headlessWebView, - InAppWebViewKeepAlive? keepAlive, - bool? preventGestureDelay, - WebViewEnvironment? webViewEnvironment, - @Deprecated('Use onGeolocationPermissionsHidePrompt instead') - void Function(InAppWebViewController controller)? - androidOnGeolocationPermissionsHidePrompt, - @Deprecated('Use onGeolocationPermissionsShowPrompt instead') - FutureOr Function( - InAppWebViewController controller, - String origin, - )? - androidOnGeolocationPermissionsShowPrompt, - @Deprecated('Use onPermissionRequest instead') - FutureOr Function( - InAppWebViewController controller, - String origin, - List resources, - )? - androidOnPermissionRequest, - @Deprecated('Use onSafeBrowsingHit instead') - FutureOr Function( - InAppWebViewController controller, - Uri url, - SafeBrowsingThreat? threatType, - )? - androidOnSafeBrowsingHit, - InAppWebViewInitialData? initialData, - String? initialFile, - @Deprecated('Use initialSettings instead') - InAppWebViewGroupOptions? initialOptions, - InAppWebViewSettings? initialSettings, - URLRequest? initialUrlRequest, - UnmodifiableListView? initialUserScripts, - PullToRefreshController? pullToRefreshController, - FindInteractionController? findInteractionController, - ContextMenu? contextMenu, - void Function(InAppWebViewController controller, WebUri? url)? - onContentLoading, - void Function(InAppWebViewController controller, WebUri? url)? - onDOMContentLoaded, - void Function(InAppWebViewController controller, WebUri? url)? - onPageCommitVisible, - void Function(InAppWebViewController controller, String? title)? - onTitleChanged, - @Deprecated( - 'Use onDidReceiveServerRedirectForProvisionalNavigation instead', - ) - void Function(InAppWebViewController controller)? - iosOnDidReceiveServerRedirectForProvisionalNavigation, - @Deprecated('Use onWebContentProcessDidTerminate instead') - void Function(InAppWebViewController controller)? - iosOnWebContentProcessDidTerminate, - @Deprecated('Use onNavigationResponse instead') - FutureOr Function( - InAppWebViewController controller, - IOSWKNavigationResponse navigationResponse, - )? - iosOnNavigationResponse, - @Deprecated('Use shouldAllowDeprecatedTLS instead') - FutureOr Function( - InAppWebViewController controller, - URLAuthenticationChallenge challenge, - )? - iosShouldAllowDeprecatedTLS, - FutureOr Function( - InAppWebViewController controller, - AjaxRequest ajaxRequest, - )? - onAjaxProgress, - FutureOr Function( - InAppWebViewController controller, - AjaxRequest ajaxRequest, - )? - onAjaxReadyStateChange, - void Function( - InAppWebViewController controller, - ConsoleMessage consoleMessage, - )? - onConsoleMessage, - FutureOr Function( - InAppWebViewController controller, - CreateWindowAction createWindowAction, - )? - onCreateWindow, - void Function(InAppWebViewController controller)? onCloseWindow, - void Function(InAppWebViewController controller)? onWindowFocus, - void Function(InAppWebViewController controller)? onWindowBlur, - @Deprecated('Use onReceivedIcon instead') - void Function(InAppWebViewController controller, Uint8List icon)? - androidOnReceivedIcon, - @Deprecated('Use onReceivedTouchIconUrl instead') - void Function(InAppWebViewController controller, Uri url, bool precomposed)? - androidOnReceivedTouchIconUrl, - @Deprecated('Use onDownloadStarting instead') - void Function(InAppWebViewController controller, Uri url)? onDownloadStart, - @Deprecated('Use onDownloadStarting instead') - void Function( - InAppWebViewController controller, - DownloadStartRequest downloadStartRequest, - )? - onDownloadStartRequest, - FutureOr Function( - InAppWebViewController controller, - DownloadStartRequest downloadStartRequest, - )? - onDownloadStarting, - @Deprecated('Use FindInteractionController.onFindResultReceived instead') - void Function( - InAppWebViewController controller, - int activeMatchOrdinal, - int numberOfMatches, - bool isDoneCounting, - )? - onFindResultReceived, - FutureOr Function( - InAppWebViewController controller, - JsAlertRequest jsAlertRequest, - )? - onJsAlert, - FutureOr Function( - InAppWebViewController controller, - JsConfirmRequest jsConfirmRequest, - )? - onJsConfirm, - FutureOr Function( - InAppWebViewController controller, - JsPromptRequest jsPromptRequest, - )? - onJsPrompt, - @Deprecated("Use onReceivedError instead") - void Function( - InAppWebViewController controller, - Uri? url, - int code, - String message, - )? - onLoadError, - void Function( - InAppWebViewController controller, - WebResourceRequest request, - WebResourceError error, - )? - onReceivedError, - @Deprecated("Use onReceivedHttpError instead") - void Function( - InAppWebViewController controller, - Uri? url, - int statusCode, - String description, - )? - onLoadHttpError, - void Function( - InAppWebViewController controller, - WebResourceRequest request, - WebResourceResponse errorResponse, - )? - onReceivedHttpError, - void Function(InAppWebViewController controller, LoadedResource resource)? - onLoadResource, - @Deprecated('Use onLoadResourceWithCustomScheme instead') - FutureOr Function( - InAppWebViewController controller, - Uri url, - )? - onLoadResourceCustomScheme, - FutureOr Function( - InAppWebViewController controller, - WebResourceRequest request, - )? - onLoadResourceWithCustomScheme, - void Function(InAppWebViewController controller, WebUri? url)? onLoadStart, - void Function(InAppWebViewController controller, WebUri? url)? onLoadStop, - void Function( - InAppWebViewController controller, - InAppWebViewHitTestResult hitTestResult, - )? - onLongPressHitTestResult, - @Deprecated("Use onPrintRequest instead") - void Function(InAppWebViewController controller, Uri? url)? onPrint, - FutureOr Function( - InAppWebViewController controller, - WebUri? url, - PlatformPrintJobController? printJobController, - )? - onPrintRequest, - void Function(InAppWebViewController controller, int progress)? - onProgressChanged, - FutureOr Function( - InAppWebViewController controller, - ClientCertChallenge challenge, - )? - onReceivedClientCertRequest, - FutureOr Function( - InAppWebViewController controller, - HttpAuthenticationChallenge challenge, - )? - onReceivedHttpAuthRequest, - FutureOr Function( - InAppWebViewController controller, - ServerTrustChallenge challenge, - )? - onReceivedServerTrustAuthRequest, - void Function(InAppWebViewController controller, int x, int y)? - onScrollChanged, - void Function( - InAppWebViewController controller, - WebUri? url, - bool? isReload, - )? - onUpdateVisitedHistory, - void Function(InAppWebViewController controller)? onWebViewCreated, - FutureOr Function( - InAppWebViewController controller, - AjaxRequest ajaxRequest, - )? - shouldInterceptAjaxRequest, - FutureOr Function( - InAppWebViewController controller, - FetchRequest fetchRequest, - )? - shouldInterceptFetchRequest, - FutureOr Function( - InAppWebViewController controller, - NavigationAction navigationAction, - )? - shouldOverrideUrlLoading, - void Function(InAppWebViewController controller)? onEnterFullscreen, - void Function(InAppWebViewController controller)? onExitFullscreen, - void Function( - InAppWebViewController controller, - int x, - int y, - bool clampedX, - bool clampedY, - )? - onOverScrolled, - void Function( - InAppWebViewController controller, - double oldScale, - double newScale, - )? - onZoomScaleChanged, - @Deprecated('Use shouldInterceptRequest instead') - FutureOr Function( - InAppWebViewController controller, - WebResourceRequest request, - )? - androidShouldInterceptRequest, - @Deprecated('Use onRenderProcessUnresponsive instead') - FutureOr Function( - InAppWebViewController controller, - Uri? url, - )? - androidOnRenderProcessUnresponsive, - @Deprecated('Use onRenderProcessResponsive instead') - FutureOr Function( - InAppWebViewController controller, - Uri? url, - )? - androidOnRenderProcessResponsive, - @Deprecated('Use onRenderProcessGone instead') - void Function( - InAppWebViewController controller, - RenderProcessGoneDetail detail, - )? - androidOnRenderProcessGone, - @Deprecated('Use onFormResubmission instead') - FutureOr Function( - InAppWebViewController controller, - Uri? url, - )? - androidOnFormResubmission, - @Deprecated('Use onZoomScaleChanged instead') - void Function( - InAppWebViewController controller, - double oldScale, - double newScale, - )? - androidOnScaleChanged, - @Deprecated('Use onJsBeforeUnload instead') - FutureOr Function( - InAppWebViewController controller, - JsBeforeUnloadRequest jsBeforeUnloadRequest, - )? - androidOnJsBeforeUnload, - @Deprecated('Use onReceivedLoginRequest instead') - void Function(InAppWebViewController controller, LoginRequest loginRequest)? - androidOnReceivedLoginRequest, - void Function(InAppWebViewController controller)? - onDidReceiveServerRedirectForProvisionalNavigation, - FutureOr Function( - InAppWebViewController controller, - WebUri? url, - )? - onFormResubmission, - void Function(InAppWebViewController controller)? - onGeolocationPermissionsHidePrompt, - FutureOr Function( - InAppWebViewController controller, - String origin, - )? - onGeolocationPermissionsShowPrompt, - FutureOr Function( - InAppWebViewController controller, - JsBeforeUnloadRequest jsBeforeUnloadRequest, - )? - onJsBeforeUnload, - FutureOr Function( - InAppWebViewController controller, - NavigationResponse navigationResponse, - )? - onNavigationResponse, - FutureOr Function( - InAppWebViewController controller, - PermissionRequest permissionRequest, - )? - onPermissionRequest, - @Deprecated('Use onFaviconChanged instead') - void Function(InAppWebViewController controller, Uint8List icon)? - onReceivedIcon, - void Function( - InAppWebViewController controller, - FaviconChangedRequest faviconChangedRequest, - )? - onFaviconChanged, - void Function(InAppWebViewController controller, LoginRequest loginRequest)? - onReceivedLoginRequest, - void Function( - InAppWebViewController controller, - PermissionRequest permissionRequest, - )? - onPermissionRequestCanceled, - void Function(InAppWebViewController controller)? onRequestFocus, - void Function( - InAppWebViewController controller, - WebUri url, - bool precomposed, - )? - onReceivedTouchIconUrl, - void Function( - InAppWebViewController controller, - RenderProcessGoneDetail detail, - )? - onRenderProcessGone, - FutureOr Function( - InAppWebViewController controller, - WebUri? url, - )? - onRenderProcessResponsive, - FutureOr Function( - InAppWebViewController controller, - WebUri? url, - )? - onRenderProcessUnresponsive, - FutureOr Function( - InAppWebViewController controller, - WebUri url, - SafeBrowsingThreat? threatType, - )? - onSafeBrowsingHit, - void Function(InAppWebViewController controller)? - onWebContentProcessDidTerminate, - FutureOr Function( - InAppWebViewController controller, - URLAuthenticationChallenge challenge, - )? - shouldAllowDeprecatedTLS, - FutureOr Function( - InAppWebViewController controller, - WebResourceRequest request, - )? - shouldInterceptRequest, - FutureOr Function( - InAppWebViewController controller, - MediaCaptureState? oldState, - MediaCaptureState? newState, - )? - onCameraCaptureStateChanged, - FutureOr Function( - InAppWebViewController controller, - MediaCaptureState? oldState, - MediaCaptureState? newState, - )? - onMicrophoneCaptureStateChanged, - void Function( - InAppWebViewController controller, - Size oldContentSize, - Size newContentSize, - )? - onContentSizeChanged, - void Function( - InAppWebViewController controller, - ProcessFailedDetail detail, - )? - onProcessFailed, - FutureOr Function( - InAppWebViewController controller, - NotificationReceivedRequest request, - )? - onNotificationReceived, - FutureOr Function( - InAppWebViewController controller, - SaveAsUIShowingRequest request, - )? - onSaveAsUIShowing, - FutureOr Function( - InAppWebViewController controller, - SaveFileSecurityCheckStartingRequest request, - )? - onSaveFileSecurityCheckStarting, - FutureOr Function( - InAppWebViewController controller, - ScreenCaptureStartingRequest request, - )? - onScreenCaptureStarting, - void Function( - InAppWebViewController controller, - AcceleratorKeyPressedDetail detail, - )? - onAcceleratorKeyPressed, - FutureOr Function( - InAppWebViewController controller, - ShowFileChooserRequest request, - )? - onShowFileChooser, - FutureOr Function( - InAppWebViewController controller, - LaunchingExternalUriSchemeRequest request, - )? - onLaunchingExternalUriScheme, - }) : this.fromPlatformCreationParams( - params: PlatformHeadlessInAppWebViewCreationParams( - controllerFromPlatform: - (PlatformInAppWebViewController controller) => - InAppWebViewController.fromPlatform(platform: controller), - initialSize: initialSize, - windowId: windowId, - initialUrlRequest: initialUrlRequest, - initialFile: initialFile, - initialData: initialData, - initialOptions: initialOptions, - initialSettings: initialSettings, - initialUserScripts: initialUserScripts, - pullToRefreshController: pullToRefreshController?.platform, - findInteractionController: findInteractionController?.platform, - contextMenu: contextMenu, - webViewEnvironment: webViewEnvironment?.platform, - onWebViewCreated: onWebViewCreated != null - ? (controller) => onWebViewCreated.call(controller) - : null, - onLoadStart: onLoadStart != null - ? (controller, url) => onLoadStart.call(controller, url) - : null, - onLoadStop: onLoadStop != null - ? (controller, url) => onLoadStop.call(controller, url) - : null, - onLoadError: onLoadError != null - ? (controller, url, code, message) => - onLoadError.call(controller, url, code, message) - : null, - onReceivedError: onReceivedError != null - ? (controller, request, error) => - onReceivedError.call(controller, request, error) - : null, - onLoadHttpError: onLoadHttpError != null - ? (controller, url, statusCode, description) => onLoadHttpError - .call(controller, url, statusCode, description) - : null, - onReceivedHttpError: onReceivedHttpError != null - ? (controller, request, errorResponse) => onReceivedHttpError - .call(controller, request, errorResponse) - : null, - onConsoleMessage: onConsoleMessage != null - ? (controller, consoleMessage) => - onConsoleMessage.call(controller, consoleMessage) - : null, - onProgressChanged: onProgressChanged != null - ? (controller, progress) => - onProgressChanged.call(controller, progress) - : null, - shouldOverrideUrlLoading: shouldOverrideUrlLoading != null - ? (controller, navigationAction) => - shouldOverrideUrlLoading(controller, navigationAction) - : null, - onLoadResource: onLoadResource != null - ? (controller, resource) => - onLoadResource.call(controller, resource) - : null, - onScrollChanged: onScrollChanged != null - ? (controller, x, y) => onScrollChanged.call(controller, x, y) - : null, - onDownloadStart: onDownloadStart != null - ? (controller, url) => onDownloadStart.call(controller, url) - : null, - onDownloadStartRequest: onDownloadStartRequest != null - ? (controller, downloadStartRequest) => onDownloadStartRequest - .call(controller, downloadStartRequest) - : null, - onDownloadStarting: onDownloadStarting != null - ? (controller, downloadStartRequest) => - onDownloadStarting.call(controller, downloadStartRequest) - : null, - onLoadResourceCustomScheme: onLoadResourceCustomScheme != null - ? (controller, url) => - onLoadResourceCustomScheme.call(controller, url) - : null, - onLoadResourceWithCustomScheme: - onLoadResourceWithCustomScheme != null - ? (controller, request) => - onLoadResourceWithCustomScheme.call(controller, request) - : null, - onCreateWindow: onCreateWindow != null - ? (controller, createWindowAction) => - onCreateWindow.call(controller, createWindowAction) - : null, - onCloseWindow: onCloseWindow != null - ? (controller) => onCloseWindow.call(controller) - : null, - onJsAlert: onJsAlert != null - ? (controller, jsAlertRequest) => - onJsAlert.call(controller, jsAlertRequest) - : null, - onJsConfirm: onJsConfirm != null - ? (controller, jsConfirmRequest) => - onJsConfirm.call(controller, jsConfirmRequest) - : null, - onJsPrompt: onJsPrompt != null - ? (controller, jsPromptRequest) => - onJsPrompt.call(controller, jsPromptRequest) - : null, - onReceivedHttpAuthRequest: onReceivedHttpAuthRequest != null - ? (controller, challenge) => - onReceivedHttpAuthRequest.call(controller, challenge) - : null, - onReceivedServerTrustAuthRequest: - onReceivedServerTrustAuthRequest != null - ? (controller, challenge) => onReceivedServerTrustAuthRequest - .call(controller, challenge) - : null, - onReceivedClientCertRequest: onReceivedClientCertRequest != null - ? (controller, challenge) => - onReceivedClientCertRequest.call(controller, challenge) - : null, - onFindResultReceived: onFindResultReceived != null - ? ( - controller, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ) => onFindResultReceived.call( - controller, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ) - : null, - shouldInterceptAjaxRequest: shouldInterceptAjaxRequest != null - ? (controller, ajaxRequest) => - shouldInterceptAjaxRequest.call(controller, ajaxRequest) - : null, - onAjaxReadyStateChange: onAjaxReadyStateChange != null - ? (controller, ajaxRequest) => - onAjaxReadyStateChange.call(controller, ajaxRequest) - : null, - onAjaxProgress: onAjaxProgress != null - ? (controller, ajaxRequest) => - onAjaxProgress.call(controller, ajaxRequest) - : null, - shouldInterceptFetchRequest: shouldInterceptFetchRequest != null - ? (controller, fetchRequest) => - shouldInterceptFetchRequest.call(controller, fetchRequest) - : null, - onUpdateVisitedHistory: onUpdateVisitedHistory != null - ? (controller, url, isReload) => - onUpdateVisitedHistory.call(controller, url, isReload) - : null, - onPrint: onPrint != null - ? (controller, url) => onPrint.call(controller, url) - : null, - onPrintRequest: onPrintRequest != null - ? (controller, url, printJobController) => - onPrintRequest.call(controller, url, printJobController) - : null, - onLongPressHitTestResult: onLongPressHitTestResult != null - ? (controller, hitTestResult) => - onLongPressHitTestResult.call(controller, hitTestResult) - : null, - onEnterFullscreen: onEnterFullscreen != null - ? (controller) => onEnterFullscreen.call(controller) - : null, - onExitFullscreen: onExitFullscreen != null - ? (controller) => onExitFullscreen.call(controller) - : null, - onContentLoading: onContentLoading != null - ? (controller, url) => onContentLoading.call(controller, url) - : null, - onDOMContentLoaded: onDOMContentLoaded != null - ? (controller, url) => onDOMContentLoaded.call(controller, url) - : null, - onPageCommitVisible: onPageCommitVisible != null - ? (controller, url) => onPageCommitVisible.call(controller, url) - : null, - onTitleChanged: onTitleChanged != null - ? (controller, title) => onTitleChanged.call(controller, title) - : null, - onWindowFocus: onWindowFocus != null - ? (controller) => onWindowFocus.call(controller) - : null, - onWindowBlur: onWindowBlur != null - ? (controller) => onWindowBlur.call(controller) - : null, - onOverScrolled: onOverScrolled != null - ? (controller, x, y, clampedX, clampedY) => - onOverScrolled.call(controller, x, y, clampedX, clampedY) - : null, - onZoomScaleChanged: onZoomScaleChanged != null - ? (controller, oldScale, newScale) => - onZoomScaleChanged.call(controller, oldScale, newScale) - : null, - androidOnSafeBrowsingHit: androidOnSafeBrowsingHit != null - ? (controller, url, threatType) => - androidOnSafeBrowsingHit.call(controller, url, threatType) - : null, - onSafeBrowsingHit: onSafeBrowsingHit != null - ? (controller, url, threatType) => - onSafeBrowsingHit.call(controller, url, threatType) - : null, - androidOnPermissionRequest: androidOnPermissionRequest != null - ? (controller, origin, resources) => androidOnPermissionRequest - .call(controller, origin, resources) - : null, - onPermissionRequest: onPermissionRequest != null - ? (controller, permissionRequest) => - onPermissionRequest.call(controller, permissionRequest) - : null, - androidOnGeolocationPermissionsShowPrompt: - androidOnGeolocationPermissionsShowPrompt != null - ? (controller, origin) => - androidOnGeolocationPermissionsShowPrompt.call( - controller, - origin, - ) - : null, - onGeolocationPermissionsShowPrompt: - onGeolocationPermissionsShowPrompt != null - ? (controller, origin) => - onGeolocationPermissionsShowPrompt.call(controller, origin) - : null, - androidOnGeolocationPermissionsHidePrompt: - androidOnGeolocationPermissionsHidePrompt != null - ? (controller) => - androidOnGeolocationPermissionsHidePrompt.call(controller) - : null, - onGeolocationPermissionsHidePrompt: - onGeolocationPermissionsHidePrompt != null - ? (controller) => - onGeolocationPermissionsHidePrompt.call(controller) - : null, - androidShouldInterceptRequest: androidShouldInterceptRequest != null - ? (controller, request) => - androidShouldInterceptRequest.call(controller, request) - : null, - shouldInterceptRequest: shouldInterceptRequest != null - ? (controller, request) => - shouldInterceptRequest.call(controller, request) - : null, - androidOnRenderProcessGone: androidOnRenderProcessGone != null - ? (controller, detail) => - androidOnRenderProcessGone.call(controller, detail) - : null, - onRenderProcessGone: onRenderProcessGone != null - ? (controller, detail) => - onRenderProcessGone.call(controller, detail) - : null, - androidOnRenderProcessResponsive: - androidOnRenderProcessResponsive != null - ? (controller, url) => - androidOnRenderProcessResponsive.call(controller, url) - : null, - onRenderProcessResponsive: onRenderProcessResponsive != null - ? (controller, url) => - onRenderProcessResponsive.call(controller, url) - : null, - androidOnRenderProcessUnresponsive: - androidOnRenderProcessUnresponsive != null - ? (controller, url) => - androidOnRenderProcessUnresponsive.call(controller, url) - : null, - onRenderProcessUnresponsive: onRenderProcessUnresponsive != null - ? (controller, url) => - onRenderProcessUnresponsive.call(controller, url) - : null, - androidOnFormResubmission: androidOnFormResubmission != null - ? (controller, url) => - androidOnFormResubmission.call(controller, url) - : null, - onFormResubmission: onFormResubmission != null - ? (controller, url) => onFormResubmission.call(controller, url) - : null, - androidOnScaleChanged: androidOnScaleChanged != null - ? (controller, oldScale, newScale) => - androidOnScaleChanged.call(controller, oldScale, newScale) - : null, - androidOnReceivedIcon: androidOnReceivedIcon != null - ? (controller, icon) => - androidOnReceivedIcon.call(controller, icon) - : null, - onReceivedIcon: onReceivedIcon != null - ? (controller, icon) => onReceivedIcon.call(controller, icon) - : null, - onFaviconChanged: onFaviconChanged != null - ? (controller, request) => - onFaviconChanged.call(controller, request) - : null, - androidOnReceivedTouchIconUrl: androidOnReceivedTouchIconUrl != null - ? (controller, url, precomposed) => androidOnReceivedTouchIconUrl - .call(controller, url, precomposed) - : null, - onReceivedTouchIconUrl: onReceivedTouchIconUrl != null - ? (controller, url, precomposed) => - onReceivedTouchIconUrl.call(controller, url, precomposed) - : null, - androidOnJsBeforeUnload: androidOnJsBeforeUnload != null - ? (controller, jsBeforeUnloadRequest) => androidOnJsBeforeUnload - .call(controller, jsBeforeUnloadRequest) - : null, - onJsBeforeUnload: onJsBeforeUnload != null - ? (controller, jsBeforeUnloadRequest) => - onJsBeforeUnload.call(controller, jsBeforeUnloadRequest) - : null, - androidOnReceivedLoginRequest: androidOnReceivedLoginRequest != null - ? (controller, loginRequest) => androidOnReceivedLoginRequest - .call(controller, loginRequest) - : null, - onReceivedLoginRequest: onReceivedLoginRequest != null - ? (controller, loginRequest) => - onReceivedLoginRequest.call(controller, loginRequest) - : null, - onPermissionRequestCanceled: onPermissionRequestCanceled != null - ? (controller, permissionRequest) => onPermissionRequestCanceled - .call(controller, permissionRequest) - : null, - onRequestFocus: onRequestFocus != null - ? (controller) => onRequestFocus.call(controller) - : null, - iosOnWebContentProcessDidTerminate: - iosOnWebContentProcessDidTerminate != null - ? (controller) => - iosOnWebContentProcessDidTerminate.call(controller) - : null, - onWebContentProcessDidTerminate: - onWebContentProcessDidTerminate != null - ? (controller) => - onWebContentProcessDidTerminate.call(controller) - : null, - iosOnDidReceiveServerRedirectForProvisionalNavigation: - iosOnDidReceiveServerRedirectForProvisionalNavigation != null - ? (controller) => - iosOnDidReceiveServerRedirectForProvisionalNavigation.call( - controller, - ) - : null, - onDidReceiveServerRedirectForProvisionalNavigation: - onDidReceiveServerRedirectForProvisionalNavigation != null - ? (controller) => - onDidReceiveServerRedirectForProvisionalNavigation.call( - controller, - ) - : null, - iosOnNavigationResponse: iosOnNavigationResponse != null - ? (controller, navigationResponse) => iosOnNavigationResponse - .call(controller, navigationResponse) - : null, - onNavigationResponse: onNavigationResponse != null - ? (controller, navigationResponse) => - onNavigationResponse.call(controller, navigationResponse) - : null, - iosShouldAllowDeprecatedTLS: iosShouldAllowDeprecatedTLS != null - ? (controller, challenge) => - iosShouldAllowDeprecatedTLS.call(controller, challenge) - : null, - shouldAllowDeprecatedTLS: shouldAllowDeprecatedTLS != null - ? (controller, challenge) => - shouldAllowDeprecatedTLS.call(controller, challenge) - : null, - onCameraCaptureStateChanged: onCameraCaptureStateChanged != null - ? (controller, oldState, newState) => onCameraCaptureStateChanged - .call(controller, oldState, newState) - : null, - onMicrophoneCaptureStateChanged: - onMicrophoneCaptureStateChanged != null - ? (controller, oldState, newState) => - onMicrophoneCaptureStateChanged.call( - controller, - oldState, - newState, - ) - : null, - onContentSizeChanged: onContentSizeChanged != null - ? (controller, oldContentSize, newContentSize) => - onContentSizeChanged.call( - controller, - oldContentSize, - newContentSize, - ) - : null, - onProcessFailed: onProcessFailed != null - ? (controller, detail) => - onProcessFailed.call(controller, detail) - : null, - onNotificationReceived: onNotificationReceived != null - ? (controller, request) => - onNotificationReceived.call(controller, request) - : null, - onSaveAsUIShowing: onSaveAsUIShowing != null - ? (controller, request) => - onSaveAsUIShowing.call(controller, request) - : null, - onSaveFileSecurityCheckStarting: - onSaveFileSecurityCheckStarting != null - ? (controller, request) => - onSaveFileSecurityCheckStarting.call(controller, request) - : null, - onScreenCaptureStarting: onScreenCaptureStarting != null - ? (controller, request) => - onScreenCaptureStarting.call(controller, request) - : null, - onAcceleratorKeyPressed: onAcceleratorKeyPressed != null - ? (controller, detail) => - onAcceleratorKeyPressed.call(controller, detail) - : null, - onShowFileChooser: onShowFileChooser != null - ? (controller, request) => - onShowFileChooser.call(controller, request) - : null, - onLaunchingExternalUriScheme: onLaunchingExternalUriScheme != null - ? (controller, request) => - onLaunchingExternalUriScheme.call(controller, request) - : null, - ), - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.run} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.run.supported_platforms} - Future run() => platform.run(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.isRunning} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.isRunning.supported_platforms} - bool isRunning() => platform.isRunning(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.setSize} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.setSize.supported_platforms} - Future setSize(Size size) => platform.setSize(size); - - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.getSize} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.getSize.supported_platforms} - Future getSize() => platform.getSize(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.dispose} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView.dispose.supported_platforms} - Future dispose() => platform.dispose(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebViewCreationParams.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformHeadlessInAppWebView.static().isClassSupported( - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebViewCreationParams.isPropertySupported} - static bool isPropertySupported( - PlatformHeadlessInAppWebViewCreationParamsProperty property, { - TargetPlatform? platform, - }) => PlatformHeadlessInAppWebView.static().isPropertySupported( - property, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebViewCreationParams.isMethodSupported} - static bool isMethodSupported( - PlatformHeadlessInAppWebViewMethod method, { - TargetPlatform? platform, - }) => PlatformHeadlessInAppWebView.static().isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview/lib/src/in_app_webview/in_app_webview.dart b/flutter_inappwebview/lib/src/in_app_webview/in_app_webview.dart deleted file mode 100755 index 60444f5170..0000000000 --- a/flutter_inappwebview/lib/src/in_app_webview/in_app_webview.dart +++ /dev/null @@ -1,924 +0,0 @@ -import 'dart:async'; -import 'dart:collection'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../find_interaction/find_interaction_controller.dart'; -import '../pull_to_refresh/main.dart'; -import '../pull_to_refresh/pull_to_refresh_controller.dart'; -import '../webview_environment/webview_environment.dart'; -import 'headless_in_app_webview.dart'; -import 'in_app_webview_controller.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewWidget} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.supported_platforms} -class InAppWebView extends StatefulWidget { - /// Constructs a [InAppWebView]. - /// - /// See [InAppWebView.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - InAppWebView.fromPlatformCreationParams({ - Key? key, - required PlatformInAppWebViewWidgetCreationParams params, - }) : this.fromPlatform( - key: key, - platform: PlatformInAppWebViewWidget(params), - ); - - /// Constructs a [InAppWebView] from a specific platform implementation. - InAppWebView.fromPlatform({super.key, required this.platform}); - - /// Implementation of [PlatformInAppWebView] for the current platform. - final PlatformInAppWebViewWidget platform; - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewWidget} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.supported_platforms} - InAppWebView({ - Key? key, - Set>? gestureRecognizers, - int? windowId, - HeadlessInAppWebView? headlessWebView, - InAppWebViewKeepAlive? keepAlive, - bool? preventGestureDelay, - TextDirection? layoutDirection, - WebViewEnvironment? webViewEnvironment, - @Deprecated('Use onGeolocationPermissionsHidePrompt instead') - void Function(InAppWebViewController controller)? - androidOnGeolocationPermissionsHidePrompt, - @Deprecated('Use onGeolocationPermissionsShowPrompt instead') - FutureOr Function( - InAppWebViewController controller, - String origin, - )? - androidOnGeolocationPermissionsShowPrompt, - @Deprecated('Use onPermissionRequest instead') - FutureOr Function( - InAppWebViewController controller, - String origin, - List resources, - )? - androidOnPermissionRequest, - @Deprecated('Use onSafeBrowsingHit instead') - FutureOr Function( - InAppWebViewController controller, - Uri url, - SafeBrowsingThreat? threatType, - )? - androidOnSafeBrowsingHit, - InAppWebViewInitialData? initialData, - String? initialFile, - @Deprecated('Use initialSettings instead') - InAppWebViewGroupOptions? initialOptions, - InAppWebViewSettings? initialSettings, - URLRequest? initialUrlRequest, - UnmodifiableListView? initialUserScripts, - PullToRefreshController? pullToRefreshController, - FindInteractionController? findInteractionController, - ContextMenu? contextMenu, - void Function(InAppWebViewController controller, WebUri? url)? - onContentLoading, - void Function(InAppWebViewController controller, WebUri? url)? - onDOMContentLoaded, - void Function(InAppWebViewController controller, WebUri? url)? - onPageCommitVisible, - void Function(InAppWebViewController controller, String? title)? - onTitleChanged, - @Deprecated( - 'Use onDidReceiveServerRedirectForProvisionalNavigation instead', - ) - void Function(InAppWebViewController controller)? - iosOnDidReceiveServerRedirectForProvisionalNavigation, - @Deprecated('Use onWebContentProcessDidTerminate instead') - void Function(InAppWebViewController controller)? - iosOnWebContentProcessDidTerminate, - @Deprecated('Use onNavigationResponse instead') - FutureOr Function( - InAppWebViewController controller, - IOSWKNavigationResponse navigationResponse, - )? - iosOnNavigationResponse, - @Deprecated('Use shouldAllowDeprecatedTLS instead') - FutureOr Function( - InAppWebViewController controller, - URLAuthenticationChallenge challenge, - )? - iosShouldAllowDeprecatedTLS, - FutureOr Function( - InAppWebViewController controller, - AjaxRequest ajaxRequest, - )? - onAjaxProgress, - FutureOr Function( - InAppWebViewController controller, - AjaxRequest ajaxRequest, - )? - onAjaxReadyStateChange, - void Function( - InAppWebViewController controller, - ConsoleMessage consoleMessage, - )? - onConsoleMessage, - FutureOr Function( - InAppWebViewController controller, - CreateWindowAction createWindowAction, - )? - onCreateWindow, - void Function(InAppWebViewController controller)? onCloseWindow, - void Function(InAppWebViewController controller)? onWindowFocus, - void Function(InAppWebViewController controller)? onWindowBlur, - @Deprecated('Use onReceivedIcon instead') - void Function(InAppWebViewController controller, Uint8List icon)? - androidOnReceivedIcon, - @Deprecated('Use onReceivedTouchIconUrl instead') - void Function(InAppWebViewController controller, Uri url, bool precomposed)? - androidOnReceivedTouchIconUrl, - @Deprecated('Use onDownloadStarting instead') - void Function(InAppWebViewController controller, Uri url)? onDownloadStart, - @Deprecated('Use onDownloadStarting instead') - void Function( - InAppWebViewController controller, - DownloadStartRequest downloadStartRequest, - )? - onDownloadStartRequest, - FutureOr Function( - InAppWebViewController controller, - DownloadStartRequest downloadStartRequest, - )? - onDownloadStarting, - @Deprecated('Use FindInteractionController.onFindResultReceived instead') - void Function( - InAppWebViewController controller, - int activeMatchOrdinal, - int numberOfMatches, - bool isDoneCounting, - )? - onFindResultReceived, - FutureOr Function( - InAppWebViewController controller, - JsAlertRequest jsAlertRequest, - )? - onJsAlert, - FutureOr Function( - InAppWebViewController controller, - JsConfirmRequest jsConfirmRequest, - )? - onJsConfirm, - FutureOr Function( - InAppWebViewController controller, - JsPromptRequest jsPromptRequest, - )? - onJsPrompt, - @Deprecated("Use onReceivedError instead") - void Function( - InAppWebViewController controller, - Uri? url, - int code, - String message, - )? - onLoadError, - void Function( - InAppWebViewController controller, - WebResourceRequest request, - WebResourceError error, - )? - onReceivedError, - @Deprecated("Use onReceivedHttpError instead") - void Function( - InAppWebViewController controller, - Uri? url, - int statusCode, - String description, - )? - onLoadHttpError, - void Function( - InAppWebViewController controller, - WebResourceRequest request, - WebResourceResponse errorResponse, - )? - onReceivedHttpError, - void Function(InAppWebViewController controller, LoadedResource resource)? - onLoadResource, - @Deprecated('Use onLoadResourceWithCustomScheme instead') - FutureOr Function( - InAppWebViewController controller, - Uri url, - )? - onLoadResourceCustomScheme, - FutureOr Function( - InAppWebViewController controller, - WebResourceRequest request, - )? - onLoadResourceWithCustomScheme, - void Function(InAppWebViewController controller, WebUri? url)? onLoadStart, - void Function(InAppWebViewController controller, WebUri? url)? onLoadStop, - void Function( - InAppWebViewController controller, - InAppWebViewHitTestResult hitTestResult, - )? - onLongPressHitTestResult, - @Deprecated("Use onPrintRequest instead") - void Function(InAppWebViewController controller, Uri? url)? onPrint, - FutureOr Function( - InAppWebViewController controller, - WebUri? url, - PlatformPrintJobController? printJobController, - )? - onPrintRequest, - void Function(InAppWebViewController controller, int progress)? - onProgressChanged, - FutureOr Function( - InAppWebViewController controller, - ClientCertChallenge challenge, - )? - onReceivedClientCertRequest, - FutureOr Function( - InAppWebViewController controller, - HttpAuthenticationChallenge challenge, - )? - onReceivedHttpAuthRequest, - FutureOr Function( - InAppWebViewController controller, - ServerTrustChallenge challenge, - )? - onReceivedServerTrustAuthRequest, - void Function(InAppWebViewController controller, int x, int y)? - onScrollChanged, - void Function( - InAppWebViewController controller, - WebUri? url, - bool? isReload, - )? - onUpdateVisitedHistory, - void Function(InAppWebViewController controller)? onWebViewCreated, - FutureOr Function( - InAppWebViewController controller, - AjaxRequest ajaxRequest, - )? - shouldInterceptAjaxRequest, - FutureOr Function( - InAppWebViewController controller, - FetchRequest fetchRequest, - )? - shouldInterceptFetchRequest, - FutureOr Function( - InAppWebViewController controller, - NavigationAction navigationAction, - )? - shouldOverrideUrlLoading, - void Function(InAppWebViewController controller)? onEnterFullscreen, - void Function(InAppWebViewController controller)? onExitFullscreen, - void Function( - InAppWebViewController controller, - int x, - int y, - bool clampedX, - bool clampedY, - )? - onOverScrolled, - void Function( - InAppWebViewController controller, - double oldScale, - double newScale, - )? - onZoomScaleChanged, - @Deprecated('Use shouldInterceptRequest instead') - FutureOr Function( - InAppWebViewController controller, - WebResourceRequest request, - )? - androidShouldInterceptRequest, - @Deprecated('Use onRenderProcessUnresponsive instead') - FutureOr Function( - InAppWebViewController controller, - Uri? url, - )? - androidOnRenderProcessUnresponsive, - @Deprecated('Use onRenderProcessResponsive instead') - FutureOr Function( - InAppWebViewController controller, - Uri? url, - )? - androidOnRenderProcessResponsive, - @Deprecated('Use onRenderProcessGone instead') - void Function( - InAppWebViewController controller, - RenderProcessGoneDetail detail, - )? - androidOnRenderProcessGone, - @Deprecated('Use onFormResubmission instead') - FutureOr Function( - InAppWebViewController controller, - Uri? url, - )? - androidOnFormResubmission, - @Deprecated('Use onZoomScaleChanged instead') - void Function( - InAppWebViewController controller, - double oldScale, - double newScale, - )? - androidOnScaleChanged, - @Deprecated('Use onJsBeforeUnload instead') - FutureOr Function( - InAppWebViewController controller, - JsBeforeUnloadRequest jsBeforeUnloadRequest, - )? - androidOnJsBeforeUnload, - @Deprecated('Use onReceivedLoginRequest instead') - void Function(InAppWebViewController controller, LoginRequest loginRequest)? - androidOnReceivedLoginRequest, - void Function(InAppWebViewController controller)? - onDidReceiveServerRedirectForProvisionalNavigation, - FutureOr Function( - InAppWebViewController controller, - WebUri? url, - )? - onFormResubmission, - void Function(InAppWebViewController controller)? - onGeolocationPermissionsHidePrompt, - FutureOr Function( - InAppWebViewController controller, - String origin, - )? - onGeolocationPermissionsShowPrompt, - FutureOr Function( - InAppWebViewController controller, - JsBeforeUnloadRequest jsBeforeUnloadRequest, - )? - onJsBeforeUnload, - FutureOr Function( - InAppWebViewController controller, - NavigationResponse navigationResponse, - )? - onNavigationResponse, - FutureOr Function( - InAppWebViewController controller, - PermissionRequest permissionRequest, - )? - onPermissionRequest, - @Deprecated('Use onFaviconChanged instead') - void Function(InAppWebViewController controller, Uint8List icon)? - onReceivedIcon, - void Function( - InAppWebViewController controller, - FaviconChangedRequest faviconChangedRequest, - )? - onFaviconChanged, - void Function(InAppWebViewController controller, LoginRequest loginRequest)? - onReceivedLoginRequest, - void Function( - InAppWebViewController controller, - PermissionRequest permissionRequest, - )? - onPermissionRequestCanceled, - void Function(InAppWebViewController controller)? onRequestFocus, - void Function( - InAppWebViewController controller, - WebUri url, - bool precomposed, - )? - onReceivedTouchIconUrl, - void Function( - InAppWebViewController controller, - RenderProcessGoneDetail detail, - )? - onRenderProcessGone, - FutureOr Function( - InAppWebViewController controller, - WebUri? url, - )? - onRenderProcessResponsive, - FutureOr Function( - InAppWebViewController controller, - WebUri? url, - )? - onRenderProcessUnresponsive, - FutureOr Function( - InAppWebViewController controller, - WebUri url, - SafeBrowsingThreat? threatType, - )? - onSafeBrowsingHit, - void Function(InAppWebViewController controller)? - onWebContentProcessDidTerminate, - FutureOr Function( - InAppWebViewController controller, - URLAuthenticationChallenge challenge, - )? - shouldAllowDeprecatedTLS, - FutureOr Function( - InAppWebViewController controller, - WebResourceRequest request, - )? - shouldInterceptRequest, - FutureOr Function( - InAppWebViewController controller, - MediaCaptureState? oldState, - MediaCaptureState? newState, - )? - onCameraCaptureStateChanged, - FutureOr Function( - InAppWebViewController controller, - MediaCaptureState? oldState, - MediaCaptureState? newState, - )? - onMicrophoneCaptureStateChanged, - void Function( - InAppWebViewController controller, - Size oldContentSize, - Size newContentSize, - )? - onContentSizeChanged, - void Function( - InAppWebViewController controller, - ProcessFailedDetail detail, - )? - onProcessFailed, - FutureOr Function( - InAppWebViewController controller, - NotificationReceivedRequest request, - )? - onNotificationReceived, - FutureOr Function( - InAppWebViewController controller, - SaveAsUIShowingRequest request, - )? - onSaveAsUIShowing, - FutureOr Function( - InAppWebViewController controller, - SaveFileSecurityCheckStartingRequest request, - )? - onSaveFileSecurityCheckStarting, - FutureOr Function( - InAppWebViewController controller, - ScreenCaptureStartingRequest request, - )? - onScreenCaptureStarting, - void Function( - InAppWebViewController controller, - AcceleratorKeyPressedDetail detail, - )? - onAcceleratorKeyPressed, - FutureOr Function( - InAppWebViewController controller, - ShowFileChooserRequest request, - )? - onShowFileChooser, - FutureOr Function( - InAppWebViewController controller, - LaunchingExternalUriSchemeRequest request, - )? - onLaunchingExternalUriScheme, - }) : this.fromPlatformCreationParams( - key: key, - params: PlatformInAppWebViewWidgetCreationParams( - controllerFromPlatform: - (PlatformInAppWebViewController controller) => - InAppWebViewController.fromPlatform(platform: controller), - windowId: windowId, - keepAlive: keepAlive, - initialUrlRequest: initialUrlRequest, - initialFile: initialFile, - initialData: initialData, - initialOptions: initialOptions, - initialSettings: initialSettings, - initialUserScripts: initialUserScripts, - pullToRefreshController: pullToRefreshController?.platform, - findInteractionController: findInteractionController?.platform, - contextMenu: contextMenu, - layoutDirection: layoutDirection, - webViewEnvironment: webViewEnvironment?.platform, - onWebViewCreated: onWebViewCreated != null - ? (controller) => onWebViewCreated.call(controller) - : null, - onLoadStart: onLoadStart != null - ? (controller, url) => onLoadStart.call(controller, url) - : null, - onLoadStop: onLoadStop != null - ? (controller, url) => onLoadStop.call(controller, url) - : null, - onLoadError: onLoadError != null - ? (controller, url, code, message) => - onLoadError.call(controller, url, code, message) - : null, - onReceivedError: onReceivedError != null - ? (controller, request, error) => - onReceivedError.call(controller, request, error) - : null, - onLoadHttpError: onLoadHttpError != null - ? (controller, url, statusCode, description) => onLoadHttpError - .call(controller, url, statusCode, description) - : null, - onReceivedHttpError: onReceivedHttpError != null - ? (controller, request, errorResponse) => onReceivedHttpError - .call(controller, request, errorResponse) - : null, - onConsoleMessage: onConsoleMessage != null - ? (controller, consoleMessage) => - onConsoleMessage.call(controller, consoleMessage) - : null, - onProgressChanged: onProgressChanged != null - ? (controller, progress) => - onProgressChanged.call(controller, progress) - : null, - shouldOverrideUrlLoading: shouldOverrideUrlLoading != null - ? (controller, navigationAction) => - shouldOverrideUrlLoading(controller, navigationAction) - : null, - onLoadResource: onLoadResource != null - ? (controller, resource) => - onLoadResource.call(controller, resource) - : null, - onScrollChanged: onScrollChanged != null - ? (controller, x, y) => onScrollChanged.call(controller, x, y) - : null, - onDownloadStart: onDownloadStart != null - ? (controller, url) => onDownloadStart.call(controller, url) - : null, - onDownloadStartRequest: onDownloadStartRequest != null - ? (controller, downloadStartRequest) => onDownloadStartRequest - .call(controller, downloadStartRequest) - : null, - onDownloadStarting: onDownloadStarting != null - ? (controller, downloadStartRequest) => - onDownloadStarting.call(controller, downloadStartRequest) - : null, - onLoadResourceCustomScheme: onLoadResourceCustomScheme != null - ? (controller, url) => - onLoadResourceCustomScheme.call(controller, url) - : null, - onLoadResourceWithCustomScheme: - onLoadResourceWithCustomScheme != null - ? (controller, request) => - onLoadResourceWithCustomScheme.call(controller, request) - : null, - onCreateWindow: onCreateWindow != null - ? (controller, createWindowAction) => - onCreateWindow.call(controller, createWindowAction) - : null, - onCloseWindow: onCloseWindow != null - ? (controller) => onCloseWindow.call(controller) - : null, - onJsAlert: onJsAlert != null - ? (controller, jsAlertRequest) => - onJsAlert.call(controller, jsAlertRequest) - : null, - onJsConfirm: onJsConfirm != null - ? (controller, jsConfirmRequest) => - onJsConfirm.call(controller, jsConfirmRequest) - : null, - onJsPrompt: onJsPrompt != null - ? (controller, jsPromptRequest) => - onJsPrompt.call(controller, jsPromptRequest) - : null, - onReceivedHttpAuthRequest: onReceivedHttpAuthRequest != null - ? (controller, challenge) => - onReceivedHttpAuthRequest.call(controller, challenge) - : null, - onReceivedServerTrustAuthRequest: - onReceivedServerTrustAuthRequest != null - ? (controller, challenge) => onReceivedServerTrustAuthRequest - .call(controller, challenge) - : null, - onReceivedClientCertRequest: onReceivedClientCertRequest != null - ? (controller, challenge) => - onReceivedClientCertRequest.call(controller, challenge) - : null, - onFindResultReceived: onFindResultReceived != null - ? ( - controller, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ) => onFindResultReceived.call( - controller, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ) - : null, - shouldInterceptAjaxRequest: shouldInterceptAjaxRequest != null - ? (controller, ajaxRequest) => - shouldInterceptAjaxRequest.call(controller, ajaxRequest) - : null, - onAjaxReadyStateChange: onAjaxReadyStateChange != null - ? (controller, ajaxRequest) => - onAjaxReadyStateChange.call(controller, ajaxRequest) - : null, - onAjaxProgress: onAjaxProgress != null - ? (controller, ajaxRequest) => - onAjaxProgress.call(controller, ajaxRequest) - : null, - shouldInterceptFetchRequest: shouldInterceptFetchRequest != null - ? (controller, fetchRequest) => - shouldInterceptFetchRequest.call(controller, fetchRequest) - : null, - onUpdateVisitedHistory: onUpdateVisitedHistory != null - ? (controller, url, isReload) => - onUpdateVisitedHistory.call(controller, url, isReload) - : null, - onPrint: onPrint != null - ? (controller, url) => onPrint.call(controller, url) - : null, - onPrintRequest: onPrintRequest != null - ? (controller, url, printJobController) => - onPrintRequest.call(controller, url, printJobController) - : null, - onLongPressHitTestResult: onLongPressHitTestResult != null - ? (controller, hitTestResult) => - onLongPressHitTestResult.call(controller, hitTestResult) - : null, - onEnterFullscreen: onEnterFullscreen != null - ? (controller) => onEnterFullscreen.call(controller) - : null, - onExitFullscreen: onExitFullscreen != null - ? (controller) => onExitFullscreen.call(controller) - : null, - onContentLoading: onContentLoading != null - ? (controller, url) => onContentLoading.call(controller, url) - : null, - onDOMContentLoaded: onDOMContentLoaded != null - ? (controller, url) => onDOMContentLoaded.call(controller, url) - : null, - onPageCommitVisible: onPageCommitVisible != null - ? (controller, url) => onPageCommitVisible.call(controller, url) - : null, - onTitleChanged: onTitleChanged != null - ? (controller, title) => onTitleChanged.call(controller, title) - : null, - onWindowFocus: onWindowFocus != null - ? (controller) => onWindowFocus.call(controller) - : null, - onWindowBlur: onWindowBlur != null - ? (controller) => onWindowBlur.call(controller) - : null, - onOverScrolled: onOverScrolled != null - ? (controller, x, y, clampedX, clampedY) => - onOverScrolled.call(controller, x, y, clampedX, clampedY) - : null, - onZoomScaleChanged: onZoomScaleChanged != null - ? (controller, oldScale, newScale) => - onZoomScaleChanged.call(controller, oldScale, newScale) - : null, - androidOnSafeBrowsingHit: androidOnSafeBrowsingHit != null - ? (controller, url, threatType) => - androidOnSafeBrowsingHit.call(controller, url, threatType) - : null, - onSafeBrowsingHit: onSafeBrowsingHit != null - ? (controller, url, threatType) => - onSafeBrowsingHit.call(controller, url, threatType) - : null, - androidOnPermissionRequest: androidOnPermissionRequest != null - ? (controller, origin, resources) => androidOnPermissionRequest - .call(controller, origin, resources) - : null, - onPermissionRequest: onPermissionRequest != null - ? (controller, permissionRequest) => - onPermissionRequest.call(controller, permissionRequest) - : null, - androidOnGeolocationPermissionsShowPrompt: - androidOnGeolocationPermissionsShowPrompt != null - ? (controller, origin) => - androidOnGeolocationPermissionsShowPrompt.call( - controller, - origin, - ) - : null, - onGeolocationPermissionsShowPrompt: - onGeolocationPermissionsShowPrompt != null - ? (controller, origin) => - onGeolocationPermissionsShowPrompt.call(controller, origin) - : null, - androidOnGeolocationPermissionsHidePrompt: - androidOnGeolocationPermissionsHidePrompt != null - ? (controller) => - androidOnGeolocationPermissionsHidePrompt.call(controller) - : null, - onGeolocationPermissionsHidePrompt: - onGeolocationPermissionsHidePrompt != null - ? (controller) => - onGeolocationPermissionsHidePrompt.call(controller) - : null, - androidShouldInterceptRequest: androidShouldInterceptRequest != null - ? (controller, request) => - androidShouldInterceptRequest.call(controller, request) - : null, - shouldInterceptRequest: shouldInterceptRequest != null - ? (controller, request) => - shouldInterceptRequest.call(controller, request) - : null, - androidOnRenderProcessGone: androidOnRenderProcessGone != null - ? (controller, detail) => - androidOnRenderProcessGone.call(controller, detail) - : null, - onRenderProcessGone: onRenderProcessGone != null - ? (controller, detail) => - onRenderProcessGone.call(controller, detail) - : null, - androidOnRenderProcessResponsive: - androidOnRenderProcessResponsive != null - ? (controller, url) => - androidOnRenderProcessResponsive.call(controller, url) - : null, - onRenderProcessResponsive: onRenderProcessResponsive != null - ? (controller, url) => - onRenderProcessResponsive.call(controller, url) - : null, - androidOnRenderProcessUnresponsive: - androidOnRenderProcessUnresponsive != null - ? (controller, url) => - androidOnRenderProcessUnresponsive.call(controller, url) - : null, - onRenderProcessUnresponsive: onRenderProcessUnresponsive != null - ? (controller, url) => - onRenderProcessUnresponsive.call(controller, url) - : null, - androidOnFormResubmission: androidOnFormResubmission != null - ? (controller, url) => - androidOnFormResubmission.call(controller, url) - : null, - onFormResubmission: onFormResubmission != null - ? (controller, url) => onFormResubmission.call(controller, url) - : null, - androidOnScaleChanged: androidOnScaleChanged != null - ? (controller, oldScale, newScale) => - androidOnScaleChanged.call(controller, oldScale, newScale) - : null, - androidOnReceivedIcon: androidOnReceivedIcon != null - ? (controller, icon) => - androidOnReceivedIcon.call(controller, icon) - : null, - onReceivedIcon: onReceivedIcon != null - ? (controller, icon) => onReceivedIcon.call(controller, icon) - : null, - onFaviconChanged: onFaviconChanged != null - ? (controller, request) => - onFaviconChanged.call(controller, request) - : null, - androidOnReceivedTouchIconUrl: androidOnReceivedTouchIconUrl != null - ? (controller, url, precomposed) => androidOnReceivedTouchIconUrl - .call(controller, url, precomposed) - : null, - onReceivedTouchIconUrl: onReceivedTouchIconUrl != null - ? (controller, url, precomposed) => - onReceivedTouchIconUrl.call(controller, url, precomposed) - : null, - androidOnJsBeforeUnload: androidOnJsBeforeUnload != null - ? (controller, jsBeforeUnloadRequest) => androidOnJsBeforeUnload - .call(controller, jsBeforeUnloadRequest) - : null, - onJsBeforeUnload: onJsBeforeUnload != null - ? (controller, jsBeforeUnloadRequest) => - onJsBeforeUnload.call(controller, jsBeforeUnloadRequest) - : null, - androidOnReceivedLoginRequest: androidOnReceivedLoginRequest != null - ? (controller, loginRequest) => androidOnReceivedLoginRequest - .call(controller, loginRequest) - : null, - onReceivedLoginRequest: onReceivedLoginRequest != null - ? (controller, loginRequest) => - onReceivedLoginRequest.call(controller, loginRequest) - : null, - onPermissionRequestCanceled: onPermissionRequestCanceled != null - ? (controller, permissionRequest) => onPermissionRequestCanceled - .call(controller, permissionRequest) - : null, - onRequestFocus: onRequestFocus != null - ? (controller) => onRequestFocus.call(controller) - : null, - iosOnWebContentProcessDidTerminate: - iosOnWebContentProcessDidTerminate != null - ? (controller) => - iosOnWebContentProcessDidTerminate.call(controller) - : null, - onWebContentProcessDidTerminate: - onWebContentProcessDidTerminate != null - ? (controller) => - onWebContentProcessDidTerminate.call(controller) - : null, - iosOnDidReceiveServerRedirectForProvisionalNavigation: - iosOnDidReceiveServerRedirectForProvisionalNavigation != null - ? (controller) => - iosOnDidReceiveServerRedirectForProvisionalNavigation.call( - controller, - ) - : null, - onDidReceiveServerRedirectForProvisionalNavigation: - onDidReceiveServerRedirectForProvisionalNavigation != null - ? (controller) => - onDidReceiveServerRedirectForProvisionalNavigation.call( - controller, - ) - : null, - iosOnNavigationResponse: iosOnNavigationResponse != null - ? (controller, navigationResponse) => iosOnNavigationResponse - .call(controller, navigationResponse) - : null, - onNavigationResponse: onNavigationResponse != null - ? (controller, navigationResponse) => - onNavigationResponse.call(controller, navigationResponse) - : null, - iosShouldAllowDeprecatedTLS: iosShouldAllowDeprecatedTLS != null - ? (controller, challenge) => - iosShouldAllowDeprecatedTLS.call(controller, challenge) - : null, - shouldAllowDeprecatedTLS: shouldAllowDeprecatedTLS != null - ? (controller, challenge) => - shouldAllowDeprecatedTLS.call(controller, challenge) - : null, - onCameraCaptureStateChanged: onCameraCaptureStateChanged != null - ? (controller, oldState, newState) => onCameraCaptureStateChanged - .call(controller, oldState, newState) - : null, - onMicrophoneCaptureStateChanged: - onMicrophoneCaptureStateChanged != null - ? (controller, oldState, newState) => - onMicrophoneCaptureStateChanged.call( - controller, - oldState, - newState, - ) - : null, - onContentSizeChanged: onContentSizeChanged != null - ? (controller, oldContentSize, newContentSize) => - onContentSizeChanged.call( - controller, - oldContentSize, - newContentSize, - ) - : null, - onProcessFailed: onProcessFailed != null - ? (controller, detail) => - onProcessFailed.call(controller, detail) - : null, - onNotificationReceived: onNotificationReceived != null - ? (controller, request) => - onNotificationReceived.call(controller, request) - : null, - onSaveAsUIShowing: onSaveAsUIShowing != null - ? (controller, request) => - onSaveAsUIShowing.call(controller, request) - : null, - onSaveFileSecurityCheckStarting: - onSaveFileSecurityCheckStarting != null - ? (controller, request) => - onSaveFileSecurityCheckStarting.call(controller, request) - : null, - onScreenCaptureStarting: onScreenCaptureStarting != null - ? (controller, request) => - onScreenCaptureStarting.call(controller, request) - : null, - onAcceleratorKeyPressed: onAcceleratorKeyPressed != null - ? (controller, detail) => - onAcceleratorKeyPressed.call(controller, detail) - : null, - onShowFileChooser: onShowFileChooser != null - ? (controller, request) => - onShowFileChooser.call(controller, request) - : null, - onLaunchingExternalUriScheme: onLaunchingExternalUriScheme != null - ? (controller, request) => - onLaunchingExternalUriScheme.call(controller, request) - : null, - gestureRecognizers: gestureRecognizers, - headlessWebView: headlessWebView?.platform, - preventGestureDelay: preventGestureDelay, - ), - ); - - @override - _InAppWebViewState createState() => _InAppWebViewState(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewWidgetCreationParams.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformInAppWebViewWidget.static().isClassSupported(platform: platform); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewWidgetCreationParams.isPropertySupported} - static bool isPropertySupported( - dynamic property, { - TargetPlatform? platform, - }) => PlatformInAppWebViewWidget.static().isPropertySupported( - property, - platform: platform, - ); -} - -class _InAppWebViewState extends State { - @override - Widget build(BuildContext context) { - return widget.platform.build(context); - } - - @override - void dispose() { - widget.platform.dispose(); - super.dispose(); - } -} diff --git a/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart deleted file mode 100644 index d673c18491..0000000000 --- a/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart +++ /dev/null @@ -1,1053 +0,0 @@ -import 'dart:core'; - -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../print_job/main.dart'; -import '../web_message/main.dart'; -import '../web_storage/web_storage.dart'; -import 'android/in_app_webview_controller.dart'; -import 'apple/in_app_webview_controller.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.supported_platforms} -class InAppWebViewController { - ///Use [InAppWebViewController] instead. - @Deprecated("Use InAppWebViewController instead") - late AndroidInAppWebViewController android; - - ///Use [InAppWebViewController] instead. - @Deprecated("Use InAppWebViewController instead") - late IOSInAppWebViewController ios; - - /// Constructs a [InAppWebViewController]. - /// - /// See [InAppWebViewController.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - InAppWebViewController.fromPlatformCreationParams({ - required PlatformInAppWebViewControllerCreationParams params, - }) : this.fromPlatform(platform: PlatformInAppWebViewController(params)); - - /// Constructs a [InAppWebViewController] from a specific platform implementation. - InAppWebViewController.fromPlatform({required this.platform}) { - android = AndroidInAppWebViewController(controller: this.platform); - ios = IOSInAppWebViewController(controller: this.platform); - } - - /// Implementation of [PlatformInAppWebViewController] for the current platform. - final PlatformInAppWebViewController platform; - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.webStorage} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.webStorage.supported_platforms} - WebStorage get webStorage => - WebStorage.fromPlatform(platform: platform.webStorage); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getUrl} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getUrl.supported_platforms} - Future getUrl() => platform.getUrl(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getTitle} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getTitle.supported_platforms} - Future getTitle() => platform.getTitle(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getFrameId} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getFrameId.supported_platforms} - Future getFrameId() => platform.getFrameId(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getProgress} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getProgress.supported_platforms} - Future getProgress() => platform.getProgress(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getHtml} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getHtml.supported_platforms} - Future getHtml() => platform.getHtml(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getFavicons} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getFavicons.supported_platforms} - Future> getFavicons() => platform.getFavicons(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getFavicon} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getFavicon.supported_platforms} - Future getFavicon({ - required WebUri url, - FaviconImageFormat faviconImageFormat = FaviconImageFormat.PNG, - }) => platform.getFavicon(url: url, faviconImageFormat: faviconImageFormat); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.showSaveAsUI} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.showSaveAsUI.supported_platforms} - Future showSaveAsUI() => platform.showSaveAsUI(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getMemoryUsageTargetLevel} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getMemoryUsageTargetLevel.supported_platforms} - Future getMemoryUsageTargetLevel() => - platform.getMemoryUsageTargetLevel(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setMemoryUsageTargetLevel} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setMemoryUsageTargetLevel.supported_platforms} - Future setMemoryUsageTargetLevel(MemoryUsageTargetLevel level) => - platform.setMemoryUsageTargetLevel(level); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.loadUrl} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.loadUrl.supported_platforms} - Future loadUrl({ - required URLRequest urlRequest, - @Deprecated('Use allowingReadAccessTo instead') - Uri? iosAllowingReadAccessTo, - WebUri? allowingReadAccessTo, - }) => platform.loadUrl( - urlRequest: urlRequest, - iosAllowingReadAccessTo: iosAllowingReadAccessTo, - allowingReadAccessTo: allowingReadAccessTo, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.postUrl} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.postUrl.supported_platforms} - Future postUrl({required WebUri url, required Uint8List postData}) => - platform.postUrl(url: url, postData: postData); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.loadData} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.loadData.supported_platforms} - Future loadData({ - required String data, - String mimeType = "text/html", - String encoding = "utf8", - WebUri? baseUrl, - @Deprecated('Use historyUrl instead') Uri? androidHistoryUrl, - WebUri? historyUrl, - @Deprecated('Use allowingReadAccessTo instead') - Uri? iosAllowingReadAccessTo, - WebUri? allowingReadAccessTo, - }) => platform.loadData( - data: data, - mimeType: mimeType, - encoding: encoding, - baseUrl: baseUrl, - androidHistoryUrl: androidHistoryUrl, - historyUrl: historyUrl, - iosAllowingReadAccessTo: iosAllowingReadAccessTo, - allowingReadAccessTo: allowingReadAccessTo, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.loadFile} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.loadFile.supported_platforms} - Future loadFile({required String assetFilePath}) => - platform.loadFile(assetFilePath: assetFilePath); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.reload} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.reload.supported_platforms} - Future reload() => platform.reload(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.goBack} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.goBack.supported_platforms} - Future goBack() => platform.goBack(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.canGoBack} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.canGoBack.supported_platforms} - Future canGoBack() => platform.canGoBack(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.goForward} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.goForward.supported_platforms} - Future goForward() => platform.goForward(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.canGoForward} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.canGoForward.supported_platforms} - Future canGoForward() => platform.canGoForward(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.goBackOrForward} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.goBackOrForward.supported_platforms} - Future goBackOrForward({required int steps}) => - platform.goBackOrForward(steps: steps); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.canGoBackOrForward} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.canGoBackOrForward.supported_platforms} - Future canGoBackOrForward({required int steps}) => - platform.canGoBackOrForward(steps: steps); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.goTo} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.goTo.supported_platforms} - Future goTo({required WebHistoryItem historyItem}) => - platform.goTo(historyItem: historyItem); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isLoading} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isLoading.supported_platforms} - Future isLoading() => platform.isLoading(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.stopLoading} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.stopLoading.supported_platforms} - Future stopLoading() => platform.stopLoading(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.evaluateJavascript} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.evaluateJavascript.supported_platforms} - Future evaluateJavascript({ - required String source, - ContentWorld? contentWorld, - }) => platform.evaluateJavascript(source: source, contentWorld: contentWorld); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.injectJavascriptFileFromUrl} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.injectJavascriptFileFromUrl.supported_platforms} - Future injectJavascriptFileFromUrl({ - required WebUri urlFile, - ScriptHtmlTagAttributes? scriptHtmlTagAttributes, - }) => platform.injectJavascriptFileFromUrl( - urlFile: urlFile, - scriptHtmlTagAttributes: scriptHtmlTagAttributes, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.injectJavascriptFileFromAsset} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.injectJavascriptFileFromAsset.supported_platforms} - Future injectJavascriptFileFromAsset({ - required String assetFilePath, - }) => platform.injectJavascriptFileFromAsset(assetFilePath: assetFilePath); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.injectCSSCode} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.injectCSSCode.supported_platforms} - Future injectCSSCode({required String source}) => - platform.injectCSSCode(source: source); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.injectCSSFileFromUrl} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.injectCSSFileFromUrl.supported_platforms} - Future injectCSSFileFromUrl({ - required WebUri urlFile, - CSSLinkHtmlTagAttributes? cssLinkHtmlTagAttributes, - }) => platform.injectCSSFileFromUrl( - urlFile: urlFile, - cssLinkHtmlTagAttributes: cssLinkHtmlTagAttributes, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.injectCSSFileFromAsset} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.injectCSSFileFromAsset.supported_platforms} - Future injectCSSFileFromAsset({required String assetFilePath}) => - platform.injectCSSFileFromAsset(assetFilePath: assetFilePath); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.addJavaScriptHandler} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.addJavaScriptHandler.supported_platforms} - void addJavaScriptHandler({ - required String handlerName, - required Function callback, - }) => platform.addJavaScriptHandler( - handlerName: handlerName, - callback: callback, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.removeJavaScriptHandler} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.removeJavaScriptHandler.supported_platforms} - Function? removeJavaScriptHandler({required String handlerName}) => - platform.removeJavaScriptHandler(handlerName: handlerName); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.hasJavaScriptHandler} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.hasJavaScriptHandler.supported_platforms} - bool hasJavaScriptHandler({required String handlerName}) => - platform.hasJavaScriptHandler(handlerName: handlerName); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.takeScreenshot} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.takeScreenshot.supported_platforms} - Future takeScreenshot({ - ScreenshotConfiguration? screenshotConfiguration, - }) => - platform.takeScreenshot(screenshotConfiguration: screenshotConfiguration); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setOptions} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setOptions.supported_platforms} - @Deprecated('Use setSettings instead') - Future setOptions({required InAppWebViewGroupOptions options}) => - platform.setOptions(options: options); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getOptions} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getOptions.supported_platforms} - @Deprecated('Use getSettings instead') - Future getOptions() => platform.getOptions(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setSettings} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setSettings.supported_platforms} - Future setSettings({required InAppWebViewSettings settings}) => - platform.setSettings(settings: settings); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getSettings} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getSettings.supported_platforms} - Future getSettings() => platform.getSettings(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getCopyBackForwardList} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getCopyBackForwardList.supported_platforms} - Future getCopyBackForwardList() => - platform.getCopyBackForwardList(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearCache} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearCache.supported_platforms} - @Deprecated("Use InAppWebViewController.clearAllCache instead") - Future clearCache() => platform.clearCache(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.findAllAsync} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.findAllAsync.supported_platforms} - @Deprecated("Use FindInteractionController.findAll instead") - Future findAllAsync({required String find}) => - platform.findAllAsync(find: find); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.findNext} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.findNext.supported_platforms} - @Deprecated("Use FindInteractionController.findNext instead") - Future findNext({required bool forward}) => - platform.findNext(forward: forward); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearMatches} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearMatches.supported_platforms} - @Deprecated("Use FindInteractionController.clearMatches instead") - Future clearMatches() => platform.clearMatches(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getTRexRunnerHtml} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getTRexRunnerHtml.supported_platforms} - @Deprecated("Use tRexRunnerHtml instead") - Future getTRexRunnerHtml() => platform.getTRexRunnerHtml(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getTRexRunnerCss} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getTRexRunnerCss.supported_platforms} - @Deprecated("Use tRexRunnerCss instead") - Future getTRexRunnerCss() => platform.getTRexRunnerCss(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.scrollTo} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.scrollTo.supported_platforms} - Future scrollTo({ - required int x, - required int y, - bool animated = false, - }) => platform.scrollTo(x: x, y: y, animated: animated); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.scrollBy} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.scrollBy.supported_platforms} - Future scrollBy({ - required int x, - required int y, - bool animated = false, - }) => platform.scrollBy(x: x, y: y, animated: animated); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.pauseTimers} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.pauseTimers.supported_platforms} - Future pauseTimers() => platform.pauseTimers(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.resumeTimers} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.resumeTimers.supported_platforms} - Future resumeTimers() => platform.resumeTimers(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.printCurrentPage} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.printCurrentPage.supported_platforms} - Future printCurrentPage({ - PrintJobSettings? settings, - }) async { - final printJobControllerPlatform = await platform.printCurrentPage( - settings: settings, - ); - if (printJobControllerPlatform == null) { - return null; - } - return PrintJobController.fromPlatform( - platform: printJobControllerPlatform, - ); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getContentHeight} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getContentHeight.supported_platforms} - Future getContentHeight() => platform.getContentHeight(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getContentWidth} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getContentWidth.supported_platforms} - Future getContentWidth() => platform.getContentWidth(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.zoomBy} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.zoomBy.supported_platforms} - Future zoomBy({ - required double zoomFactor, - @Deprecated('Use animated instead') bool? iosAnimated, - bool animated = false, - }) => platform.zoomBy( - zoomFactor: zoomFactor, - iosAnimated: iosAnimated, - animated: animated, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getOriginalUrl} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getOriginalUrl.supported_platforms} - Future getOriginalUrl() => platform.getOriginalUrl(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getZoomScale} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getZoomScale.supported_platforms} - Future getZoomScale() => platform.getZoomScale(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getScale} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getScale.supported_platforms} - @Deprecated('Use getZoomScale instead') - Future getScale() => platform.getScale(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getSelectedText} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getSelectedText.supported_platforms} - Future getSelectedText() => platform.getSelectedText(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getHitTestResult} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getHitTestResult.supported_platforms} - Future getHitTestResult() => - platform.getHitTestResult(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestFocus} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestFocus.supported_platforms} - Future requestFocus({ - FocusDirection? direction, - InAppWebViewRect? previouslyFocusedRect, - }) => platform.requestFocus( - direction: direction, - previouslyFocusedRect: previouslyFocusedRect, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearFocus} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearFocus.supported_platforms} - Future clearFocus() => platform.clearFocus(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setInputMethodEnabled} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setInputMethodEnabled.supported_platforms} - Future setInputMethodEnabled(bool enabled) => - platform.setInputMethodEnabled(enabled); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.showInputMethod} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.showInputMethod.supported_platforms} - Future showInputMethod() => platform.showInputMethod(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.hideInputMethod} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.hideInputMethod.supported_platforms} - Future hideInputMethod() => platform.hideInputMethod(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setContextMenu} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setContextMenu.supported_platforms} - Future setContextMenu(ContextMenu? contextMenu) => - platform.setContextMenu(contextMenu); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestFocusNodeHref} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestFocusNodeHref.supported_platforms} - Future requestFocusNodeHref() => - platform.requestFocusNodeHref(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestImageRef} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestImageRef.supported_platforms} - Future requestImageRef() => - platform.requestImageRef(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getMetaTags} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getMetaTags.supported_platforms} - Future> getMetaTags() => platform.getMetaTags(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getMetaThemeColor} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getMetaThemeColor.supported_platforms} - Future getMetaThemeColor() => platform.getMetaThemeColor(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getScrollX} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getScrollX.supported_platforms} - Future getScrollX() => platform.getScrollX(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getScrollY} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getScrollY.supported_platforms} - Future getScrollY() => platform.getScrollY(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getCertificate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getCertificate.supported_platforms} - Future getCertificate() => platform.getCertificate(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.addUserScript} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.addUserScript.supported_platforms} - Future addUserScript({required UserScript userScript}) => - platform.addUserScript(userScript: userScript); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.addUserScripts} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.addUserScripts.supported_platforms} - Future addUserScripts({required List userScripts}) => - platform.addUserScripts(userScripts: userScripts); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.removeUserScript} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.removeUserScript.supported_platforms} - Future removeUserScript({required UserScript userScript}) => - platform.removeUserScript(userScript: userScript); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.removeUserScriptsByGroupName} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.removeUserScriptsByGroupName.supported_platforms} - Future removeUserScriptsByGroupName({required String groupName}) => - platform.removeUserScriptsByGroupName(groupName: groupName); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.removeUserScripts} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.removeUserScripts.supported_platforms} - Future removeUserScripts({required List userScripts}) => - platform.removeUserScripts(userScripts: userScripts); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.removeAllUserScripts} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.removeAllUserScripts.supported_platforms} - Future removeAllUserScripts() => platform.removeAllUserScripts(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.hasUserScript} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.hasUserScript.supported_platforms} - bool hasUserScript({required UserScript userScript}) => - platform.hasUserScript(userScript: userScript); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.callAsyncJavaScript} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.callAsyncJavaScript.supported_platforms} - Future callAsyncJavaScript({ - required String functionBody, - Map arguments = const {}, - ContentWorld? contentWorld, - }) => platform.callAsyncJavaScript( - functionBody: functionBody, - arguments: arguments, - contentWorld: contentWorld, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.saveWebArchive} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.saveWebArchive.supported_platforms} - Future saveWebArchive({ - required String filePath, - bool autoname = false, - }) => platform.saveWebArchive(filePath: filePath, autoname: autoname); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isSecureContext} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isSecureContext.supported_platforms} - Future isSecureContext() => platform.isSecureContext(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.createWebMessageChannel} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.createWebMessageChannel.supported_platforms} - Future createWebMessageChannel() async { - final webMessagePlatform = await platform.createWebMessageChannel(); - if (webMessagePlatform == null) { - return null; - } - return WebMessageChannel.fromPlatform(platform: webMessagePlatform); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.postWebMessage} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.postWebMessage.supported_platforms} - Future postWebMessage({ - required WebMessage message, - WebUri? targetOrigin, - }) => platform.postWebMessage(message: message, targetOrigin: targetOrigin); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.addWebMessageListener} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.addWebMessageListener.supported_platforms} - Future addWebMessageListener(WebMessageListener webMessageListener) => - platform.addWebMessageListener(webMessageListener.platform); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.hasWebMessageListener} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.hasWebMessageListener.supported_platforms} - bool hasWebMessageListener(WebMessageListener webMessageListener) => - platform.hasWebMessageListener(webMessageListener.platform); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.canScrollVertically} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.canScrollVertically.supported_platforms} - Future canScrollVertically() => platform.canScrollVertically(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.canScrollHorizontally} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.canScrollHorizontally.supported_platforms} - Future canScrollHorizontally() => platform.canScrollHorizontally(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.startSafeBrowsing} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.startSafeBrowsing.supported_platforms} - Future startSafeBrowsing() => platform.startSafeBrowsing(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearSslPreferences} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearSslPreferences.supported_platforms} - Future clearSslPreferences() => platform.clearSslPreferences(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.pause} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.pause.supported_platforms} - Future pause() => platform.pause(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.resume} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.resume.supported_platforms} - Future resume() => platform.resume(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.pageDown} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.pageDown.supported_platforms} - Future pageDown({required bool bottom}) => - platform.pageDown(bottom: bottom); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.pageUp} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.pageUp.supported_platforms} - Future pageUp({required bool top}) => platform.pageUp(top: top); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.zoomIn} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.zoomIn.supported_platforms} - Future zoomIn() => platform.zoomIn(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.zoomOut} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.zoomOut.supported_platforms} - Future zoomOut() => platform.zoomOut(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearHistory} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearHistory.supported_platforms} - Future clearHistory() => platform.clearHistory(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.reloadFromOrigin} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.reloadFromOrigin.supported_platforms} - Future reloadFromOrigin() => platform.reloadFromOrigin(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.createPdf} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.createPdf.supported_platforms} - Future createPdf({ - @Deprecated("Use pdfConfiguration instead") - // ignore: deprecated_member_use_from_same_package - IOSWKPDFConfiguration? iosWKPdfConfiguration, - PDFConfiguration? pdfConfiguration, - }) => platform.createPdf( - iosWKPdfConfiguration: iosWKPdfConfiguration, - pdfConfiguration: pdfConfiguration, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.createWebArchiveData} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.createWebArchiveData.supported_platforms} - Future createWebArchiveData() => platform.createWebArchiveData(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.hasOnlySecureContent} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.hasOnlySecureContent.supported_platforms} - Future hasOnlySecureContent() => platform.hasOnlySecureContent(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.pauseAllMediaPlayback} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.pauseAllMediaPlayback.supported_platforms} - Future pauseAllMediaPlayback() => platform.pauseAllMediaPlayback(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setAllMediaPlaybackSuspended} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setAllMediaPlaybackSuspended.supported_platforms} - Future setAllMediaPlaybackSuspended({required bool suspended}) => - platform.setAllMediaPlaybackSuspended(suspended: suspended); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.closeAllMediaPresentations} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.closeAllMediaPresentations.supported_platforms} - Future closeAllMediaPresentations() => - platform.closeAllMediaPresentations(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestMediaPlaybackState} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestMediaPlaybackState.supported_platforms} - Future requestMediaPlaybackState() => - platform.requestMediaPlaybackState(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isInFullscreen} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isInFullscreen.supported_platforms} - Future isInFullscreen() => platform.isInFullscreen(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestEnterFullscreen} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestEnterFullscreen.supported_platforms} - Future requestEnterFullscreen() => platform.requestEnterFullscreen(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestExitFullscreen} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestExitFullscreen.supported_platforms} - Future requestExitFullscreen() => platform.requestExitFullscreen(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setVisible} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setVisible.supported_platforms} - Future setVisible({required bool visible}) => - platform.setVisible(visible: visible); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setTargetRefreshRate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setTargetRefreshRate.supported_platforms} - Future setTargetRefreshRate({required int rate}) => - platform.setTargetRefreshRate(rate: rate); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getTargetRefreshRate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getTargetRefreshRate.supported_platforms} - Future getTargetRefreshRate() => platform.getTargetRefreshRate(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getScreenScale} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getScreenScale.supported_platforms} - Future getScreenScale() => platform.getScreenScale(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setScreenScale} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setScreenScale.supported_platforms} - Future setScreenScale({required double scale}) => - platform.setScreenScale(scale: scale); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isVisible} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isVisible.supported_platforms} - Future isVisible() => platform.isVisible(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestPointerLock} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestPointerLock.supported_platforms} - Future requestPointerLock() => platform.requestPointerLock(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestPointerUnlock} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestPointerUnlock.supported_platforms} - Future requestPointerUnlock() => platform.requestPointerUnlock(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearFormData} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearFormData.supported_platforms} - Future clearFormData() => platform.clearFormData(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getCameraCaptureState} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getCameraCaptureState.supported_platforms} - Future getCameraCaptureState() => - platform.getCameraCaptureState(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setCameraCaptureState} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setCameraCaptureState.supported_platforms} - Future setCameraCaptureState({required MediaCaptureState state}) => - platform.setCameraCaptureState(state: state); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getMicrophoneCaptureState} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getMicrophoneCaptureState.supported_platforms} - Future getMicrophoneCaptureState() => - platform.getMicrophoneCaptureState(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setMicrophoneCaptureState} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setMicrophoneCaptureState.supported_platforms} - Future setMicrophoneCaptureState({required MediaCaptureState state}) => - platform.setMicrophoneCaptureState(state: state); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isPlayingAudio} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isPlayingAudio.supported_platforms} - Future isPlayingAudio() => platform.isPlayingAudio(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isMuted} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isMuted.supported_platforms} - Future isMuted() => platform.isMuted(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setMuted} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setMuted.supported_platforms} - Future setMuted({required bool muted}) => - platform.setMuted(muted: muted); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.terminateWebProcess} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.terminateWebProcess.supported_platforms} - Future terminateWebProcess() => platform.terminateWebProcess(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.loadSimulatedRequest} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.loadSimulatedRequest.supported_platforms} - Future loadSimulatedRequest({ - required URLRequest urlRequest, - required Uint8List data, - URLResponse? urlResponse, - }) => platform.loadSimulatedRequest(urlRequest: urlRequest, data: data); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.openDevTools} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.openDevTools.supported_platforms} - Future openDevTools() => platform.openDevTools(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.callDevToolsProtocolMethod} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.callDevToolsProtocolMethod.supported_platforms} - Future callDevToolsProtocolMethod({ - required String methodName, - Map? parameters, - }) => platform.callDevToolsProtocolMethod( - methodName: methodName, - parameters: parameters, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.addDevToolsProtocolEventListener} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.addDevToolsProtocolEventListener.supported_platforms} - Future addDevToolsProtocolEventListener({ - required String eventName, - required Function(dynamic data) callback, - }) => platform.addDevToolsProtocolEventListener( - eventName: eventName, - callback: callback, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.removeDevToolsProtocolEventListener} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.removeDevToolsProtocolEventListener.supported_platforms} - Future removeDevToolsProtocolEventListener({ - required String eventName, - }) => platform.removeDevToolsProtocolEventListener(eventName: eventName); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isInterfaceSupported} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isInterfaceSupported.supported_platforms} - Future isInterfaceSupported(WebViewInterface interface) => - platform.isInterfaceSupported(interface); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.saveState} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.saveState.supported_platforms} - Future saveState() => platform.saveState(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.restoreState} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.restoreState.supported_platforms} - Future restoreState(Uint8List state) => platform.restoreState(state); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getIFrameId} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getIFrameId.supported_platforms} - Future getIFrameId() => platform.getIFrameId(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getDefaultUserAgent} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getDefaultUserAgent.supported_platforms} - static Future getDefaultUserAgent() => - PlatformInAppWebViewController.static().getDefaultUserAgent(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearClientCertPreferences} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearClientCertPreferences.supported_platforms} - static Future clearClientCertPreferences() => - PlatformInAppWebViewController.static().clearClientCertPreferences(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getSafeBrowsingPrivacyPolicyUrl} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getSafeBrowsingPrivacyPolicyUrl.supported_platforms} - static Future getSafeBrowsingPrivacyPolicyUrl() => - PlatformInAppWebViewController.static().getSafeBrowsingPrivacyPolicyUrl(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setSafeBrowsingWhitelist} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setSafeBrowsingWhitelist.supported_platforms} - @Deprecated("Use setSafeBrowsingAllowlist instead") - static Future setSafeBrowsingWhitelist({required List hosts}) => - PlatformInAppWebViewController.static().setSafeBrowsingWhitelist( - hosts: hosts, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setSafeBrowsingAllowlist} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setSafeBrowsingAllowlist.supported_platforms} - static Future setSafeBrowsingAllowlist({required List hosts}) => - PlatformInAppWebViewController.static().setSafeBrowsingAllowlist( - hosts: hosts, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getCurrentWebViewPackage} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getCurrentWebViewPackage.supported_platforms} - static Future getCurrentWebViewPackage() => - PlatformInAppWebViewController.static().getCurrentWebViewPackage(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setWebContentsDebuggingEnabled} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setWebContentsDebuggingEnabled.supported_platforms} - static Future setWebContentsDebuggingEnabled(bool debuggingEnabled) => - PlatformInAppWebViewController.static().setWebContentsDebuggingEnabled( - debuggingEnabled, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getVariationsHeader} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getVariationsHeader.supported_platforms} - static Future getVariationsHeader() => - PlatformInAppWebViewController.static().getVariationsHeader(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isMultiProcessEnabled} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isMultiProcessEnabled.supported_platforms} - static Future isMultiProcessEnabled() => - PlatformInAppWebViewController.static().isMultiProcessEnabled(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.disableWebView} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.disableWebView.supported_platforms} - static Future disableWebView() => - PlatformInAppWebViewController.static().disableWebView(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.handlesURLScheme} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.handlesURLScheme.supported_platforms} - static Future handlesURLScheme(String urlScheme) => - PlatformInAppWebViewController.static().handlesURLScheme(urlScheme); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.disposeKeepAlive} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.disposeKeepAlive.supported_platforms} - static Future disposeKeepAlive(InAppWebViewKeepAlive keepAlive) => - PlatformInAppWebViewController.static().disposeKeepAlive(keepAlive); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearAllCache} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearAllCache.supported_platforms} - static Future clearAllCache({bool includeDiskFiles = true}) => - PlatformInAppWebViewController.static().clearAllCache( - includeDiskFiles: includeDiskFiles, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.enableSlowWholeDocumentDraw} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.enableSlowWholeDocumentDraw.supported_platforms} - static Future enableSlowWholeDocumentDraw() => - PlatformInAppWebViewController.static().enableSlowWholeDocumentDraw(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setJavaScriptBridgeName} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setJavaScriptBridgeName.supported_platforms} - static Future setJavaScriptBridgeName(String bridgeName) => - PlatformInAppWebViewController.static().setJavaScriptBridgeName( - bridgeName, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getJavaScriptBridgeName} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getJavaScriptBridgeName.supported_platforms} - static Future getJavaScriptBridgeName() => - PlatformInAppWebViewController.static().getJavaScriptBridgeName(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.tRexRunnerHtml} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.tRexRunnerHtml.supported_platforms} - static Future get tRexRunnerHtml => - PlatformInAppWebViewController.static().tRexRunnerHtml; - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.tRexRunnerCss} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.tRexRunnerCss.supported_platforms} - static Future get tRexRunnerCss => - PlatformInAppWebViewController.static().tRexRunnerCss; - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformInAppWebViewController.static().isClassSupported( - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isPropertySupported} - static bool isPropertySupported( - PlatformInAppWebViewControllerProperty property, { - TargetPlatform? platform, - }) => PlatformInAppWebViewController.static().isPropertySupported( - property, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.isMethodSupported} - static bool isMethodSupported( - PlatformInAppWebViewControllerMethod method, { - TargetPlatform? platform, - }) => PlatformInAppWebViewController.static().isMethodSupported( - method, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getViewId} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getViewId.supported_platforms} - dynamic getViewId() => platform.getViewId(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.dispose} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.dispose.supported_platforms} - void dispose({bool isKeepAlive = false}) => - platform.dispose(isKeepAlive: isKeepAlive); -} diff --git a/flutter_inappwebview/lib/src/in_app_webview/main.dart b/flutter_inappwebview/lib/src/in_app_webview/main.dart deleted file mode 100644 index 900cef929b..0000000000 --- a/flutter_inappwebview/lib/src/in_app_webview/main.dart +++ /dev/null @@ -1,6 +0,0 @@ -export 'in_app_webview.dart'; -export 'in_app_webview_controller.dart'; -export 'headless_in_app_webview.dart'; -export 'android/main.dart'; -export 'apple/main.dart'; -export '../find_interaction/find_interaction_controller.dart'; diff --git a/flutter_inappwebview/lib/src/main.dart b/flutter_inappwebview/lib/src/main.dart deleted file mode 100644 index f4d56ade25..0000000000 --- a/flutter_inappwebview/lib/src/main.dart +++ /dev/null @@ -1,19 +0,0 @@ -export 'in_app_webview/main.dart'; -export 'in_app_browser/main.dart'; -export 'chrome_safari_browser/main.dart'; -export 'web_storage/main.dart'; -export 'cookie_manager.dart'; -export 'http_auth_credentials_database.dart'; -export 'pull_to_refresh/main.dart'; -export 'web_message/main.dart'; -export 'web_authentication_session/main.dart'; -export 'web_notification/main.dart'; -export 'print_job/main.dart'; -export 'find_interaction/main.dart'; -export 'service_worker_controller.dart'; -export 'proxy_controller.dart'; -export 'webview_asset_loader.dart'; -export 'tracing_controller.dart'; -export 'process_global_config.dart'; -export 'in_app_localhost_server.dart'; -export 'webview_environment/main.dart'; diff --git a/flutter_inappwebview/lib/src/print_job/main.dart b/flutter_inappwebview/lib/src/print_job/main.dart deleted file mode 100644 index 4e70ad9405..0000000000 --- a/flutter_inappwebview/lib/src/print_job/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'print_job_controller.dart'; diff --git a/flutter_inappwebview/lib/src/print_job/print_job_controller.dart b/flutter_inappwebview/lib/src/print_job/print_job_controller.dart deleted file mode 100644 index 3e9323d3bd..0000000000 --- a/flutter_inappwebview/lib/src/print_job/print_job_controller.dart +++ /dev/null @@ -1,91 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.supported_platforms} -class PrintJobController { - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.supported_platforms} - PrintJobController({required String id}) - : this.fromPlatformCreationParams( - params: PlatformPrintJobControllerCreationParams(id: id), - ); - - /// Constructs a [PrintJobController]. - /// - /// See [PrintJobController.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - PrintJobController.fromPlatformCreationParams({ - required PlatformPrintJobControllerCreationParams params, - }) : this.fromPlatform(platform: PlatformPrintJobController(params)); - - /// Constructs a [PrintJobController] from a specific platform implementation. - PrintJobController.fromPlatform({required this.platform}); - - /// Implementation of [PlatformPrintJobController] for the current platform. - final PlatformPrintJobController platform; - - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.id} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.id.supported_platforms} - String get id => platform.id; - - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.onComplete} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.onComplete.supported_platforms} - PrintJobCompletionHandler? get onComplete => platform.onComplete; - - void set onComplete(PrintJobCompletionHandler? handler) { - platform.onComplete = handler; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.cancel} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.cancel.supported_platforms} - Future cancel() => platform.cancel(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.restart} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.restart.supported_platforms} - Future restart() => platform.restart(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.dismiss} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.dismiss.supported_platforms} - Future dismiss({bool animated = true}) => - platform.dismiss(animated: animated); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.getInfo} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.getInfo.supported_platforms} - Future getInfo() => platform.getInfo(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.dispose} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.dispose.supported_platforms} - void dispose() => platform.dispose(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobControllerCreationParams.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformPrintJobController.static().isClassSupported(platform: platform); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.isPropertySupported} - static bool isPropertySupported( - dynamic property, { - TargetPlatform? platform, - }) => PlatformPrintJobController.static().isPropertySupported( - property, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController.isMethodSupported} - static bool isMethodSupported( - PlatformPrintJobControllerMethod method, { - TargetPlatform? platform, - }) => PlatformPrintJobController.static().isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview/lib/src/process_global_config.dart b/flutter_inappwebview/lib/src/process_global_config.dart deleted file mode 100644 index a5522b6bee..0000000000 --- a/flutter_inappwebview/lib/src/process_global_config.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'dart:async'; -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformProcessGlobalConfig} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformProcessGlobalConfig.supported_platforms} -class ProcessGlobalConfig { - ///{@macro flutter_inappwebview_platform_interface.PlatformProcessGlobalConfig} - ProcessGlobalConfig() - : this.fromPlatformCreationParams( - const PlatformProcessGlobalConfigCreationParams(), - ); - - /// Constructs a [ProcessGlobalConfig] from creation params for a specific - /// platform. - ProcessGlobalConfig.fromPlatformCreationParams( - PlatformProcessGlobalConfigCreationParams params, - ) : this.fromPlatform(PlatformProcessGlobalConfig(params)); - - /// Constructs a [ProcessGlobalConfig] from a specific platform - /// implementation. - ProcessGlobalConfig.fromPlatform(this.platform); - - /// Implementation of [PlatformProcessGlobalConfig] for the current platform. - final PlatformProcessGlobalConfig platform; - - static ProcessGlobalConfig? _instance; - - ///Gets the [ProcessGlobalConfig] shared instance. - static ProcessGlobalConfig instance() { - if (_instance == null) { - _instance = ProcessGlobalConfig(); - } - return _instance!; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformProcessGlobalConfig.apply} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformProcessGlobalConfig.apply.supported_platforms} - Future apply({required ProcessGlobalConfigSettings settings}) => - platform.apply(settings: settings); - - ///{@macro flutter_inappwebview_platform_interface.PlatformProcessGlobalConfigCreationParams.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformProcessGlobalConfig.static().isClassSupported(platform: platform); - - ///{@macro flutter_inappwebview_platform_interface.PlatformProcessGlobalConfig.isMethodSupported} - static bool isMethodSupported( - PlatformProcessGlobalConfigMethod method, { - TargetPlatform? platform, - }) => PlatformProcessGlobalConfig.static().isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview/lib/src/proxy_controller.dart b/flutter_inappwebview/lib/src/proxy_controller.dart deleted file mode 100644 index 31511042a4..0000000000 --- a/flutter_inappwebview/lib/src/proxy_controller.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformProxyController} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformProxyController.supported_platforms} -class ProxyController { - ///{@macro flutter_inappwebview_platform_interface.PlatformProxyController} - ProxyController() - : this.fromPlatformCreationParams( - const PlatformProxyControllerCreationParams(), - ); - - /// Constructs a [ProxyController] from creation params for a specific - /// platform. - ProxyController.fromPlatformCreationParams( - PlatformProxyControllerCreationParams params, - ) : this.fromPlatform(PlatformProxyController(params)); - - /// Constructs a [ProxyController] from a specific platform - /// implementation. - ProxyController.fromPlatform(this.platform); - - /// Implementation of [PlatformProxyController] for the current platform. - final PlatformProxyController platform; - - static ProxyController? _instance; - - ///Gets the [ProxyController] shared instance. - static ProxyController instance() { - if (_instance == null) { - _instance = ProxyController(); - } - return _instance!; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformProxyController.setProxyOverride} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformProxyController.setProxyOverride.supported_platforms} - Future setProxyOverride({required ProxySettings settings}) => - platform.setProxyOverride(settings: settings); - - ///{@macro flutter_inappwebview_platform_interface.PlatformProxyController.clearProxyOverride} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformProxyController.clearProxyOverride.supported_platforms} - Future clearProxyOverride() => platform.clearProxyOverride(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformProxyControllerCreationParams.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformProxyController.static().isClassSupported(platform: platform); - - ///{@macro flutter_inappwebview_platform_interface.PlatformProxyController.isMethodSupported} - static bool isMethodSupported( - PlatformProxyControllerMethod method, { - TargetPlatform? platform, - }) => PlatformProxyController.static().isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview/lib/src/pull_to_refresh/main.dart b/flutter_inappwebview/lib/src/pull_to_refresh/main.dart deleted file mode 100644 index dd2f106af9..0000000000 --- a/flutter_inappwebview/lib/src/pull_to_refresh/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'pull_to_refresh_controller.dart'; diff --git a/flutter_inappwebview/lib/src/pull_to_refresh/pull_to_refresh_controller.dart b/flutter_inappwebview/lib/src/pull_to_refresh/pull_to_refresh_controller.dart deleted file mode 100644 index bba9842020..0000000000 --- a/flutter_inappwebview/lib/src/pull_to_refresh/pull_to_refresh_controller.dart +++ /dev/null @@ -1,163 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.supported_platforms} -class PullToRefreshController { - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.supported_platforms} - PullToRefreshController({ - void Function()? onRefresh, - @Deprecated("Use settings instead") PullToRefreshOptions? options, - PullToRefreshSettings? settings, - }) : this.fromPlatformCreationParams( - params: PlatformPullToRefreshControllerCreationParams( - onRefresh: onRefresh, - options: options, - settings: settings, - ), - ); - - /// Constructs a [PullToRefreshController]. - /// - /// See [PullToRefreshController.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - PullToRefreshController.fromPlatformCreationParams({ - required PlatformPullToRefreshControllerCreationParams params, - }) : this.fromPlatform(platform: PlatformPullToRefreshController(params)); - - /// Constructs a [PullToRefreshController] from a specific platform implementation. - PullToRefreshController.fromPlatform({required this.platform}); - - /// Implementation of [PlatformPullToRefreshController] for the current platform. - final PlatformPullToRefreshController platform; - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.options} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.options.supported_platforms} - @Deprecated("Use settings instead") - PullToRefreshOptions get options => platform.options; - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.settings} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.settings.supported_platforms} - PullToRefreshSettings get settings => platform.settings; - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.onRefresh} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.onRefresh.supported_platforms} - void Function()? get onRefresh => platform.onRefresh; - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setEnabled} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setEnabled.supported_platforms} - Future setEnabled(bool enabled) => platform.setEnabled(enabled); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.isEnabled} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.isEnabled.supported_platforms} - Future isEnabled() => platform.isEnabled(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.beginRefreshing} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.beginRefreshing.supported_platforms} - Future beginRefreshing() => platform.beginRefreshing(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.endRefreshing} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.endRefreshing.supported_platforms} - Future endRefreshing() => platform.endRefreshing(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.isRefreshing} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.isRefreshing.supported_platforms} - Future isRefreshing() => platform.isRefreshing(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setColor} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setColor.supported_platforms} - Future setColor(Color color) => platform.setColor(color); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setBackgroundColor} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setBackgroundColor.supported_platforms} - Future setBackgroundColor(Color color) => - platform.setBackgroundColor(color); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setDistanceToTriggerSync} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setDistanceToTriggerSync.supported_platforms} - Future setDistanceToTriggerSync(int distanceToTriggerSync) => - platform.setDistanceToTriggerSync(distanceToTriggerSync); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setSlingshotDistance} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setSlingshotDistance.supported_platforms} - Future setSlingshotDistance(int slingshotDistance) => - platform.setSlingshotDistance(slingshotDistance); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.getDefaultSlingshotDistance} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.getDefaultSlingshotDistance.supported_platforms} - Future getDefaultSlingshotDistance() => - platform.getDefaultSlingshotDistance(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setSize} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setSize.supported_platforms} - @Deprecated("Use setIndicatorSize instead") - Future setSize(AndroidPullToRefreshSize size) => platform.setSize(size); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setIndicatorSize} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setIndicatorSize.supported_platforms} - Future setIndicatorSize(PullToRefreshSize size) => - platform.setIndicatorSize(size); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setAttributedTitle} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setAttributedTitle.supported_platforms} - @Deprecated("Use setStyledTitle instead") - Future setAttributedTitle(IOSNSAttributedString attributedTitle) => - platform.setAttributedTitle(attributedTitle); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setStyledTitle} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.setStyledTitle.supported_platforms} - Future setStyledTitle(AttributedString attributedTitle) => - platform.setStyledTitle(attributedTitle); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.dispose} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.dispose.supported_platforms} - void dispose({bool isKeepAlive = false}) => - platform.dispose(isKeepAlive: isKeepAlive); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformPullToRefreshController.static().isClassSupported( - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.isPropertySupported} - static bool isPropertySupported( - PlatformPullToRefreshControllerCreationParamsProperty property, { - TargetPlatform? platform, - }) => PlatformPullToRefreshController.static().isPropertySupported( - property, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController.isMethodSupported} - static bool isMethodSupported( - PlatformPullToRefreshControllerMethod method, { - TargetPlatform? platform, - }) => PlatformPullToRefreshController.static().isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview/lib/src/service_worker_controller.dart b/flutter_inappwebview/lib/src/service_worker_controller.dart deleted file mode 100644 index f7074334e2..0000000000 --- a/flutter_inappwebview/lib/src/service_worker_controller.dart +++ /dev/null @@ -1,263 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.supported_platforms} -class ServiceWorkerController { - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController} - ServiceWorkerController() - : this.fromPlatformCreationParams( - const PlatformServiceWorkerControllerCreationParams(), - ); - - /// Constructs a [ServiceWorkerController] from creation params for a specific - /// platform. - ServiceWorkerController.fromPlatformCreationParams( - PlatformServiceWorkerControllerCreationParams params, - ) : this.fromPlatform(PlatformServiceWorkerController(params)); - - /// Constructs a [ServiceWorkerController] from a specific platform - /// implementation. - ServiceWorkerController.fromPlatform(this.platform); - - /// Implementation of [PlatformServiceWorkerController] for the current platform. - final PlatformServiceWorkerController platform; - - static ServiceWorkerController? _instance; - - ///Gets the [ServiceWorkerController] shared instance. - static ServiceWorkerController instance() { - if (_instance == null) { - _instance = ServiceWorkerController(); - } - return _instance!; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.serviceWorkerClient} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.serviceWorkerClient.supported_platforms} - ServiceWorkerClient? get serviceWorkerClient => platform.serviceWorkerClient; - - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.setServiceWorkerClient} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.setServiceWorkerClient.supported_platforms} - setServiceWorkerClient(ServiceWorkerClient? value) => - platform.setServiceWorkerClient(value); - - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.getAllowContentAccess} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.getAllowContentAccess.supported_platforms} - static Future getAllowContentAccess() => - PlatformServiceWorkerController.static().getAllowContentAccess(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.getAllowFileAccess} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.getAllowFileAccess.supported_platforms} - static Future getAllowFileAccess() => - PlatformServiceWorkerController.static().getAllowFileAccess(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.getBlockNetworkLoads} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.getBlockNetworkLoads.supported_platforms} - static Future getBlockNetworkLoads() => - PlatformServiceWorkerController.static().getBlockNetworkLoads(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.getCacheMode} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.getCacheMode.supported_platforms} - static Future getCacheMode() => - PlatformServiceWorkerController.static().getCacheMode(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.setAllowContentAccess} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.setAllowContentAccess.supported_platforms} - static Future setAllowContentAccess(bool allow) => - PlatformServiceWorkerController.static().setAllowContentAccess(allow); - - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.setAllowFileAccess} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.setAllowFileAccess.supported_platforms} - static Future setAllowFileAccess(bool allow) => - PlatformServiceWorkerController.static().setAllowFileAccess(allow); - - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.setBlockNetworkLoads} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.setBlockNetworkLoads.supported_platforms} - static Future setBlockNetworkLoads(bool flag) => - PlatformServiceWorkerController.static().setBlockNetworkLoads(flag); - - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.setCacheMode} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.setCacheMode.supported_platforms} - static Future setCacheMode(CacheMode mode) => - PlatformServiceWorkerController.static().setCacheMode(mode); - - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerControllerCreationParams.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformServiceWorkerController.static().isClassSupported( - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController.isMethodSupported} - static bool isMethodSupported( - PlatformServiceWorkerControllerMethod method, { - TargetPlatform? platform, - }) => PlatformServiceWorkerController.static().isMethodSupported( - method, - platform: platform, - ); -} - -///Class that represents an Android-specific class that manages Service Workers used by `WebView`. -/// -///**NOTE**: available on Android 24+. -/// -///**Official Android API**: https://developer.android.com/reference/androidx/webkit/ServiceWorkerControllerCompat -/// -///Use [ServiceWorkerController] instead. -@Deprecated("Use ServiceWorkerController instead") -class AndroidServiceWorkerController { - static AndroidServiceWorkerController? _instance; - - AndroidServiceWorkerClient? _serviceWorkerClient; - - AndroidServiceWorkerClient? get serviceWorkerClient => _serviceWorkerClient; - - ///Gets the [AndroidServiceWorkerController] shared instance. - static AndroidServiceWorkerController instance() { - return (_instance != null) ? _instance! : _init(); - } - - static AndroidServiceWorkerController _init() { - _instance = AndroidServiceWorkerController(); - return _instance!; - } - - @Deprecated("Use setServiceWorkerClient instead") - set serviceWorkerClient(AndroidServiceWorkerClient? value) { - setServiceWorkerClient(value); - } - - ///Sets the service worker client - setServiceWorkerClient(AndroidServiceWorkerClient? value) async { - await ServiceWorkerController.instance().setServiceWorkerClient( - value != null - ? ServiceWorkerClient( - shouldInterceptRequest: value.shouldInterceptRequest, - ) - : null, - ); - _serviceWorkerClient = value; - } - - ///Gets whether Service Workers support content URL access. - ///This method should only be called if [AndroidWebViewFeature.isFeatureSupported] returns `true` for [AndroidWebViewFeature.SERVICE_WORKER_CONTENT_ACCESS]. - /// - ///**NOTE**: available on Android 24+. - /// - ///**Official Android API**: https://developer.android.com/reference/androidx/webkit/ServiceWorkerWebSettingsCompat#getAllowContentAccess() - static Future getAllowContentAccess() async { - return await ServiceWorkerController.getAllowContentAccess(); - } - - ///Gets whether Service Workers support file access. - ///This method should only be called if [AndroidWebViewFeature.isFeatureSupported] returns `true` for [AndroidWebViewFeature.SERVICE_WORKER_FILE_ACCESS]. - /// - ///**NOTE**: available on Android 24+. - /// - ///**Official Android API**: https://developer.android.com/reference/androidx/webkit/ServiceWorkerWebSettingsCompat#getAllowFileAccess() - static Future getAllowFileAccess() async { - return await ServiceWorkerController.getAllowFileAccess(); - } - - ///Gets whether Service Workers are prohibited from loading any resources from the network. - ///This method should only be called if [AndroidWebViewFeature.isFeatureSupported] returns `true` for [AndroidWebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS]. - /// - ///**NOTE**: available on Android 24+. - /// - ///**Official Android API**: https://developer.android.com/reference/androidx/webkit/ServiceWorkerWebSettingsCompat#getBlockNetworkLoads() - static Future getBlockNetworkLoads() async { - return await ServiceWorkerController.getBlockNetworkLoads(); - } - - ///Gets the current setting for overriding the cache mode. - ///This method should only be called if [AndroidWebViewFeature.isFeatureSupported] returns `true` for [AndroidWebViewFeature.SERVICE_WORKER_CACHE_MODE]. - /// - ///**NOTE**: available on Android 24+. - /// - ///**Official Android API**: https://developer.android.com/reference/androidx/webkit/ServiceWorkerWebSettingsCompat#getCacheMode() - static Future getCacheMode() async { - return AndroidCacheMode.fromNativeValue( - (await ServiceWorkerController.getCacheMode())?.toNativeValue(), - ); - } - - ///Enables or disables content URL access from Service Workers. - ///This method should only be called if [AndroidWebViewFeature.isFeatureSupported] returns `true` for [AndroidWebViewFeature.SERVICE_WORKER_CONTENT_ACCESS]. - /// - ///**NOTE**: available on Android 24+. - /// - ///**Official Android API**: https://developer.android.com/reference/androidx/webkit/ServiceWorkerWebSettingsCompat#setAllowContentAccess(boolean) - static Future setAllowContentAccess(bool allow) async { - await ServiceWorkerController.setAllowContentAccess(allow); - } - - ///Enables or disables file access within Service Workers. - ///This method should only be called if [AndroidWebViewFeature.isFeatureSupported] returns `true` for [AndroidWebViewFeature.SERVICE_WORKER_FILE_ACCESS]. - /// - ///**NOTE**: available on Android 24+. - /// - ///**Official Android API**: https://developer.android.com/reference/androidx/webkit/ServiceWorkerWebSettingsCompat#setAllowFileAccess(boolean) - static Future setAllowFileAccess(bool allow) async { - await ServiceWorkerController.setAllowFileAccess(allow); - } - - ///Sets whether Service Workers should not load resources from the network. - ///This method should only be called if [AndroidWebViewFeature.isFeatureSupported] returns `true` for [AndroidWebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS]. - /// - ///**NOTE**: available on Android 24+. - /// - ///**Official Android API**: https://developer.android.com/reference/androidx/webkit/ServiceWorkerWebSettingsCompat#setBlockNetworkLoads(boolean) - static Future setBlockNetworkLoads(bool flag) async { - await ServiceWorkerController.setBlockNetworkLoads(flag); - } - - ///Overrides the way the cache is used. - ///This method should only be called if [AndroidWebViewFeature.isFeatureSupported] returns `true` for [AndroidWebViewFeature.SERVICE_WORKER_CACHE_MODE]. - /// - ///**NOTE**: available on Android 24+. - /// - ///**Official Android API**: https://developer.android.com/reference/androidx/webkit/ServiceWorkerWebSettingsCompat#setCacheMode(int) - static Future setCacheMode(AndroidCacheMode mode) async { - await ServiceWorkerController.setCacheMode( - CacheMode.fromNativeValue(mode.toNativeValue())!, - ); - } -} - -///Class that represents an Android-specific class for clients to capture Service Worker related callbacks. -/// -///**NOTE**: available on Android 24+. -/// -///**Official Android API**: https://developer.android.com/reference/androidx/webkit/ServiceWorkerClientCompat -///Use [ServiceWorkerClient] instead. -@Deprecated("Use ServiceWorkerClient instead") -class AndroidServiceWorkerClient { - ///Notify the host application of a resource request and allow the application to return the data. - ///If the return value is `null`, the Service Worker will continue to load the resource as usual. - ///Otherwise, the return response and data will be used. - /// - ///This method is called only if [AndroidWebViewFeature.SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST] is supported. - ///You can check whether that flag is supported using [AndroidWebViewFeature.isFeatureSupported]. - /// - ///[request] represents an object containing the details of the request. - /// - ///**NOTE**: available on Android 24+. - final Future Function(WebResourceRequest request)? - shouldInterceptRequest; - - AndroidServiceWorkerClient({this.shouldInterceptRequest}); -} diff --git a/flutter_inappwebview/lib/src/tracing_controller.dart b/flutter_inappwebview/lib/src/tracing_controller.dart deleted file mode 100644 index 27067262a8..0000000000 --- a/flutter_inappwebview/lib/src/tracing_controller.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformTracingController} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformTracingController.supported_platforms} -class TracingController { - ///{@macro flutter_inappwebview_platform_interface.PlatformTracingController} - TracingController() - : this.fromPlatformCreationParams( - const PlatformTracingControllerCreationParams(), - ); - - /// Constructs a [TracingController] from creation params for a specific - /// platform. - TracingController.fromPlatformCreationParams( - PlatformTracingControllerCreationParams params, - ) : this.fromPlatform(PlatformTracingController(params)); - - /// Constructs a [TracingController] from a specific platform - /// implementation. - TracingController.fromPlatform(this.platform); - - /// Implementation of [PlatformTracingController] for the current platform. - final PlatformTracingController platform; - - static TracingController? _instance; - - ///Gets the [TracingController] shared instance. - static TracingController instance() { - if (_instance == null) { - _instance = TracingController(); - } - return _instance!; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformTracingController.start} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformTracingController.start.supported_platforms} - Future start({required TracingSettings settings}) => - platform.start(settings: settings); - - ///{@macro flutter_inappwebview_platform_interface.PlatformTracingController.stop} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformTracingController.stop.supported_platforms} - Future stop({String? filePath}) => platform.stop(filePath: filePath); - - ///{@macro flutter_inappwebview_platform_interface.PlatformTracingController.isTracing} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformTracingController.isTracing.supported_platforms} - Future isTracing() => platform.isTracing(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformTracingControllerCreationParams.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformTracingController.static().isClassSupported(platform: platform); - - ///{@macro flutter_inappwebview_platform_interface.PlatformTracingController.isMethodSupported} - static bool isMethodSupported( - PlatformTracingControllerMethod method, { - TargetPlatform? platform, - }) => PlatformTracingController.static().isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview/lib/src/web_authentication_session/main.dart b/flutter_inappwebview/lib/src/web_authentication_session/main.dart deleted file mode 100644 index 37ca0c240c..0000000000 --- a/flutter_inappwebview/lib/src/web_authentication_session/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'web_authenticate_session.dart'; diff --git a/flutter_inappwebview/lib/src/web_authentication_session/web_authenticate_session.dart b/flutter_inappwebview/lib/src/web_authentication_session/web_authenticate_session.dart deleted file mode 100755 index b9b4e493a1..0000000000 --- a/flutter_inappwebview/lib/src/web_authentication_session/web_authenticate_session.dart +++ /dev/null @@ -1,134 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.supported_platforms} -class WebAuthenticationSession { - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.supported_platforms} - WebAuthenticationSession() - : this.fromPlatformCreationParams( - params: PlatformWebAuthenticationSessionCreationParams(), - ); - - /// Constructs a [WebAuthenticationSession]. - /// - /// See [WebAuthenticationSession.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - WebAuthenticationSession.fromPlatformCreationParams({ - required PlatformWebAuthenticationSessionCreationParams params, - }) : this.fromPlatform(platform: PlatformWebAuthenticationSession(params)); - - /// Constructs a [WebAuthenticationSession] from a specific platform implementation. - WebAuthenticationSession.fromPlatform({required this.platform}); - - /// Implementation of [PlatformWebAuthenticationSession] for the current platform. - final PlatformWebAuthenticationSession platform; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.id} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.id.supported_platforms} - String get id => platform.id; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.url} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.url.supported_platforms} - WebUri get url => platform.url; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.callbackURLScheme} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.callbackURLScheme.supported_platforms} - String? get callbackURLScheme => platform.callbackURLScheme; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.initialSettings} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.initialSettings.supported_platforms} - WebAuthenticationSessionSettings? get initialSettings => - platform.initialSettings; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.onComplete} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.onComplete.supported_platforms} - WebAuthenticationSessionCompletionHandler get onComplete => - platform.onComplete; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.create} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.create.supported_platforms} - static Future create({ - required WebUri url, - String? callbackURLScheme, - WebAuthenticationSessionCompletionHandler onComplete, - WebAuthenticationSessionSettings? initialSettings, - }) async { - return WebAuthenticationSession.fromPlatform( - platform: await PlatformWebAuthenticationSession.static().create( - url: url, - callbackURLScheme: callbackURLScheme, - onComplete: onComplete, - initialSettings: initialSettings, - ), - ); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.canStart} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.canStart.supported_platforms} - Future canStart() => platform.canStart(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.start} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.start.supported_platforms} - Future start() => platform.start(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.cancel} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.cancel.supported_platforms} - Future cancel() => platform.cancel(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.dispose} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.dispose.supported_platforms} - Future dispose() => platform.dispose(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.isAvailable} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.isAvailable.supported_platforms} - static Future isAvailable() => - PlatformWebAuthenticationSession.static().isAvailable(); - - ///{@template flutter_inappwebview.WebAuthenticationSession.isClassSupported} - ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. - ///{@endtemplate} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformWebAuthenticationSession.static().isClassSupported( - platform: platform, - ); - - ///{@template flutter_inappwebview.WebAuthenticationSession.isPropertySupported} - ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. - ///The property should be one of the [PlatformWebAuthenticationSessionProperty] or [PlatformWebAuthenticationSessionCreationParamsProperty] values. - ///{@endtemplate} - static bool isPropertySupported( - dynamic property, { - TargetPlatform? platform, - }) => PlatformWebAuthenticationSession.static().isPropertySupported( - property, - platform: platform, - ); - - ///{@template flutter_inappwebview.WebAuthenticationSession.isMethodSupported} - ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. - ///{@endtemplate} - static bool isMethodSupported( - PlatformWebAuthenticationSessionMethod method, { - TargetPlatform? platform, - }) => PlatformWebAuthenticationSession.static().isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview/lib/src/web_message/main.dart b/flutter_inappwebview/lib/src/web_message/main.dart deleted file mode 100644 index 4355f8bcdb..0000000000 --- a/flutter_inappwebview/lib/src/web_message/main.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'web_message_port.dart'; -export 'web_message_channel.dart'; -export 'web_message_listener.dart'; diff --git a/flutter_inappwebview/lib/src/web_message/web_message_channel.dart b/flutter_inappwebview/lib/src/web_message/web_message_channel.dart deleted file mode 100644 index 3d2a6a615a..0000000000 --- a/flutter_inappwebview/lib/src/web_message/web_message_channel.dart +++ /dev/null @@ -1,98 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import 'web_message_port.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.supported_platforms} -class WebMessageChannel { - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel} - WebMessageChannel({ - required String id, - required WebMessagePort port1, - required WebMessagePort port2, - }) : this.fromPlatformCreationParams( - params: PlatformWebMessageChannelCreationParams( - id: id, - port1: port1.platform, - port2: port2.platform, - ), - ); - - /// Constructs a [WebMessageChannel]. - /// - /// See [WebMessageChannel.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - WebMessageChannel.fromPlatformCreationParams({ - required PlatformWebMessageChannelCreationParams params, - }) : this.fromPlatform(platform: PlatformWebMessageChannel(params)); - - /// Constructs a [WebMessageChannel] from a specific platform implementation. - WebMessageChannel.fromPlatform({required this.platform}); - - /// Implementation of [PlatformWebMessageChannel] for the current platform. - final PlatformWebMessageChannel platform; - - /// Provide static access. - static WebMessageChannel static() { - return WebMessageChannel.fromPlatform( - platform: PlatformWebMessageChannel.static(), - ); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformWebMessageChannel.static().isClassSupported(platform: platform); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.isPropertySupported} - static bool isPropertySupported( - PlatformWebMessageChannelCreationParamsProperty property, { - TargetPlatform? platform, - }) => PlatformWebMessageChannel.static().isPropertySupported( - property, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.isMethodSupported} - static bool isMethodSupported( - PlatformWebMessageChannelMethod method, { - TargetPlatform? platform, - }) => PlatformWebMessageChannel.static().isMethodSupported( - method, - platform: platform, - ); - - static WebMessageChannel? fromMap(Map? map) { - PlatformWebMessageChannel? platform = PlatformWebMessageChannel.static() - .fromMap(map); - if (platform == null) { - return null; - } - return WebMessageChannel.fromPlatform(platform: platform); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.id} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.id.supported_platforms} - String get id => platform.id; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.port1} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.port1.supported_platforms} - WebMessagePort get port1 => - WebMessagePort.fromPlatform(platform: platform.port1); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.port2} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.port2.supported_platforms} - WebMessagePort get port2 => - WebMessagePort.fromPlatform(platform: platform.port2); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.dispose} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.dispose.supported_platforms} - void dispose() => platform.dispose(); - - @override - String toString() => platform.toString(); -} diff --git a/flutter_inappwebview/lib/src/web_message/web_message_listener.dart b/flutter_inappwebview/lib/src/web_message/web_message_listener.dart deleted file mode 100644 index 192cada6b4..0000000000 --- a/flutter_inappwebview/lib/src/web_message/web_message_listener.dart +++ /dev/null @@ -1,127 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.supported_platforms} -class WebMessageListener { - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener} - WebMessageListener({ - required String jsObjectName, - Set? allowedOriginRules, - OnPostMessageCallback? onPostMessage, - }) : this.fromPlatformCreationParams( - params: PlatformWebMessageListenerCreationParams( - jsObjectName: jsObjectName, - allowedOriginRules: allowedOriginRules, - onPostMessage: onPostMessage, - ), - ); - - /// Constructs a [WebMessageListener]. - /// - /// See [WebMessageListener.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - WebMessageListener.fromPlatformCreationParams({ - required PlatformWebMessageListenerCreationParams params, - }) : this.fromPlatform(platform: PlatformWebMessageListener(params)); - - /// Constructs a [WebMessageListener] from a specific platform implementation. - WebMessageListener.fromPlatform({required this.platform}); - - /// Implementation of [PlatformWebMessageListener] for the current platform. - final PlatformWebMessageListener platform; - - /// Provide static access. - static WebMessageListener static() { - return WebMessageListener.fromPlatform( - platform: PlatformWebMessageListener.static(), - ); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformWebMessageListener.static().isClassSupported(platform: platform); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.isPropertySupported} - static bool isPropertySupported( - PlatformWebMessageListenerCreationParamsProperty property, { - TargetPlatform? platform, - }) => PlatformWebMessageListener.static().isPropertySupported( - property, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.isMethodSupported} - static bool isMethodSupported( - PlatformWebMessageListenerMethod method, { - TargetPlatform? platform, - }) => PlatformWebMessageListener.static().isMethodSupported( - method, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.jsObjectName} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.jsObjectName.supported_platforms} - String get jsObjectName => platform.jsObjectName; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.allowedOriginRules} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.allowedOriginRules.supported_platforms} - Set? get allowedOriginRules => platform.allowedOriginRules; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.onPostMessage} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.onPostMessage.supported_platforms} - OnPostMessageCallback? get onPostMessage => platform.onPostMessage; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.dispose} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.dispose.supported_platforms} - void dispose() => platform.dispose(); - - Map toMap() => platform.toMap(); - - Map toJson() => platform.toJson(); - - @override - String toString() => platform.toString(); -} - -///{@macro flutter_inappwebview_platform_interface.PlatformJavaScriptReplyProxy} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformJavaScriptReplyProxy.supported_platforms} -class JavaScriptReplyProxy { - ///{@macro flutter_inappwebview_platform_interface.PlatformJavaScriptReplyProxy} - JavaScriptReplyProxy({required PlatformWebMessageListener webMessageListener}) - : this.fromPlatformCreationParams( - params: PlatformJavaScriptReplyProxyCreationParams( - webMessageListener: webMessageListener, - ), - ); - - /// Constructs a [JavaScriptReplyProxy]. - /// - /// See [JavaScriptReplyProxy.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - JavaScriptReplyProxy.fromPlatformCreationParams({ - required PlatformJavaScriptReplyProxyCreationParams params, - }) : this.fromPlatform(platform: PlatformJavaScriptReplyProxy(params)); - - /// Constructs a [JavaScriptReplyProxy] from a specific platform implementation. - JavaScriptReplyProxy.fromPlatform({required this.platform}); - - /// Implementation of [PlatformJavaScriptReplyProxy] for the current platform. - final PlatformJavaScriptReplyProxy platform; - - ///{@macro flutter_inappwebview_platform_interface.PlatformJavaScriptReplyProxy.postMessage} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformJavaScriptReplyProxy.postMessage.supported_platforms} - Future postMessage(WebMessage message) => platform.postMessage(message); - - @override - String toString() { - return 'JavaScriptReplyProxy{}'; - } -} diff --git a/flutter_inappwebview/lib/src/web_message/web_message_port.dart b/flutter_inappwebview/lib/src/web_message/web_message_port.dart deleted file mode 100644 index 3087889866..0000000000 --- a/flutter_inappwebview/lib/src/web_message/web_message_port.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessagePort} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessagePort.supported_platforms} -class WebMessagePort implements IWebMessagePort { - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessagePort} - WebMessagePort({required int index}) - : this.fromPlatformCreationParams( - params: PlatformWebMessagePortCreationParams(index: index), - ); - - /// Constructs a [WebMessagePort]. - /// - /// See [WebMessagePort.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - WebMessagePort.fromPlatformCreationParams({ - required PlatformWebMessagePortCreationParams params, - }) : this.fromPlatform(platform: PlatformWebMessagePort(params)); - - /// Constructs a [WebMessagePort] from a specific platform implementation. - WebMessagePort.fromPlatform({required this.platform}); - - /// Implementation of [PlatformWebMessagePort] for the current platform. - final PlatformWebMessagePort platform; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessagePort.setWebMessageCallback} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessagePort.setWebMessageCallback.supported_platforms} - Future setWebMessageCallback(WebMessageCallback? onMessage) => - platform.setWebMessageCallback(onMessage); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessagePort.postMessage} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessagePort.postMessage.supported_platforms} - Future postMessage(WebMessage message) => platform.postMessage(message); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessagePort.close} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessagePort.close.supported_platforms} - Future close() => platform.close(); - - Map toMap({EnumMethod? enumMethod}) => - platform.toMap(enumMethod: enumMethod); - - Map toJson() => platform.toJson(); - - @override - String toString() => platform.toString(); -} diff --git a/flutter_inappwebview/lib/src/web_notification/main.dart b/flutter_inappwebview/lib/src/web_notification/main.dart deleted file mode 100644 index 9887d895b2..0000000000 --- a/flutter_inappwebview/lib/src/web_notification/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'web_notification_controller.dart'; diff --git a/flutter_inappwebview/lib/src/web_notification/web_notification_controller.dart b/flutter_inappwebview/lib/src/web_notification/web_notification_controller.dart deleted file mode 100644 index 1c517d97ce..0000000000 --- a/flutter_inappwebview/lib/src/web_notification/web_notification_controller.dart +++ /dev/null @@ -1,97 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController.supported_platforms} -class WebNotificationController { - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController.supported_platforms} - WebNotificationController({ - required String id, - required WebNotification notification, - }) : this.fromPlatformCreationParams( - params: PlatformWebNotificationControllerCreationParams( - id: id, - notification: notification, - ), - ); - - /// Constructs a [WebNotificationController]. - /// - /// See [WebNotificationController.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - WebNotificationController.fromPlatformCreationParams({ - required PlatformWebNotificationControllerCreationParams params, - }) : this.fromPlatform(platform: PlatformWebNotificationController(params)); - - /// Constructs a [WebNotificationController] from a specific platform implementation. - WebNotificationController.fromPlatform({required this.platform}); - - /// Implementation of [PlatformWebNotificationController] for the current platform. - final PlatformWebNotificationController platform; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationControllerCreationParams.id} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationControllerCreationParams.id.supported_platforms} - String get id => platform.id; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationControllerCreationParams.notification} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationControllerCreationParams.notification.supported_platforms} - WebNotification get notification => platform.notification; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController.onClose} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController.onClose.supported_platforms} - WebNotificationCloseHandler? get onClose => platform.onClose; - - void set onClose(WebNotificationCloseHandler? handler) { - platform.onClose = handler; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController.reportShown} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController.reportShown.supported_platforms} - Future reportShown() => platform.reportShown(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController.reportClicked} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController.reportClicked.supported_platforms} - Future reportClicked() => platform.reportClicked(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController.reportClosed} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController.reportClosed.supported_platforms} - Future reportClosed() => platform.reportClosed(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController.dispose} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController.dispose.supported_platforms} - void dispose() => platform.dispose(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationControllerCreationParams.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformWebNotificationController.static().isClassSupported( - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController.isPropertySupported} - static bool isPropertySupported( - dynamic property, { - TargetPlatform? platform, - }) => PlatformWebNotificationController.static().isPropertySupported( - property, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebNotificationController.isMethodSupported} - static bool isMethodSupported( - PlatformWebNotificationControllerMethod method, { - TargetPlatform? platform, - }) => PlatformWebNotificationController.static().isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview/lib/src/web_storage/android/main.dart b/flutter_inappwebview/lib/src/web_storage/android/main.dart deleted file mode 100644 index 43c8e7bab4..0000000000 --- a/flutter_inappwebview/lib/src/web_storage/android/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'web_storage_manager.dart'; diff --git a/flutter_inappwebview/lib/src/web_storage/android/web_storage_manager.dart b/flutter_inappwebview/lib/src/web_storage/android/web_storage_manager.dart deleted file mode 100755 index f5539fd1c7..0000000000 --- a/flutter_inappwebview/lib/src/web_storage/android/web_storage_manager.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'dart:async'; - -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../web_storage_manager.dart'; - -///Class that is used to manage the JavaScript storage APIs provided by the WebView. -///It manages the Application Cache API, the Web SQL Database API and the HTML5 Web Storage API. -/// -///Use [WebStorageManager] instead. -@Deprecated("Use WebStorageManager instead") -class AndroidWebStorageManager { - ///Gets the origins currently using either the Application Cache or Web SQL Database APIs. - Future> getOrigins() async { - List originsList = []; - - List origins = await WebStorageManager.instance() - .getOrigins(); - - for (var origin in origins) { - originsList.add( - AndroidWebStorageOrigin( - origin: origin.origin, - quota: origin.quota, - usage: origin.usage, - ), - ); - } - - return originsList; - } - - ///Clears all storage currently being used by the JavaScript storage APIs. - ///This includes the Application Cache, Web SQL Database and the HTML5 Web Storage APIs. - Future deleteAllData() async { - await WebStorageManager.instance().deleteAllData(); - } - - ///Clears the storage currently being used by both the Application Cache and Web SQL Database APIs by the given [origin]. - ///The origin is specified using its string representation. - Future deleteOrigin({required String origin}) async { - await WebStorageManager.instance().deleteOrigin(origin: origin); - } - - ///Gets the storage quota for the Web SQL Database API for the given [origin]. - ///The quota is given in bytes and the origin is specified using its string representation. - ///Note that a quota is not enforced on a per-origin basis for the Application Cache API. - Future getQuotaForOrigin({required String origin}) async { - return await WebStorageManager.instance().getQuotaForOrigin(origin: origin); - } - - ///Gets the amount of storage currently being used by both the Application Cache and Web SQL Database APIs by the given [origin]. - ///The amount is given in bytes and the origin is specified using its string representation. - Future getUsageForOrigin({required String origin}) async { - return await WebStorageManager.instance().getUsageForOrigin(origin: origin); - } -} diff --git a/flutter_inappwebview/lib/src/web_storage/ios/main.dart b/flutter_inappwebview/lib/src/web_storage/ios/main.dart deleted file mode 100644 index 43c8e7bab4..0000000000 --- a/flutter_inappwebview/lib/src/web_storage/ios/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'web_storage_manager.dart'; diff --git a/flutter_inappwebview/lib/src/web_storage/ios/web_storage_manager.dart b/flutter_inappwebview/lib/src/web_storage/ios/web_storage_manager.dart deleted file mode 100755 index b2a57b4c21..0000000000 --- a/flutter_inappwebview/lib/src/web_storage/ios/web_storage_manager.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'dart:async'; - -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../web_storage_manager.dart'; - -///Class that represents various types of data that a website might make use of. -///This includes cookies, disk and memory caches, and persistent data such as WebSQL, IndexedDB databases, and local storage. -/// -///**NOTE**: available on iOS 9.0+. -/// -///Use [WebStorageManager] instead. -@Deprecated("Use WebStorageManager instead") -class IOSWebStorageManager { - ///Fetches data records containing the given website data types. - /// - ///[dataTypes] represents the website data types to fetch records for. - Future> fetchDataRecords({ - required Set dataTypes, - }) async { - List recordList = []; - Set dataTypesList = Set(); - for (var dataType in dataTypes) { - dataTypesList.add( - WebsiteDataType.fromNativeValue(dataType.toNativeValue())!, - ); - } - - List records = await WebStorageManager.instance() - .fetchDataRecords(dataTypes: dataTypesList); - - for (var record in records) { - Set dataTypesString = record.dataTypes ?? Set(); - Set dataTypes = Set(); - for (var dataTypeValue in dataTypesString) { - var dataType = IOSWKWebsiteDataType.fromNativeValue( - dataTypeValue.toNativeValue(), - ); - if (dataType != null) { - dataTypes.add(dataType); - } - } - recordList.add( - IOSWKWebsiteDataRecord( - displayName: record.displayName, - dataTypes: dataTypes, - ), - ); - } - return recordList; - } - - ///Removes website data of the given types for the given data records. - /// - ///[dataTypes] represents the website data types that should be removed. - /// - ///[dataRecords] represents the website data records to delete website data for. - Future removeDataFor({ - required Set dataTypes, - required List dataRecords, - }) async { - Set dataTypesList = Set(); - for (var dataType in dataTypes) { - dataTypesList.add( - WebsiteDataType.fromNativeValue(dataType.toNativeValue())!, - ); - } - - List recordList = []; - for (var record in dataRecords) { - recordList.add(WebsiteDataRecord.fromMap(record.toMap())!); - } - - await WebStorageManager.instance().removeDataFor( - dataRecords: recordList, - dataTypes: dataTypesList, - ); - } - - ///Removes all website data of the given types that has been modified since the given date. - /// - ///[dataTypes] represents the website data types that should be removed. - /// - ///[date] represents a date. All website data modified after this date will be removed. - Future removeDataModifiedSince({ - required Set dataTypes, - required DateTime date, - }) async { - Set dataTypesList = Set(); - for (var dataType in dataTypes) { - dataTypesList.add( - WebsiteDataType.fromNativeValue(dataType.toNativeValue())!, - ); - } - - await WebStorageManager.instance().removeDataModifiedSince( - dataTypes: dataTypesList, - date: date, - ); - } -} diff --git a/flutter_inappwebview/lib/src/web_storage/main.dart b/flutter_inappwebview/lib/src/web_storage/main.dart deleted file mode 100644 index 6462ba4d49..0000000000 --- a/flutter_inappwebview/lib/src/web_storage/main.dart +++ /dev/null @@ -1,4 +0,0 @@ -export 'web_storage.dart'; -export 'web_storage_manager.dart'; -export 'android/main.dart'; -export 'ios/main.dart'; diff --git a/flutter_inappwebview/lib/src/web_storage/web_storage.dart b/flutter_inappwebview/lib/src/web_storage/web_storage.dart deleted file mode 100644 index e6492e9189..0000000000 --- a/flutter_inappwebview/lib/src/web_storage/web_storage.dart +++ /dev/null @@ -1,240 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../in_app_webview/in_app_webview_controller.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage.supported_platforms} -class WebStorage { - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage} - WebStorage({ - required PlatformLocalStorage localStorage, - required PlatformSessionStorage sessionStorage, - }) : this.fromPlatformCreationParams( - params: PlatformWebStorageCreationParams( - localStorage: localStorage, - sessionStorage: sessionStorage, - ), - ); - - /// Constructs a [WebStorage]. - /// - /// See [WebStorage.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - WebStorage.fromPlatformCreationParams({ - required PlatformWebStorageCreationParams params, - }) : this.fromPlatform(platform: PlatformWebStorage(params)); - - /// Constructs a [WebStorage] from a specific platform implementation. - WebStorage.fromPlatform({required this.platform}); - - /// Implementation of [PlatformWebStorage] for the current platform. - final PlatformWebStorage platform; - - ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. - static bool isClassSupported({TargetPlatform? platform}) => - PlatformWebStorage.static().isClassSupported(platform: platform); - - ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. - static bool isPropertySupported( - dynamic property, { - TargetPlatform? platform, - }) => PlatformWebStorage.static().isPropertySupported( - property, - platform: platform, - ); - - ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. - static bool isMethodSupported( - PlatformWebStorageMethod method, { - TargetPlatform? platform, - }) => - PlatformWebStorage.static().isMethodSupported(method, platform: platform); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage.localStorage} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage.localStorage.supported_platforms} - LocalStorage get localStorage => - LocalStorage.fromPlatform(platform: platform.localStorage); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage.sessionStorage} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage.sessionStorage.supported_platforms} - SessionStorage get sessionStorage => - SessionStorage.fromPlatform(platform: platform.sessionStorage); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage.dispose} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage.dispose.supported_platforms} - void dispose() => platform.dispose(); -} - -///{@macro flutter_inappwebview_platform_interface.PlatformStorage} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformStorage.supported_platforms} -abstract class Storage implements PlatformStorage { - /// Constructs a [Storage] from a specific platform implementation. - Storage.fromPlatform({required this.platform}); - - /// Implementation of [PlatformStorage] for the current platform. - final PlatformStorage platform; - - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.controller} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.controller.supported_platforms} - PlatformInAppWebViewController? get controller => platform.controller; - - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.webStorageType} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.webStorageType.supported_platforms} - WebStorageType get webStorageType => platform.webStorageType; - - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.length} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.length.supported_platforms} - Future length() => platform.length(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.setItem} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.setItem.supported_platforms} - Future setItem({required String key, required dynamic value}) => - platform.setItem(key: key, value: value); - - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.getItem} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.getItem.supported_platforms} - Future getItem({required String key}) => platform.getItem(key: key); - - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.removeItem} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.removeItem.supported_platforms} - Future removeItem({required String key}) => - platform.removeItem(key: key); - - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.getItems} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.getItems.supported_platforms} - Future> getItems() => platform.getItems(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.clear} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.clear.supported_platforms} - Future clear() => platform.clear(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.key} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.key.supported_platforms} - Future key({required int index}) => platform.key(index: index); - - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.dispose} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.dispose.supported_platforms} - void dispose() => platform.dispose(); -} - -///{@macro flutter_inappwebview_platform_interface.PlatformLocalStorage} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformLocalStorage.supported_platforms} -class LocalStorage extends Storage { - ///{@macro flutter_inappwebview_platform_interface.PlatformLocalStorage} - LocalStorage({required InAppWebViewController? controller}) - : this.fromPlatformCreationParams( - params: PlatformLocalStorageCreationParams( - PlatformStorageCreationParams( - controller: controller?.platform, - webStorageType: WebStorageType.LOCAL_STORAGE, - ), - ), - ); - - /// Constructs a [LocalStorage]. - /// - /// See [LocalStorage.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - LocalStorage.fromPlatformCreationParams({ - required PlatformLocalStorageCreationParams params, - }) : this.fromPlatform(platform: PlatformLocalStorage(params)); - - /// Constructs a [LocalStorage] from a specific platform implementation. - LocalStorage.fromPlatform({required this.platform}) - : super.fromPlatform(platform: platform); - - /// Implementation of [PlatformLocalStorage] for the current platform. - final PlatformLocalStorage platform; - - ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. - static bool isClassSupported({TargetPlatform? platform}) => - PlatformLocalStorage.static().isClassSupported(platform: platform); - - ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. - static bool isPropertySupported( - PlatformStorageCreationParamsProperty property, { - TargetPlatform? platform, - }) => PlatformLocalStorage.static().isPropertySupported( - property, - platform: platform, - ); - - ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. - static bool isMethodSupported( - PlatformLocalStorageMethod method, { - TargetPlatform? platform, - }) => PlatformLocalStorage.static().isMethodSupported( - method, - platform: platform, - ); -} - -///{@macro flutter_inappwebview_platform_interface.PlatformSessionStorage} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformSessionStorage.supported_platforms} -class SessionStorage extends Storage { - ///{@macro flutter_inappwebview_platform_interface.PlatformSessionStorage} - SessionStorage({required InAppWebViewController? controller}) - : this.fromPlatformCreationParams( - params: PlatformSessionStorageCreationParams( - PlatformStorageCreationParams( - controller: controller?.platform, - webStorageType: WebStorageType.SESSION_STORAGE, - ), - ), - ); - - /// Constructs a [SessionStorage]. - /// - /// See [SessionStorage.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - SessionStorage.fromPlatformCreationParams({ - required PlatformSessionStorageCreationParams params, - }) : this.fromPlatform(platform: PlatformSessionStorage(params)); - - /// Constructs a [SessionStorage] from a specific platform implementation. - SessionStorage.fromPlatform({required this.platform}) - : super.fromPlatform(platform: platform); - - /// Implementation of [PlatformSessionStorage] for the current platform. - final PlatformSessionStorage platform; - - ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. - static bool isClassSupported({TargetPlatform? platform}) => - PlatformSessionStorage.static().isClassSupported(platform: platform); - - ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. - static bool isPropertySupported( - PlatformStorageCreationParamsProperty property, { - TargetPlatform? platform, - }) => PlatformSessionStorage.static().isPropertySupported( - property, - platform: platform, - ); - - ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. - static bool isMethodSupported( - PlatformSessionStorageMethod method, { - TargetPlatform? platform, - }) => PlatformSessionStorage.static().isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview/lib/src/web_storage/web_storage_manager.dart b/flutter_inappwebview/lib/src/web_storage/web_storage_manager.dart deleted file mode 100755 index 8a815d5fbf..0000000000 --- a/flutter_inappwebview/lib/src/web_storage/web_storage_manager.dart +++ /dev/null @@ -1,113 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import 'android/web_storage_manager.dart'; -import 'ios/web_storage_manager.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.supported_platforms} -class WebStorageManager { - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager} - WebStorageManager() - : this.fromPlatformCreationParams( - const PlatformWebStorageManagerCreationParams(), - ); - - /// Constructs a [WebStorageManager] from creation params for a specific - /// platform. - WebStorageManager.fromPlatformCreationParams( - PlatformWebStorageManagerCreationParams params, - ) : this.fromPlatform(PlatformWebStorageManager(params)); - - /// Constructs a [WebStorageManager] from a specific platform - /// implementation. - WebStorageManager.fromPlatform(this.platform); - - /// Implementation of [PlatformCookieManager] for the current platform. - final PlatformWebStorageManager platform; - - static WebStorageManager? _instance; - - ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. - static bool isClassSupported({TargetPlatform? platform}) => - PlatformWebStorageManager.static().isClassSupported(platform: platform); - - ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. - static bool isMethodSupported( - PlatformWebStorageManagerMethod method, { - TargetPlatform? platform, - }) => PlatformWebStorageManager.static().isMethodSupported( - method, - platform: platform, - ); - - ///Use [WebStorageManager] instead. - @Deprecated("Use WebStorageManager instead") - AndroidWebStorageManager android = AndroidWebStorageManager(); - - ///Use [WebStorageManager] instead. - @Deprecated("Use WebStorageManager instead") - IOSWebStorageManager ios = IOSWebStorageManager(); - - ///Gets the [WebStorageManager] shared instance. - static WebStorageManager instance() { - if (_instance == null) { - _instance = WebStorageManager(); - } - return _instance!; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.getOrigins} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.getOrigins.supported_platforms} - Future> getOrigins() => platform.getOrigins(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.deleteAllData} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.deleteAllData.supported_platforms} - Future deleteAllData() => platform.deleteAllData(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.deleteOrigin} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.deleteOrigin.supported_platforms} - Future deleteOrigin({required String origin}) => - platform.deleteOrigin(origin: origin); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.getQuotaForOrigin} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.getQuotaForOrigin.supported_platforms} - Future getQuotaForOrigin({required String origin}) => - platform.getQuotaForOrigin(origin: origin); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.getUsageForOrigin} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.getUsageForOrigin.supported_platforms} - Future getUsageForOrigin({required String origin}) => - platform.getUsageForOrigin(origin: origin); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.fetchDataRecords} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.fetchDataRecords.supported_platforms} - Future> fetchDataRecords({ - required Set dataTypes, - }) => platform.fetchDataRecords(dataTypes: dataTypes); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.removeDataFor} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.removeDataFor.supported_platforms} - Future removeDataFor({ - required Set dataTypes, - required List dataRecords, - }) => platform.removeDataFor(dataTypes: dataTypes, dataRecords: dataRecords); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.removeDataModifiedSince} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.removeDataModifiedSince.supported_platforms} - Future removeDataModifiedSince({ - required Set dataTypes, - required DateTime date, - }) => platform.removeDataModifiedSince(dataTypes: dataTypes, date: date); -} diff --git a/flutter_inappwebview/lib/src/webview_asset_loader.dart b/flutter_inappwebview/lib/src/webview_asset_loader.dart deleted file mode 100644 index 80404e507c..0000000000 --- a/flutter_inappwebview/lib/src/webview_asset_loader.dart +++ /dev/null @@ -1,200 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformPathHandler} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformPathHandler.supported_platforms} -abstract class PathHandler - implements PlatformPathHandler, PlatformPathHandlerEvents { - /// Constructs a [PathHandler] from a specific platform implementation. - PathHandler.fromPlatform({required this.platform}) { - this.platform.eventHandler = this; - } - - /// Returns whether this class is supported on the current platform. - /// - /// Use [platform] to check support for a specific platform. - static bool isClassSupported({TargetPlatform? platform}) => - PlatformPathHandlerCreationParams( - path: '', - ).isClassSupported(platform: platform); - - @override - late final PlatformPathHandlerEvents? eventHandler; - - /// Implementation of [PlatformPathHandler] for the current platform. - final PlatformPathHandler platform; - - @override - String get type => platform.type; - - @override - String get path => platform.path; - - @override - Future handle(String path) async { - return null; - } - - @override - Map toMap({EnumMethod? enumMethod}) => - platform.toMap(enumMethod: enumMethod); - - @override - Map toJson() => platform.toJson(); -} - -///{@macro flutter_inappwebview_platform_interface.PlatformAssetsPathHandler} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformAssetsPathHandler.supported_platforms} -class AssetsPathHandler extends PathHandler { - ///{@macro flutter_inappwebview_platform_interface.PlatformAssetsPathHandler} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformAssetsPathHandler.supported_platforms} - AssetsPathHandler({required String path}) - : this.fromPlatformCreationParams( - params: PlatformAssetsPathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: path), - ), - ); - - /// Constructs a [AssetsPathHandler]. - /// - /// See [AssetsPathHandler.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - AssetsPathHandler.fromPlatformCreationParams({ - required PlatformAssetsPathHandlerCreationParams params, - }) : this.fromPlatform(platform: PlatformAssetsPathHandler(params)); - - /// Constructs a [AssetsPathHandler] from a specific platform implementation. - AssetsPathHandler.fromPlatform({required this.platform}) - : super.fromPlatform(platform: platform); - - /// Implementation of [PlatformAssetsPathHandler] for the current platform. - final PlatformAssetsPathHandler platform; - - /// Returns whether this class is supported on the current platform. - /// - /// Use [platform] to check support for a specific platform. - static bool isClassSupported({TargetPlatform? platform}) => - PlatformPathHandlerCreationParams( - path: '', - ).isClassSupported(platform: platform); -} - -///{@macro flutter_inappwebview_platform_interface.PlatformResourcesPathHandler} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformResourcesPathHandler.supported_platforms} -class ResourcesPathHandler extends PathHandler { - ///{@macro flutter_inappwebview_platform_interface.PlatformResourcesPathHandler} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformResourcesPathHandler.supported_platforms} - ResourcesPathHandler({required String path}) - : this.fromPlatformCreationParams( - params: PlatformResourcesPathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: path), - ), - ); - - /// Constructs a [ResourcesPathHandler]. - /// - /// See [ResourcesPathHandler.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - ResourcesPathHandler.fromPlatformCreationParams({ - required PlatformResourcesPathHandlerCreationParams params, - }) : this.fromPlatform(platform: PlatformResourcesPathHandler(params)); - - /// Constructs a [ResourcesPathHandler] from a specific platform implementation. - ResourcesPathHandler.fromPlatform({required this.platform}) - : super.fromPlatform(platform: platform); - - /// Implementation of [PlatformResourcesPathHandler] for the current platform. - final PlatformResourcesPathHandler platform; - - /// Returns whether this class is supported on the current platform. - /// - /// Use [platform] to check support for a specific platform. - static bool isClassSupported({TargetPlatform? platform}) => - PlatformPathHandlerCreationParams( - path: '', - ).isClassSupported(platform: platform); -} - -///{@macro flutter_inappwebview_platform_interface.PlatformInternalStoragePathHandler} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformInternalStoragePathHandler.supported_platforms} -class InternalStoragePathHandler extends PathHandler { - ///{@macro flutter_inappwebview_platform_interface.PlatformInternalStoragePathHandler} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInternalStoragePathHandler.supported_platforms} - InternalStoragePathHandler({required String path, required String directory}) - : this.fromPlatformCreationParams( - params: PlatformInternalStoragePathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: path), - directory: directory, - ), - ); - - /// Constructs a [InternalStoragePathHandler]. - /// - /// See [InternalStoragePathHandler.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - InternalStoragePathHandler.fromPlatformCreationParams({ - required PlatformInternalStoragePathHandlerCreationParams params, - }) : this.fromPlatform(platform: PlatformInternalStoragePathHandler(params)); - - /// Constructs a [InternalStoragePathHandler] from a specific platform implementation. - InternalStoragePathHandler.fromPlatform({required this.platform}) - : super.fromPlatform(platform: platform); - - /// Implementation of [PlatformInternalStoragePathHandler] for the current platform. - final PlatformInternalStoragePathHandler platform; - - String get directory => platform.directory; - - /// Returns whether this class is supported on the current platform. - /// - /// Use [platform] to check support for a specific platform. - static bool isClassSupported({TargetPlatform? platform}) => - PlatformPathHandlerCreationParams( - path: '', - ).isClassSupported(platform: platform); -} - -///{@macro flutter_inappwebview_platform_interface.PlatformCustomPathHandler} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformCustomPathHandler.supported_platforms} -abstract class CustomPathHandler extends PathHandler { - ///{@macro flutter_inappwebview_platform_interface.PlatformCustomPathHandler} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformCustomPathHandler.supported_platforms} - CustomPathHandler({required String path}) - : this.fromPlatformCreationParams( - params: PlatformCustomPathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: path), - ), - ); - - /// Constructs a [CustomPathHandler]. - /// - /// See [CustomPathHandler.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - CustomPathHandler.fromPlatformCreationParams({ - required PlatformCustomPathHandlerCreationParams params, - }) : this.fromPlatform(platform: PlatformCustomPathHandler(params)); - - /// Constructs a [CustomPathHandler] from a specific platform implementation. - CustomPathHandler.fromPlatform({required this.platform}) - : super.fromPlatform(platform: platform); - - /// Implementation of [PlatformCustomPathHandler] for the current platform. - final PlatformCustomPathHandler platform; - - /// Returns whether this class is supported on the current platform. - /// - /// Use [platform] to check support for a specific platform. - static bool isClassSupported({TargetPlatform? platform}) => - PlatformPathHandlerCreationParams( - path: '', - ).isClassSupported(platform: platform); -} diff --git a/flutter_inappwebview/lib/src/webview_environment/main.dart b/flutter_inappwebview/lib/src/webview_environment/main.dart deleted file mode 100644 index f9bf33a73a..0000000000 --- a/flutter_inappwebview/lib/src/webview_environment/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'webview_environment.dart'; diff --git a/flutter_inappwebview/lib/src/webview_environment/webview_environment.dart b/flutter_inappwebview/lib/src/webview_environment/webview_environment.dart deleted file mode 100644 index 79dcbae30a..0000000000 --- a/flutter_inappwebview/lib/src/webview_environment/webview_environment.dart +++ /dev/null @@ -1,158 +0,0 @@ -import 'dart:core'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.supported_platforms} -class WebViewEnvironment { - /// Constructs a [WebViewEnvironment]. - /// - /// See [WebViewEnvironment.fromPlatformCreationParams] for setting parameters for - /// a specific platform. - WebViewEnvironment.fromPlatformCreationParams({ - required PlatformWebViewEnvironmentCreationParams params, - }) : this.fromPlatform(platform: PlatformWebViewEnvironment(params)); - - /// Constructs a [WebViewEnvironment] from a specific platform implementation. - WebViewEnvironment.fromPlatform({required this.platform}); - - /// Implementation of [PlatformWebViewEnvironment] for the current platform. - final PlatformWebViewEnvironment platform; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.id} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.id.supported_platforms} - String get id => platform.id; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.settings} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.settings.supported_platforms} - WebViewEnvironmentSettings? get settings => platform.settings; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isInterfaceSupported} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isInterfaceSupported.supported_platforms} - Future isInterfaceSupported(WebViewInterface interface) => - platform.isInterfaceSupported(interface); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getProcessInfos} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getProcessInfos.supported_platforms} - Future> getProcessInfos() => - platform.getProcessInfos(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getFailureReportFolderPath} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getFailureReportFolderPath.supported_platforms} - Future getFailureReportFolderPath() => - platform.getFailureReportFolderPath(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.create} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.create.supported_platforms} - static Future create({ - WebViewEnvironmentSettings? settings, - }) async { - return WebViewEnvironment.fromPlatform( - platform: await PlatformWebViewEnvironment.static().create( - settings: settings, - ), - ); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getAvailableVersion} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getAvailableVersion.supported_platforms} - static Future getAvailableVersion({ - String? browserExecutableFolder, - }) => PlatformWebViewEnvironment.static().getAvailableVersion( - browserExecutableFolder: browserExecutableFolder, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getAvailableVersion} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getAvailableVersion.supported_platforms} - static Future compareBrowserVersions({ - required String version1, - required String version2, - }) => PlatformWebViewEnvironment.static().compareBrowserVersions( - version1: version1, - version2: version2, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.onNewBrowserVersionAvailable} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.onNewBrowserVersionAvailable.supported_platforms} - void Function()? get onNewBrowserVersionAvailable => - platform.onNewBrowserVersionAvailable; - set onNewBrowserVersionAvailable(void Function()? value) => - platform.onNewBrowserVersionAvailable = value; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.onBrowserProcessExited} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.onBrowserProcessExited.supported_platforms} - void Function(BrowserProcessExitedDetail detail)? - get onBrowserProcessExited => platform.onBrowserProcessExited; - set onBrowserProcessExited( - void Function(BrowserProcessExitedDetail detail)? value, - ) => platform.onBrowserProcessExited = value; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.onProcessInfosChanged} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.onProcessInfosChanged.supported_platforms} - void Function(BrowserProcessInfosChangedDetail detail)? - get onProcessInfosChanged => platform.onProcessInfosChanged; - set onProcessInfosChanged( - void Function(BrowserProcessInfosChangedDetail detail)? value, - ) => platform.onProcessInfosChanged = value; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getCacheModel} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getCacheModel.supported_platforms} - Future getCacheModel() => platform.getCacheModel(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isSpellCheckingEnabled} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isSpellCheckingEnabled.supported_platforms} - Future isSpellCheckingEnabled() => platform.isSpellCheckingEnabled(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getSpellCheckingLanguages} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getSpellCheckingLanguages.supported_platforms} - Future> getSpellCheckingLanguages() => - platform.getSpellCheckingLanguages(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isAutomationAllowed} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isAutomationAllowed.supported_platforms} - Future isAutomationAllowed() => platform.isAutomationAllowed(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.dispose} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.dispose.supported_platforms} - Future dispose() => platform.dispose(); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.isClassSupported} - static bool isClassSupported({TargetPlatform? platform}) => - PlatformWebViewEnvironment.static().isClassSupported(platform: platform); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isPropertySupported} - static bool isPropertySupported( - dynamic property, { - TargetPlatform? platform, - }) => PlatformWebViewEnvironment.static().isPropertySupported( - property, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isMethodSupported} - static bool isMethodSupported( - PlatformWebViewEnvironmentMethod method, { - TargetPlatform? platform, - }) => PlatformWebViewEnvironment.static().isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview/pubspec.yaml b/flutter_inappwebview/pubspec.yaml deleted file mode 100755 index 21ef16a2f4..0000000000 --- a/flutter_inappwebview/pubspec.yaml +++ /dev/null @@ -1,104 +0,0 @@ -name: flutter_inappwebview -description: A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window. -version: 6.2.0-beta.3 -homepage: https://inappwebview.dev/ -repository: https://github.com/pichillilorenzo/flutter_inappwebview -issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues -funding: - - https://inappwebview.dev/donate/ -topics: - - html - - webview - - webview-flutter - - inappwebview - - browser - -environment: - sdk: ^3.8.0 - flutter: ">=3.32.0" - -dependencies: - flutter: - sdk: flutter - flutter_inappwebview_platform_interface: ^1.4.0-beta.3 - # path: ../flutter_inappwebview_platform_interface - flutter_inappwebview_android: ^1.2.0-beta.3 - # path: ../flutter_inappwebview_android - flutter_inappwebview_ios: ^1.2.0-beta.3 - # path: ../flutter_inappwebview_ios - flutter_inappwebview_macos: ^1.2.0-beta.3 - # path: ../flutter_inappwebview_macos - flutter_inappwebview_web: ^1.2.0-beta.3 - # path: ../flutter_inappwebview_web - flutter_inappwebview_windows: ^0.7.0-beta.3 - # path: ../flutter_inappwebview_windows - flutter_inappwebview_linux: ^0.1.0-beta.1 - # path: ../flutter_inappwebview_linux - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_driver: - sdk: flutter - flutter_lints: ^6.0.0 - build_runner: ^2.4.12 - generators: - path: ../dev_packages/generators - -# For information on the generic Dart part of this file, see the -# following page: https://www.dartlang.org/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - plugin: - platforms: - android: - default_package: flutter_inappwebview_android - ios: - default_package: flutter_inappwebview_ios - macos: - default_package: flutter_inappwebview_macos - web: - default_package: flutter_inappwebview_web - windows: - default_package: flutter_inappwebview_windows - linux: - default_package: flutter_inappwebview_linux - - assets: - - packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html - - packages/flutter_inappwebview/assets/t_rex_runner/t-rex.css - # To add assets to your plugin package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.io/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.io/assets-and-images/#resolution-aware. - - # To add custom fonts to your plugin package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.io/custom-fonts/#from-packages - -false_secrets: - - /test_node_server/*.pem - - /test_node_server/*.pfx \ No newline at end of file diff --git a/flutter_inappwebview_android/.gitignore b/flutter_inappwebview_android/.gitignore deleted file mode 100644 index 96486fd930..0000000000 --- a/flutter_inappwebview_android/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock -**/doc/api/ -.dart_tool/ -.packages -build/ diff --git a/flutter_inappwebview_android/.metadata b/flutter_inappwebview_android/.metadata deleted file mode 100644 index 3f294f39ea..0000000000 --- a/flutter_inappwebview_android/.metadata +++ /dev/null @@ -1,30 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e" - channel: "stable" - -project_type: plugin - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - - platform: android - create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/flutter_inappwebview_android/CHANGELOG.md b/flutter_inappwebview_android/CHANGELOG.md deleted file mode 100644 index b18e420171..0000000000 --- a/flutter_inappwebview_android/CHANGELOG.md +++ /dev/null @@ -1,152 +0,0 @@ -## 1.2.0-beta.3 - -- Updated flutter_inappwebview_platform_interface version to ^1.4.0-beta.3 -- Updated native dependencies: - - implementation from `'androidx.webkit:webkit:1.12.0'` to `'androidx.webkit:webkit:1.14.0'` - - implementation from `'androidx.browser:browser:1.8.0'` to `'androidx.browser:browser:1.9.0'` - - implementation from `'androidx.appcompat:appcompat:1.6.1'` to `'androidx.appcompat:appcompat:1.7.1'` - - implementation from `'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'` to `'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0'` -- Updated android native `compileOptions` to `JavaVersion.VERSION_17` -- Implemented `saveState`, `restoreState` InAppWebViewController methods -- Implemented `onShowFileChooser` WebView event -- Updated InAppBrowser toolbar top -- Merged "Android: implemented PlatformPrintJobController.onComplete" [#2216](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2216) (thanks to [Doflatango](https://github.com/Doflatango)) -- Fixed "When useShouldInterceptAjaxRequest is true, some ajax requests doesn't work" [#2197](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2197) -- Merged "Fixed recursive calling toMap in AndroidInternalStoragePathHandler" [#2452](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2452) (thanks to [roberthofstra](https://github.com/roberthofstra)) -- Fixed recursive `toMap` call for `AndroidInternalStoragePathHandler` [#2451](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2451) -- Fixed "Error when updating webview settings Android in v6.2.0-beta.2" [#2449](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2449) -- Fixed "[Android] Upgrade to AGP 9" [#2765](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2765) -- Fixed "update android apg version to 8.9.1 or higer" [#2761](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2761) -- Fixed "InAppWebViewController.goTo" implementation -- Merged "fix #2484, Remove not-empty assert for Cookie.value" [#2486](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2486) (thanks to [laishere](https://github.com/laishere)) - -## 1.2.0-beta.2 - -- Updated flutter_inappwebview_platform_interface version to ^1.4.0-beta.2 -- Implemented `hideInputMethod`, `showInputMethod` InAppWebViewController methods -- Implemented `isUserInteractionEnabled`, `alpha` properties of `InAppWebViewSettings` -- Merged "Show / Hide / Disable / Enable soft Keyboard Input (Android & iOS)" [#2408](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2408) (thanks to [Mecharyry](https://github.com/Mecharyry)) -- Fixed "[Android] PrintJobOrientation _TypeError (type 'Null' is not a subtype of type 'int')" [#2413](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2413) -- Fixed "Accessibility Android" [#1694](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1694) -- Fixed "Automatic font scale according to accessibility option 'font size' of device does not work on Android" [#540](https://github.com/pichillilorenzo/flutter_inappwebview/issues/540) -- Fixed "callHandler method is not injected into InAppBrowser" [#1973](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1973) - -## 1.2.0-beta.1 - -- Updated flutter_inappwebview_platform_interface version to ^1.4.0-beta.1 -- Added `InAppWebViewController.enableSlowWholeDocumentDraw` static method -- Added `CookieManager.flush` method -- Added support for `UserScript.forMainFrameOnly` parameter -- Implemented `requestFocus` WebView method -- Updated UserScript at document end implementation -- Updated `InAppWebViewController.takeScreenshot` implementation to support screenshot out of visible viewport when `InAppWebViewController.enableSlowWholeDocumentDraw` is called -- Fixed "After dispose a InAppWebViewKeepAlive using InAppWebViewController.disposeKeepAlive. NullPointerException is thrown when main activity enter destroyed state." [#2025](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2025) -- Fixed crash when trying to open InAppBrowser with R.menu.menu_main on release mode -- Fixed "android.webkit.WebSettingsWrapper cannot be cast to com.android.webview.chromium.ContentSettingsAdapter" [#2397](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2397) -- Merged "Prevent blank InAppBrowser Activity from being restored" [#1984](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1984) (thanks to [ShuheiSuzuki-07](https://github.com/ShuheiSuzuki-07)) -- Merged "Update Android Cookie Expiration date format to 24-hour format (HH)" [#2389](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2389) (thanks to [takuyaaaaaaahaaaaaa](https://github.com/takuyaaaaaaahaaaaaa)) -- Merged "[Android] allow sync navigation requests using a regular expression" [#2008](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2008) (thanks to [lyb5834](https://github.com/lyb5834)) - -## 1.1.3 - -- Updated flutter_inappwebview_platform_interface version to ^1.3.0 - -## 1.1.2 - -- Removed webview/plugin_scripts_js/ConsoleLogJS.java file, use native WebChromeClient.onConsoleMessage instead - -## 1.1.1 - -- Updated flutter_inappwebview_platform_interface version to ^1.2.0 - -## 1.1.0+4 - -- Updated flutter_inappwebview_platform_interface version - -## 1.1.0+3 - -- Fixed compilation error - -## 1.1.0+2 - -- Updated pubspec.yaml - -## 1.1.0+1 - -- Downgraded androidx.appcompat:appcompat:1.7.0 to androidx.appcompat:appcompat:1.6.1 -- Added `-dontwarn android.window.BackEvent` proguard rule - -## 1.1.0 - -- Updated androidx.webkit:webkit:1.8.0 to androidx.webkit:webkit:1.12.0 -- Updated androidx.browser:browser:1.6.0 to androidx.browser:browser:1.8.0 -- Updates minimum supported SDK version to Flutter 3.24/Dart 3.5. -- Removed unsupported WebViewFeature.SUPPRESS_ERROR_PAGE -- Merged "Remove references to deprecated v1 Android embedding" [#2176](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2176) (thanks to [gmackall](https://github.com/gmackall)) - -## 1.0.13 - -- Fixed "Android emulator using API 34 fails to draw on resume sometimes" [#1981](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1981) - -## 1.0.12 - -- Updated `flutter_inappwebview_platform_interface` version dependency to `^1.0.10` - -## 1.0.11 - -- Updated `flutter_inappwebview_platform_interface` version dependency to `^1.0.9` -- Fix typos (thanks to [michalsrutek](https://github.com/michalsrutek)) - -## 1.0.10 - -- Updated `flutter_inappwebview_platform_interface` version dependency to `^1.0.8` -- Implemented `PlatformCustomPathHandler` class - -## 1.0.9 - -- Updated `flutter_inappwebview_platform_interface` version dependency to `^1.0.7` -- Fixed "Cloudflare Turnstile failure" [#1738](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738) -- Fixed `InAppWebViewController.callAsyncJavaScript` issue when the last line of the `functionBody` parameter includes a code comment - -## 1.0.8 - -- Implemented `InAppWebViewSettings.interceptOnlyAsyncAjaxRequests` -- Implemented `PlatformInAppWebViewController.clearFormData` method -- Implemented `PlatformCookieManager.removeSessionCookies` method -- Updated `useShouldInterceptAjaxRequest` automatic infer logic -- Updated `CookieManager` methods return value - -## 1.0.7 - -- Merged "Fixed error in InterceptAjaxRequestJS 'Failed to set responseType property'" [#1904](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1904) (thanks to [EArminjon](https://github.com/EArminjon)) -- Fixed shouldInterceptAjaxRequest javascript code when overriding XMLHttpRequest.open method parameters - -## 1.0.6 - -- Fixed "getFavicons: _TypeError: type '_Map' is not a subtype of type 'Iterable'" [#1897](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1897) -- Fixed "onClosed not considering back navigation or up button / close button in ChromeSafariBrowser when using noHistory: true" [#1882](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1882) - -## 1.0.5 - -- Call `super.dispose();` on `InAppBrowser` and `ChromeSafari` implementations - -## 1.0.4 - -- Throw platform exception when ProcessGlobalConfig.apply throws an error on the native side to be able to catch it on Flutter side - -## 1.0.3 - -- Updated `ContentBlockerHandler` CSS_DISPLAY_NONE action type and `JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_SOURCE` javascript implementation code - -## 1.0.2 - -- Updated `flutter_inappwebview_platform_interface` version dependency to `1.0.2` -- Fixed "Crash when starting ChromeSafariBrowser on Android java.lang.NoSuchMethodError: No virtual method isEngagementSignalsApiAvailable" [#1881](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1881) - -## 1.0.1 - -- Updated README - -## 1.0.0 - -Initial release. diff --git a/flutter_inappwebview_android/LICENSE b/flutter_inappwebview_android/LICENSE deleted file mode 100644 index 6ccd8da42c..0000000000 --- a/flutter_inappwebview_android/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2023 Lorenzo Pichilli - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/flutter_inappwebview_android/README.md b/flutter_inappwebview_android/README.md deleted file mode 100644 index 77d0be6d60..0000000000 --- a/flutter_inappwebview_android/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# flutter\_inappwebview\_android - -The Android WebView implementation of [`flutter_inappwebview`](https://pub.dev/packages/flutter_inappwebview). - -## Usage - -This package is [endorsed](https://flutter.dev/docs/development/packages-and-plugins/developing-packages#endorsed-federated-plugin), -which means you can simply use `flutter_inappwebview` -normally. This package will be automatically included in your app when you do, -so you do not need to add it to your `pubspec.yaml`. - -However, if you `import` this package to use any of its APIs directly, you -should add it to your `pubspec.yaml` as usual. \ No newline at end of file diff --git a/flutter_inappwebview_android/analysis_options.yaml b/flutter_inappwebview_android/analysis_options.yaml deleted file mode 100644 index e2d13ab58a..0000000000 --- a/flutter_inappwebview_android/analysis_options.yaml +++ /dev/null @@ -1,16 +0,0 @@ -include: package:flutter_lints/flutter.yaml - -linter: - rules: - constant_identifier_names: ignore - deprecated_member_use_from_same_package: ignore - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options -analyzer: - errors: - constant_identifier_names: ignore - deprecated_member_use: ignore - deprecated_member_use_from_same_package: ignore - unnecessary_cast: ignore - unnecessary_import: ignore diff --git a/flutter_inappwebview_android/android/.gitignore b/flutter_inappwebview_android/android/.gitignore deleted file mode 100755 index 4b97ae3e94..0000000000 --- a/flutter_inappwebview_android/android/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -*.iml -.gradle -gradlew -gradlew.bat -gradle-wrapper.jar -/local.properties -/.idea/workspace.xml -/.idea/libraries -.DS_Store -/build -/captures -local.properties -keystore.properties \ No newline at end of file diff --git a/flutter_inappwebview_android/android/build.gradle b/flutter_inappwebview_android/android/build.gradle deleted file mode 100755 index 1f2295e464..0000000000 --- a/flutter_inappwebview_android/android/build.gradle +++ /dev/null @@ -1,62 +0,0 @@ -group 'com.pichillilorenzo.flutter_inappwebview_android' -version '1.0-SNAPSHOT' - -buildscript { - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:8.13.1' - } -} - -rootProject.allprojects { - repositories { - google() - mavenCentral() - } -} - -apply plugin: 'com.android.library' - -android { - // Conditional for compatibility with AGP <4.2. - if (project.android.hasProperty("namespace")) { - namespace 'com.pichillilorenzo.flutter_inappwebview_android' - } - compileSdk = flutter.compileSdkVersion - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - - defaultConfig { - minSdkVersion 19 - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - - vectorDrawables.useSupportLibrary = true - consumerProguardFiles 'proguard-rules.pro' - } - lintOptions { - disable 'InvalidPackage' - } - buildTypes { - debug { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - release { - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - dependencies { - implementation 'androidx.webkit:webkit:1.14.0' - implementation 'androidx.browser:browser:1.9.0' - implementation 'androidx.appcompat:appcompat:1.7.1' - implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0' - } -} diff --git a/flutter_inappwebview_android/android/gradle.properties b/flutter_inappwebview_android/android/gradle.properties deleted file mode 100644 index 94adc3a3f9..0000000000 --- a/flutter_inappwebview_android/android/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true -android.enableJetifier=true diff --git a/flutter_inappwebview_android/android/proguard-rules.pro b/flutter_inappwebview_android/android/proguard-rules.pro deleted file mode 100755 index a806bdcc44..0000000000 --- a/flutter_inappwebview_android/android/proguard-rules.pro +++ /dev/null @@ -1,19 +0,0 @@ -# WebView --keepattributes *JavascriptInterface* --keepclassmembers class * { - @android.webkit.JavascriptInterface ; -} --keepclassmembers class * extends android.webkit.WebViewClient { - public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap); - public boolean *(android.webkit.WebView, java.lang.String); - public void *(android.webkit.webView, jav.lang.String); -} --keepclassmembers class com.pichillilorenzo.flutter_inappwebview_android$JavaScriptBridgeInterface { - ; - ; - public *; - private *; -} --keep class com.pichillilorenzo.flutter_inappwebview_android.** { *; } - --dontwarn android.window.BackEvent \ No newline at end of file diff --git a/flutter_inappwebview_android/android/settings.gradle b/flutter_inappwebview_android/android/settings.gradle deleted file mode 100755 index 5841fff020..0000000000 --- a/flutter_inappwebview_android/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'flutter_inappwebview_android' diff --git a/flutter_inappwebview_android/android/src/main/AndroidManifest.xml b/flutter_inappwebview_android/android/src/main/AndroidManifest.xml deleted file mode 100755 index c8036b21bc..0000000000 --- a/flutter_inappwebview_android/android/src/main/AndroidManifest.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/flutter_inappwebview_android/android/src/main/java/android/print/InAppWebViewPrintDocumentAdapter.java b/flutter_inappwebview_android/android/src/main/java/android/print/InAppWebViewPrintDocumentAdapter.java deleted file mode 100644 index 2d31781710..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/android/print/InAppWebViewPrintDocumentAdapter.java +++ /dev/null @@ -1,123 +0,0 @@ -package android.print; - -import android.os.Bundle; -import android.os.CancellationSignal; -import android.os.ParcelFileDescriptor; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -public class InAppWebViewPrintDocumentAdapter extends PrintDocumentAdapter { - @NonNull - private final PrintDocumentAdapter delegate; - @Nullable - private final PrintDocumentAdapterCallback callback; - - public InAppWebViewPrintDocumentAdapter(@NonNull PrintDocumentAdapter delegate, @Nullable PrintDocumentAdapterCallback callback) { - this.delegate = delegate; - this.callback = callback; - } - - @Override - public void onStart() { - this.delegate.onStart(); - if (this.callback != null) this.callback.onStart(); - } - - @Override - public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback layoutResultCallback, Bundle extras) { - this.delegate.onLayout(oldAttributes, newAttributes, cancellationSignal, new LayoutResultCallback() { - @Override - public void onLayoutFinished(PrintDocumentInfo info, boolean changed) { - layoutResultCallback.onLayoutFinished(info, changed); - if (callback != null) callback.onLayoutFinished(info, changed); - } - - @Override - public void onLayoutFailed(CharSequence error) { - layoutResultCallback.onLayoutFailed(error); - if (callback != null) callback.onLayoutFailed(error); - } - - @Override - public void onLayoutCancelled() { - layoutResultCallback.onLayoutCancelled(); - if (callback != null) callback.onLayoutCancelled(); - } - }, extras); - - if (callback != null) callback.onLayout(oldAttributes, newAttributes, cancellationSignal, layoutResultCallback, extras); - } - - @Override - public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback writeResultCallback) { - this.delegate.onWrite(pages, destination, cancellationSignal, new WriteResultCallback() { - @Override - public void onWriteFinished(PageRange[] pages) { - writeResultCallback.onWriteFinished(pages); - if (callback != null) callback.onWriteFinished(pages); - } - - @Override - public void onWriteFailed(CharSequence error) { - writeResultCallback.onWriteFailed(error); - if (callback != null) callback.onWriteFailed(error); - } - - @Override - public void onWriteCancelled() { - writeResultCallback.onWriteCancelled(); - if (callback != null) callback.onWriteCancelled(); - } - }); - if (callback != null) callback.onWrite(pages, destination, cancellationSignal, writeResultCallback); - } - - @Override - public void onFinish() { - this.delegate.onFinish(); - if (this.callback != null) this.callback.onFinish(); - } - - public static class PrintDocumentAdapterCallback { - public void onStart() { - /* do nothing - stub */ - } - - public void onFinish() { - /* do nothing - stub */ - } - - public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback layoutResultCallback, Bundle extras) { - /* do nothing - stub */ - } - - public void onLayoutFinished(PrintDocumentInfo info, boolean changed) { - /* do nothing - stub */ - } - - public void onLayoutFailed(CharSequence error) { - /* do nothing - stub */ - } - - public void onLayoutCancelled() { - /* do nothing - stub */ - } - - public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback writeResultCallback) { - /* do nothing - stub */ - } - - public void onWriteFinished(PageRange[] pages) { - /* do nothing - stub */ - } - - public void onWriteFailed(CharSequence error) { - /* do nothing - stub */ - } - - public void onWriteCancelled() { - /* do nothing - stub */ - } - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/ISettings.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/ISettings.java deleted file mode 100755 index c005c2edb6..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/ISettings.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android; - -import androidx.annotation.NonNull; - -import java.util.Map; - -public interface ISettings { - @NonNull ISettings parse(@NonNull Map settings); - @NonNull Map toMap(); - @NonNull Map getRealSettings(@NonNull T obj); -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/InAppWebViewFileProvider.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/InAppWebViewFileProvider.java deleted file mode 100644 index 3db8636292..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/InAppWebViewFileProvider.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android; - -import androidx.core.content.FileProvider; - -public class InAppWebViewFileProvider extends FileProvider { - - public static final String fileProviderAuthorityExtension = "flutter_inappwebview_android.fileprovider"; - -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/InAppWebViewFlutterPlugin.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/InAppWebViewFlutterPlugin.java deleted file mode 100755 index 21ce254a94..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/InAppWebViewFlutterPlugin.java +++ /dev/null @@ -1,224 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android; - -import android.app.Activity; -import android.content.Context; -import android.os.Build; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs.ChromeSafariBrowserManager; -import com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs.NoHistoryCustomTabsActivityCallbacks; -import com.pichillilorenzo.flutter_inappwebview_android.credential_database.CredentialDatabaseHandler; -import com.pichillilorenzo.flutter_inappwebview_android.headless_in_app_webview.HeadlessInAppWebViewManager; -import com.pichillilorenzo.flutter_inappwebview_android.in_app_browser.InAppBrowserManager; -import com.pichillilorenzo.flutter_inappwebview_android.print_job.PrintJobManager; -import com.pichillilorenzo.flutter_inappwebview_android.process_global_config.ProcessGlobalConfigManager; -import com.pichillilorenzo.flutter_inappwebview_android.proxy.ProxyManager; -import com.pichillilorenzo.flutter_inappwebview_android.service_worker.ServiceWorkerManager; -import com.pichillilorenzo.flutter_inappwebview_android.tracing.TracingControllerManager; -import com.pichillilorenzo.flutter_inappwebview_android.webview.FlutterWebViewFactory; -import com.pichillilorenzo.flutter_inappwebview_android.webview.InAppWebViewManager; - -import io.flutter.embedding.engine.plugins.FlutterPlugin; -import io.flutter.embedding.engine.plugins.activity.ActivityAware; -import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; -import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.platform.PlatformViewRegistry; -import io.flutter.embedding.android.FlutterView; - -public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware { - - protected static final String LOG_TAG = "InAppWebViewFlutterPL"; - - @Nullable - public PlatformUtil platformUtil; - @Nullable - public InAppBrowserManager inAppBrowserManager; - @Nullable - public HeadlessInAppWebViewManager headlessInAppWebViewManager; - @Nullable - public ChromeSafariBrowserManager chromeSafariBrowserManager; - @Nullable - public NoHistoryCustomTabsActivityCallbacks noHistoryCustomTabsActivityCallbacks; - @Nullable - public InAppWebViewManager inAppWebViewManager; - @Nullable - public MyCookieManager myCookieManager; - @Nullable - public CredentialDatabaseHandler credentialDatabaseHandler; - @Nullable - public MyWebStorage myWebStorage; - @Nullable - public ServiceWorkerManager serviceWorkerManager; - @Nullable - public WebViewFeatureManager webViewFeatureManager; - @Nullable - public ProxyManager proxyManager; - @Nullable - public PrintJobManager printJobManager; - @Nullable - public TracingControllerManager tracingControllerManager; - @Nullable - public ProcessGlobalConfigManager processGlobalConfigManager; - public FlutterWebViewFactory flutterWebViewFactory; - public Context applicationContext; - public BinaryMessenger messenger; - public FlutterPlugin.FlutterAssets flutterAssets; - @Nullable - public ActivityPluginBinding activityPluginBinding; - @Nullable - public Activity activity; - public FlutterView flutterView; - - public InAppWebViewFlutterPlugin() {} - - @Override - public void onAttachedToEngine(FlutterPluginBinding binding) { - this.flutterAssets = binding.getFlutterAssets(); - - // Shared.activity could be null or not. - // It depends on who is called first between onAttachedToEngine event and onAttachedToActivity event. - // - // See https://github.com/pichillilorenzo/flutter_inappwebview/issues/390#issuecomment-647039084 - onAttachedToEngine( - binding.getApplicationContext(), binding.getBinaryMessenger(), this.activity, binding.getPlatformViewRegistry(), null); - } - - private void onAttachedToEngine(Context applicationContext, BinaryMessenger messenger, Activity activity, PlatformViewRegistry platformViewRegistry, FlutterView flutterView) { - this.applicationContext = applicationContext; - this.activity = activity; - this.messenger = messenger; - this.flutterView = flutterView; - - inAppBrowserManager = new InAppBrowserManager(this); - headlessInAppWebViewManager = new HeadlessInAppWebViewManager(this); - chromeSafariBrowserManager = new ChromeSafariBrowserManager(this); - noHistoryCustomTabsActivityCallbacks = new NoHistoryCustomTabsActivityCallbacks(this); - flutterWebViewFactory = new FlutterWebViewFactory(this); - platformViewRegistry.registerViewFactory( - FlutterWebViewFactory.VIEW_TYPE_ID, flutterWebViewFactory); - - platformUtil = new PlatformUtil(this); - inAppWebViewManager = new InAppWebViewManager(this); - myCookieManager = new MyCookieManager(this); - myWebStorage = new MyWebStorage(this); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - serviceWorkerManager = new ServiceWorkerManager(this); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - credentialDatabaseHandler = new CredentialDatabaseHandler(this); - } - webViewFeatureManager = new WebViewFeatureManager(this); - proxyManager = new ProxyManager(this); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - printJobManager = new PrintJobManager(this); - } - tracingControllerManager = new TracingControllerManager(this); - processGlobalConfigManager = new ProcessGlobalConfigManager(this); - } - - @Override - public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { - if (platformUtil != null) { - platformUtil.dispose(); - platformUtil = null; - } - if (inAppBrowserManager != null) { - inAppBrowserManager.dispose(); - inAppBrowserManager = null; - } - if (headlessInAppWebViewManager != null) { - headlessInAppWebViewManager.dispose(); - headlessInAppWebViewManager = null; - } - if (chromeSafariBrowserManager != null) { - chromeSafariBrowserManager.dispose(); - chromeSafariBrowserManager = null; - } - if (noHistoryCustomTabsActivityCallbacks != null) { - noHistoryCustomTabsActivityCallbacks.dispose(); - noHistoryCustomTabsActivityCallbacks = null; - } - if (myCookieManager != null) { - myCookieManager.dispose(); - myCookieManager = null; - } - if (myWebStorage != null) { - myWebStorage.dispose(); - myWebStorage = null; - } - if (credentialDatabaseHandler != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - credentialDatabaseHandler.dispose(); - credentialDatabaseHandler = null; - } - if (inAppWebViewManager != null) { - inAppWebViewManager.dispose(); - inAppWebViewManager = null; - } - if (serviceWorkerManager != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - serviceWorkerManager.dispose(); - serviceWorkerManager = null; - } - if (webViewFeatureManager != null) { - webViewFeatureManager.dispose(); - webViewFeatureManager = null; - } - if (proxyManager != null) { - proxyManager.dispose(); - proxyManager = null; - } - if (printJobManager != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - printJobManager.dispose(); - printJobManager = null; - } - if (tracingControllerManager != null) { - tracingControllerManager.dispose(); - tracingControllerManager = null; - } - if (processGlobalConfigManager != null) { - processGlobalConfigManager.dispose(); - processGlobalConfigManager = null; - } - } - - @Override - public void onAttachedToActivity(ActivityPluginBinding activityPluginBinding) { - this.activityPluginBinding = activityPluginBinding; - this.activity = activityPluginBinding.getActivity(); - - if (noHistoryCustomTabsActivityCallbacks != null) { - this.activity.getApplication().registerActivityLifecycleCallbacks(noHistoryCustomTabsActivityCallbacks.activityLifecycleCallbacks); - } - } - - @Override - public void onDetachedFromActivityForConfigChanges() { - if (activity != null && noHistoryCustomTabsActivityCallbacks != null) { - this.activity.getApplication().unregisterActivityLifecycleCallbacks(noHistoryCustomTabsActivityCallbacks.activityLifecycleCallbacks); - } - - activityPluginBinding = null; - activity = null; - } - - @Override - public void onReattachedToActivityForConfigChanges(ActivityPluginBinding activityPluginBinding) { - this.activityPluginBinding = activityPluginBinding; - this.activity = activityPluginBinding.getActivity(); - - if (noHistoryCustomTabsActivityCallbacks != null) { - this.activity.getApplication().registerActivityLifecycleCallbacks(noHistoryCustomTabsActivityCallbacks.activityLifecycleCallbacks); - } - } - - @Override - public void onDetachedFromActivity() { - if (activity != null && noHistoryCustomTabsActivityCallbacks != null) { - this.activity.getApplication().unregisterActivityLifecycleCallbacks(noHistoryCustomTabsActivityCallbacks.activityLifecycleCallbacks); - } - - activityPluginBinding = null; - activity = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/MyCookieManager.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/MyCookieManager.java deleted file mode 100755 index dccb7eabf3..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/MyCookieManager.java +++ /dev/null @@ -1,454 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android; - -import android.os.Build; -import android.util.Log; -import android.webkit.CookieManager; -import android.webkit.CookieSyncManager; -import android.webkit.ValueCallback; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.CookieManagerCompat; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.TimeZone; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class MyCookieManager extends ChannelDelegateImpl { - protected static final String LOG_TAG = "MyCookieManager"; - public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_cookiemanager"; - @Nullable - public static CookieManager cookieManager; - @Nullable - public InAppWebViewFlutterPlugin plugin; - - public MyCookieManager(@NonNull final InAppWebViewFlutterPlugin plugin) { - super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME)); - this.plugin = plugin; - } - - public static void init() { - if (cookieManager == null) { - cookieManager = getCookieManager(); - } - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - init(); - - switch (call.method) { - case "setCookie": - { - String url = (String) call.argument("url"); - String name = (String) call.argument("name"); - String value = (String) call.argument("value"); - String domain = (String) call.argument("domain"); - String path = (String) call.argument("path"); - String expiresDateString = (String) call.argument("expiresDate"); - Long expiresDate = (expiresDateString != null ? new Long(expiresDateString) : null); - Integer maxAge = (Integer) call.argument("maxAge"); - Boolean isSecure = (Boolean) call.argument("isSecure"); - Boolean isHttpOnly = (Boolean) call.argument("isHttpOnly"); - String sameSite = (String) call.argument("sameSite"); - setCookie(url, - name, - value, - domain, - path, - expiresDate, - maxAge, - isSecure, - isHttpOnly, - sameSite, - result); - } - break; - case "getCookies": - result.success(getCookies((String) call.argument("url"))); - break; - case "deleteCookie": - { - String url = (String) call.argument("url"); - String name = (String) call.argument("name"); - String domain = (String) call.argument("domain"); - String path = (String) call.argument("path"); - deleteCookie(url, name, domain, path, result); - } - break; - case "deleteCookies": - { - String url = (String) call.argument("url"); - String domain = (String) call.argument("domain"); - String path = (String) call.argument("path"); - deleteCookies(url, domain, path, result); - } - break; - case "deleteAllCookies": - deleteAllCookies(result); - break; - case "removeSessionCookies": - removeSessionCookies(result); - break; - case "flush": - flush(result); - break; - default: - result.notImplemented(); - } - } - - /** - * Instantiating CookieManager will load the Chromium task taking a 100ish ms so we do it lazily - * to make sure it's done on a background thread as needed. - * - * https://github.com/facebook/react-native/blob/1903f6680d9750e244d97c3cd4a9f755a9a47c61/ReactAndroid/src/main/java/com/facebook/react/modules/network/ForwardingCookieHandler.java#L132 - */ - static private @Nullable CookieManager getCookieManager() { - if (cookieManager == null) { - try { - cookieManager = CookieManager.getInstance(); - } catch (IllegalArgumentException ex) { - // https://bugs.chromium.org/p/chromium/issues/detail?id=559720 - return null; - } catch (Exception exception) { - String message = exception.getMessage(); - // We cannot catch MissingWebViewPackageException as it is in a private / system API - // class. This validates the exception's message to ensure we are only handling this - // specific exception. - // https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/webkit/WebViewFactory.java#348 - if (message != null - && exception - .getClass() - .getCanonicalName() - .equals("android.webkit.WebViewFactory.MissingWebViewPackageException")) { - return null; - } else { - throw exception; - } - } - } - - return cookieManager; - } - - public void setCookie(String url, - String name, - String value, - String domain, - String path, - Long expiresDate, - Integer maxAge, - Boolean isSecure, - Boolean isHttpOnly, - String sameSite, - final MethodChannel.Result result) { - cookieManager = getCookieManager(); - if (cookieManager == null) { - result.success(false); - return; - } - - String cookieValue = name + "=" + value + "; Path=" + path; - - if (domain != null) - cookieValue += "; Domain=" + domain; - - if (expiresDate != null) - cookieValue += "; Expires=" + getCookieExpirationDate(expiresDate); - - if (maxAge != null) - cookieValue += "; Max-Age=" + maxAge.toString(); - - if (isSecure != null && isSecure) - cookieValue += "; Secure"; - - if (isHttpOnly != null && isHttpOnly) - cookieValue += "; HttpOnly"; - - if (sameSite != null) - cookieValue += "; SameSite=" + sameSite; - - cookieValue += ";"; - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - cookieManager.setCookie(url, cookieValue, new ValueCallback() { - @Override - public void onReceiveValue(Boolean successful) { - result.success(successful); - } - }); - cookieManager.flush(); - } - else if (plugin != null) { - CookieSyncManager cookieSyncMngr = CookieSyncManager.createInstance(plugin.applicationContext); - cookieSyncMngr.startSync(); - cookieManager.setCookie(url, cookieValue); - cookieSyncMngr.stopSync(); - cookieSyncMngr.sync(); - result.success(true); - } else { - cookieManager.setCookie(url, cookieValue); - result.success(true); - } - } - - public List> getCookies(final String url) { - - final List> cookieListMap = new ArrayList<>(); - - cookieManager = getCookieManager(); - if (cookieManager == null) return cookieListMap; - - List cookies = new ArrayList<>(); - if (WebViewFeature.isFeatureSupported(WebViewFeature.GET_COOKIE_INFO)) { - cookies = CookieManagerCompat.getCookieInfo(cookieManager, url); - } else { - String cookiesString = cookieManager.getCookie(url); - if (cookiesString != null) { - cookies = Arrays.asList(cookiesString.split(";")); - } - } - - for (String cookie : cookies) { - String[] cookieParams = cookie.split(";"); - if (cookieParams.length == 0) continue; - - String[] nameValue = cookieParams[0].split("=", 2); - String name = nameValue[0].trim(); - String value = (nameValue.length > 1) ? nameValue[1].trim() : ""; - - Map cookieMap = new HashMap<>(); - cookieMap.put("name", name); - cookieMap.put("value", value); - cookieMap.put("expiresDate", null); - cookieMap.put("isSessionOnly", null); - cookieMap.put("domain", null); - cookieMap.put("sameSite", null); - cookieMap.put("isSecure", null); - cookieMap.put("isHttpOnly", null); - cookieMap.put("path", null); - - if (WebViewFeature.isFeatureSupported(WebViewFeature.GET_COOKIE_INFO)) { - cookieMap.put("isSecure", false); - cookieMap.put("isHttpOnly", false); - - for (int i = 1; i < cookieParams.length; i++) { - String[] cookieParamNameValue = cookieParams[i].split("=", 2); - String cookieParamName = cookieParamNameValue[0].trim(); - String cookieParamValue = (cookieParamNameValue.length > 1) ? cookieParamNameValue[1].trim() : ""; - - if (cookieParamName.equalsIgnoreCase("Expires")) { - try { - final SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); - Date expiryDate = sdf.parse(cookieParamValue); - if (expiryDate != null) { - cookieMap.put("expiresDate", expiryDate.getTime()); - } - } catch (ParseException e) { - Log.e(LOG_TAG, "", e); - } - } else if (cookieParamName.equalsIgnoreCase("Max-Age")) { - try { - long maxAge = Long.parseLong(cookieParamValue); - cookieMap.put("expiresDate", System.currentTimeMillis() + maxAge); - } catch (NumberFormatException e) { - Log.e(LOG_TAG, "", e); - } - } else if (cookieParamName.equalsIgnoreCase("Domain")) { - cookieMap.put("domain", cookieParamValue); - } else if (cookieParamName.equalsIgnoreCase("SameSite")) { - cookieMap.put("sameSite", cookieParamValue); - } else if (cookieParamName.equalsIgnoreCase("Secure")) { - cookieMap.put("isSecure", true); - } else if (cookieParamName.equalsIgnoreCase("HttpOnly")) { - cookieMap.put("isHttpOnly", true); - } else if (cookieParamName.equalsIgnoreCase("Path")) { - cookieMap.put("path", cookieParamValue); - } - } - } - - cookieListMap.add(cookieMap); - } - return cookieListMap; - - } - - public void deleteCookie(String url, String name, String domain, String path, final MethodChannel.Result result) { - cookieManager = getCookieManager(); - if (cookieManager == null) { - result.success(false); - return; - } - - String cookieValue = name + "=; Path=" + path + "; Max-Age=-1"; - - if (domain != null) - cookieValue += "; Domain=" + domain; - - cookieValue += ";"; - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - cookieManager.setCookie(url, cookieValue, new ValueCallback() { - @Override - public void onReceiveValue(Boolean successful) { - result.success(successful); - } - }); - cookieManager.flush(); - } - else if (plugin != null) { - CookieSyncManager cookieSyncMngr = CookieSyncManager.createInstance(plugin.applicationContext); - cookieSyncMngr.startSync(); - cookieManager.setCookie(url, cookieValue); - cookieSyncMngr.stopSync(); - cookieSyncMngr.sync(); - result.success(true); - } else { - cookieManager.setCookie(url, cookieValue); - result.success(true); - } - } - - public void deleteCookies(String url, String domain, String path, final MethodChannel.Result result) { - cookieManager = getCookieManager(); - if (cookieManager == null) { - result.success(false); - return; - } - - CookieSyncManager cookieSyncMngr = null; - - String cookiesString = cookieManager.getCookie(url); - if (cookiesString != null) { - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && plugin != null) { - cookieSyncMngr = CookieSyncManager.createInstance(plugin.applicationContext); - cookieSyncMngr.startSync(); - } - - String[] cookies = cookiesString.split(";"); - for (String cookie : cookies) { - String[] nameValue = cookie.split("=", 2); - String name = nameValue[0].trim(); - - String cookieValue = name + "=; Path=" + path + "; Max-Age=-1"; - - if (domain != null) - cookieValue += "; Domain=" + domain; - - cookieValue += ";"; - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - cookieManager.setCookie(url, cookieValue, null); - else - cookieManager.setCookie(url, cookieValue); - } - - if (cookieSyncMngr != null) { - cookieSyncMngr.stopSync(); - cookieSyncMngr.sync(); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - cookieManager.flush(); - } - result.success(true); - } - - public void deleteAllCookies(final MethodChannel.Result result) { - cookieManager = getCookieManager(); - if (cookieManager == null) { - result.success(false); - return; - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - cookieManager.removeAllCookies(new ValueCallback() { - @Override - public void onReceiveValue(Boolean successful) { - result.success(successful); - } - }); - cookieManager.flush(); - } - else if (plugin != null) { - CookieSyncManager cookieSyncMngr = CookieSyncManager.createInstance(plugin.applicationContext); - cookieSyncMngr.startSync(); - cookieManager.removeAllCookie(); - cookieSyncMngr.stopSync(); - cookieSyncMngr.sync(); - result.success(true); - } else { - cookieManager.removeAllCookie(); - result.success(true); - } - } - - public void removeSessionCookies(final MethodChannel.Result result) { - cookieManager = getCookieManager(); - if (cookieManager == null) { - result.success(false); - return; - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - cookieManager.removeSessionCookies(new ValueCallback() { - @Override - public void onReceiveValue(Boolean successful) { - result.success(successful); - } - }); - cookieManager.flush(); - } - else if (plugin != null) { - CookieSyncManager cookieSyncMngr = CookieSyncManager.createInstance(plugin.applicationContext); - cookieSyncMngr.startSync(); - cookieManager.removeSessionCookie(); - cookieSyncMngr.stopSync(); - cookieSyncMngr.sync(); - result.success(true); - } else { - cookieManager.removeSessionCookie(); - result.success(true); - } - } - - public void flush(MethodChannel.Result result) { - cookieManager = getCookieManager(); - if (cookieManager == null) { - result.success(false); - return; - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - cookieManager.flush(); - } else if (plugin != null) { - CookieSyncManager cookieSyncMngr = CookieSyncManager.createInstance(plugin.applicationContext); - cookieSyncMngr.sync(); - } - } - - public static String getCookieExpirationDate(Long timestamp) { - final SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); - sdf.setTimeZone(TimeZone.getTimeZone("GMT")); - return sdf.format(new Date(timestamp)); - } - - @Override - public void dispose() { - super.dispose(); - plugin = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/MyWebStorage.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/MyWebStorage.java deleted file mode 100755 index d826b58381..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/MyWebStorage.java +++ /dev/null @@ -1,138 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android; - -import android.webkit.ValueCallback; -import android.webkit.WebStorage; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class MyWebStorage extends ChannelDelegateImpl { - protected static final String LOG_TAG = "MyWebStorage"; - public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webstoragemanager"; - - @Nullable - public static WebStorage webStorageManager; - @Nullable - public InAppWebViewFlutterPlugin plugin; - - public MyWebStorage(@NonNull final InAppWebViewFlutterPlugin plugin) { - super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME)); - this.plugin = plugin; - } - - public static void init() { - if (webStorageManager == null) { - webStorageManager = WebStorage.getInstance(); - } - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - init(); - - switch (call.method) { - case "getOrigins": - getOrigins(result); - break; - case "deleteAllData": - if (webStorageManager != null) { - webStorageManager.deleteAllData(); - result.success(true); - } else { - result.success(false); - } - break; - case "deleteOrigin": - { - if (webStorageManager != null) { - String origin = (String) call.argument("origin"); - webStorageManager.deleteOrigin(origin); - result.success(true); - } else { - result.success(false); - } - } - break; - case "getQuotaForOrigin": - { - String origin = (String) call.argument("origin"); - getQuotaForOrigin(origin, result); - } - break; - case "getUsageForOrigin": - { - String origin = (String) call.argument("origin"); - getUsageForOrigin(origin, result); - } - break; - default: - result.notImplemented(); - } - } - - public void getOrigins(final MethodChannel.Result result) { - if (webStorageManager == null) { - result.success(new ArrayList<>()); - return; - } - webStorageManager.getOrigins(new ValueCallback() { - @Override - public void onReceiveValue(Map value) { - List> origins = new ArrayList<>(); - for(Object key : value.keySet()) { - WebStorage.Origin originObj = (WebStorage.Origin) value.get(key); - - Map originInfo = new HashMap<>(); - originInfo.put("origin", originObj.getOrigin()); - originInfo.put("quota", originObj.getQuota()); - originInfo.put("usage", originObj.getUsage()); - - origins.add(originInfo); - } - result.success(origins); - } - }); - } - - public void getQuotaForOrigin(String origin, final MethodChannel.Result result) { - if (webStorageManager == null) { - result.success(0); - return; - } - webStorageManager.getQuotaForOrigin(origin, new ValueCallback() { - @Override - public void onReceiveValue(Long value) { - result.success(value); - } - }); - } - - public void getUsageForOrigin(String origin, final MethodChannel.Result result) { - if (webStorageManager == null) { - result.success(0); - return; - } - webStorageManager.getUsageForOrigin(origin, new ValueCallback() { - @Override - public void onReceiveValue(Long value) { - result.success(value); - } - }); - } - - @Override - public void dispose() { - super.dispose(); - plugin = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/PlatformUtil.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/PlatformUtil.java deleted file mode 100755 index 7a2459fcf7..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/PlatformUtil.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android; - -import android.os.Build; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class PlatformUtil extends ChannelDelegateImpl { - protected static final String LOG_TAG = "PlatformUtil"; - public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_platformutil"; - - @Nullable - public InAppWebViewFlutterPlugin plugin; - - public PlatformUtil(final InAppWebViewFlutterPlugin plugin) { - super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME)); - this.plugin = plugin; - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) { - switch (call.method) { - case "getSystemVersion": - result.success(String.valueOf(Build.VERSION.SDK_INT)); - break; - case "formatDate": - long date = (long) call.argument("date"); - String format = (String) call.argument("format"); - Locale locale = PlatformUtil.getLocaleFromString((String) call.argument("locale")); - String timezone = (String) call.argument("timezone"); - if (timezone == null) { - timezone = "UTC"; - } - result.success(PlatformUtil.formatDate(date, format, locale, TimeZone.getTimeZone(timezone))); - break; - default: - result.notImplemented(); - } - } - - public static Locale getLocaleFromString(@Nullable String locale) { - if (locale == null) { - return Locale.US; - } - String[] localeSplit = locale.split("_"); - String language = localeSplit[0]; - String country = localeSplit.length > 1 ? localeSplit[1] : ""; - String variant = localeSplit.length > 2 ? localeSplit[2] : ""; - return new Locale(language, country, variant); - } - - public static String formatDate(long date, String format, Locale locale, TimeZone timezone) { - final SimpleDateFormat sdf = new SimpleDateFormat(format, locale); - sdf.setTimeZone(timezone); - return sdf.format(new Date(date)); - } - - @Override - public void dispose() { - super.dispose(); - plugin = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/Util.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/Util.java deleted file mode 100755 index 1531562129..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/Util.java +++ /dev/null @@ -1,386 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android; - -import android.content.Context; -import android.content.res.AssetManager; -import android.graphics.BitmapFactory; -import android.graphics.Insets; -import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.net.http.SslCertificate; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.text.TextUtils; -import android.util.DisplayMetrics; -import android.util.Log; -import android.view.WindowInsets; -import android.view.WindowManager; -import android.view.WindowMetrics; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; - -import com.pichillilorenzo.flutter_inappwebview_android.types.Size2D; -import com.pichillilorenzo.flutter_inappwebview_android.types.SyncBaseCallbackResultImpl; - -import org.json.JSONArray; -import org.json.JSONObject; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.HttpURLConnection; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.URL; -import java.net.UnknownHostException; -import java.security.Key; -import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.Enumeration; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.regex.Pattern; - -import javax.net.ssl.SSLHandshakeException; - -import io.flutter.plugin.common.MethodChannel; - -public class Util { - - static final String LOG_TAG = "Util"; - public static final String ANDROID_ASSET_URL = "file:///android_asset/"; - - private Util() {} - - public static String getUrlAsset(InAppWebViewFlutterPlugin plugin, String assetFilePath) throws IOException { - String key = plugin.flutterAssets.getAssetFilePathByName(assetFilePath); - InputStream is = null; - IOException e = null; - - try { - is = getFileAsset(plugin, assetFilePath); - } catch (IOException ex) { - e = ex; - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException ex) { - e = ex; - } - } - } - if (e != null) { - throw e; - } - - return ANDROID_ASSET_URL + key; - } - - public static InputStream getFileAsset(InAppWebViewFlutterPlugin plugin, String assetFilePath) throws IOException { - String key = plugin.flutterAssets.getAssetFilePathByName(assetFilePath); - AssetManager mg = plugin.applicationContext.getResources().getAssets(); - return mg.open(key); - } - - public static T invokeMethodAndWaitResult(final @NonNull MethodChannel channel, - final @NonNull String method, final @Nullable Object arguments, - final @NonNull SyncBaseCallbackResultImpl callback) throws InterruptedException { - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - @Override - public void run() { - channel.invokeMethod(method, arguments, callback); - } - }); - callback.latch.await(); - return callback.result; - } - - @Nullable - public static PrivateKeyAndCertificates loadPrivateKeyAndCertificate(@NonNull InAppWebViewFlutterPlugin plugin, - @NonNull String certificatePath, - @Nullable String certificatePassword, - @NonNull String keyStoreType) { - PrivateKeyAndCertificates privateKeyAndCertificates = null; - InputStream certificateFileStream = null; - - try { - certificateFileStream = getFileAsset(plugin, certificatePath); - } catch (IOException ignored) {} - - try { - if (certificateFileStream == null) { - certificateFileStream = new FileInputStream(certificatePath); - } - KeyStore keyStore = KeyStore.getInstance(keyStoreType); - keyStore.load(certificateFileStream, (certificatePassword != null ? certificatePassword : "").toCharArray()); - - Enumeration aliases = keyStore.aliases(); - String alias = aliases.nextElement(); - - Key key = keyStore.getKey(alias, (certificatePassword != null ? certificatePassword : "").toCharArray()); - if (key instanceof PrivateKey) { - PrivateKey privateKey = (PrivateKey)key; - Certificate cert = keyStore.getCertificate(alias); - X509Certificate[] certificates = new X509Certificate[1]; - certificates[0] = (X509Certificate)cert; - privateKeyAndCertificates = new PrivateKeyAndCertificates(privateKey, certificates); - } - certificateFileStream.close(); - } catch (Exception e) { - Log.e(LOG_TAG, "", e); - } finally { - if (certificateFileStream != null) { - try { - certificateFileStream.close(); - } catch (IOException ex) { - Log.e(LOG_TAG, "", ex); - } - } - } - - return privateKeyAndCertificates; - } - - public static class PrivateKeyAndCertificates { - - public X509Certificate[] certificates; - public PrivateKey privateKey; - - public PrivateKeyAndCertificates(PrivateKey privateKey, X509Certificate[] certificates) { - this.privateKey = privateKey; - this.certificates = certificates; - } - } - - @Nullable - public static HttpURLConnection makeHttpRequest(String urlString, String method, @Nullable Map headers) { - HttpURLConnection urlConnection = null; - try { - URL url = new URL(urlString); - urlConnection = (HttpURLConnection) url.openConnection(); - urlConnection.setRequestMethod(method); - if (headers != null) { - for (Map.Entry header : headers.entrySet()) { - urlConnection.setRequestProperty(header.getKey(), header.getValue()); - } - } - urlConnection.setConnectTimeout(15000); // 15 seconds - urlConnection.setReadTimeout(15000); // 15 seconds - urlConnection.setDoInput(true); - urlConnection.setInstanceFollowRedirects(true); - if ("GET".equalsIgnoreCase(method)) { - urlConnection.setDoOutput(false); - } - urlConnection.connect(); - return urlConnection; - } - catch (Exception e) { - if (!(e instanceof SSLHandshakeException)) { - Log.e(LOG_TAG, "", e); - } - if (urlConnection != null) { - urlConnection.disconnect(); - } - } - return null; - } - - /** - * SslCertificate class does not has a public getter for the underlying - * X509Certificate, we can only do this by hack. This only works for Android 4.0+ - * https://groups.google.com/forum/#!topic/android-developers/eAPJ6b7mrmg - */ - public static X509Certificate getX509CertFromSslCertHack(SslCertificate sslCert) { - X509Certificate x509Certificate = null; - - Bundle bundle = SslCertificate.saveState(sslCert); - byte[] bytes = bundle.getByteArray("x509-certificate"); - - if (bytes == null) { - x509Certificate = null; - } else { - try { - CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); - Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes)); - x509Certificate = (X509Certificate) cert; - } catch (CertificateException e) { - x509Certificate = null; - } - } - - return x509Certificate; - } - - @RequiresApi(api = Build.VERSION_CODES.KITKAT) - public static String JSONStringify(@Nullable Object value) { - if (value == null) { - return "null"; - } - if (value instanceof Map) { - return new JSONObject((Map) value).toString(); - } else if (value instanceof List) { - return new JSONArray((List) value).toString(); - } else if (value instanceof String) { - return JSONObject.quote((String) value); - } else { - return JSONObject.wrap(value).toString(); - } - } - - public static boolean objEquals(@Nullable Object a, @Nullable Object b) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - return Objects.equals(a, b); - } - return (a == b) || (a != null && a.equals(b)); - } - - public static String replaceAll(String s, String oldString, String newString) { - return TextUtils.join(newString, s.split(Pattern.quote(oldString))); - } - - public static void log(String tag, String message) { - // Split by line, then ensure each line can fit into Log's maximum length. - for (int i = 0, length = message.length(); i < length; i++) { - int newline = message.indexOf('\n', i); - newline = newline != -1 ? newline : length; - do { - int end = Math.min(newline, i + 4000); - Log.d(tag, message.substring(i, end)); - i = end; - } while (i < newline); - } - } - - public static float getPixelDensity(Context context) { - return context.getResources().getDisplayMetrics().density; - } - - public static Size2D getFullscreenSize(Context context) { - Size2D fullscreenSize = new Size2D(-1, -1); - WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - if (wm != null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - final WindowMetrics metrics = wm.getCurrentWindowMetrics(); - // Gets all excluding insets - final WindowInsets windowInsets = metrics.getWindowInsets(); - Insets insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars() - | WindowInsets.Type.displayCutout()); - int insetsWidth = insets.right + insets.left; - int insetsHeight = insets.top + insets.bottom; - final Rect bounds = metrics.getBounds(); - fullscreenSize.setWidth(bounds.width() - insetsWidth); - fullscreenSize.setHeight(bounds.height() - insetsHeight); - } else { - DisplayMetrics displayMetrics = new DisplayMetrics(); - wm.getDefaultDisplay().getMetrics(displayMetrics); - fullscreenSize.setWidth(displayMetrics.widthPixels); - fullscreenSize.setHeight(displayMetrics.heightPixels); - } - } - return fullscreenSize; - } - - public static boolean isClass(String className) { - try { - Class.forName(className); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - - public static boolean isIPv6(String address) { - try { - Inet6Address.getByName(address); - } catch (UnknownHostException e) { - return false; - } - return true; - } - - public static String normalizeIPv6(String address) throws Exception { - if (!Util.isIPv6(address)) { - throw new Exception("Invalid address: " + address); - } - return InetAddress.getByName(address).getCanonicalHostName(); - } - - public static T getOrDefault(Map map, String key, T defaultValue) { - return map.containsKey(key) ? (T) map.get(key) : defaultValue; - } - - @Nullable - public static byte[] readAllBytes(@Nullable InputStream inputStream) { - if (inputStream == null) { - return null; - } - - final int bufLen = 4 * 0x400; // 4KB - byte[] buf = new byte[bufLen]; - int readLen; - IOException exception = null; - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - byte[] data = null; - - try { - while ((readLen = inputStream.read(buf, 0, bufLen)) != -1) - outputStream.write(buf, 0, readLen); - - data = outputStream.toByteArray(); - } catch (IOException e) { - exception = e; - } finally { - try { - inputStream.close(); - } catch (IOException e) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && exception != null) { - exception.addSuppressed(e); - } - } - try { - outputStream.close(); - } catch (IOException e) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && exception != null) { - exception.addSuppressed(e); - } - } - } - return data; - } - - @Nullable - public static Object invokeMethodIfExists(final O o, final String methodName, Object... args) { - Method[] methods = o.getClass().getMethods(); - for (Method method : methods) { - if (method.getName().equals(methodName)) { - try { - return method.invoke(o, args); - } catch (IllegalAccessException e) { - return null; - } catch (InvocationTargetException e) { - return null; - } - } - } - return null; - } - - public static Drawable drawableFromBytes(Context context, byte[] data) { - return new BitmapDrawable(context.getResources(), BitmapFactory.decodeByteArray(data, 0, data.length)); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/WebViewFeatureManager.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/WebViewFeatureManager.java deleted file mode 100755 index f72c03c0f9..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/WebViewFeatureManager.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class WebViewFeatureManager extends ChannelDelegateImpl { - protected static final String LOG_TAG = "WebViewFeatureManager"; - public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webviewfeature"; - - @Nullable - public InAppWebViewFlutterPlugin plugin; - - public WebViewFeatureManager(@NonNull final InAppWebViewFlutterPlugin plugin) { - super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME)); - this.plugin = plugin; - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - switch (call.method) { - case "isFeatureSupported": - String feature = (String) call.argument("feature"); - result.success(WebViewFeature.isFeatureSupported(feature)); - break; - case "isStartupFeatureSupported": - if (plugin != null && plugin.activity != null) { - String startupFeature = (String) call.argument("startupFeature"); - result.success(WebViewFeature.isStartupFeatureSupported(plugin.activity, startupFeature)); - } - break; - default: - result.notImplemented(); - } - } - - @Override - public void dispose() { - super.dispose(); - plugin = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ActionBroadcastReceiver.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ActionBroadcastReceiver.java deleted file mode 100644 index cf160c718e..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ActionBroadcastReceiver.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; - -import androidx.browser.customtabs.CustomTabsIntent; - -public class ActionBroadcastReceiver extends BroadcastReceiver { - protected static final String LOG_TAG = "ActionBroadcastReceiver"; - public static final String KEY_ACTION_ID = "com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ACTION_ID"; - public static final String KEY_ACTION_VIEW_ID = "com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ACTION_VIEW_ID"; - public static final String KEY_ACTION_MANAGER_ID = "com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ACTION_MANAGER_ID"; - public static final String KEY_URL_TITLE = "android.intent.extra.SUBJECT"; - - @Override - public void onReceive(Context context, Intent intent) { - int clickedId = intent.getIntExtra(CustomTabsIntent.EXTRA_REMOTEVIEWS_CLICKED_ID, -1); - String url = intent.getDataString(); - if (url != null) { - Bundle b = intent.getExtras(); - String viewId = b.getString(KEY_ACTION_VIEW_ID); - String managerId = b.getString(KEY_ACTION_MANAGER_ID); - - if (managerId != null) { - ChromeSafariBrowserManager chromeSafariBrowserManager = ChromeSafariBrowserManager.shared.get(managerId); - if (chromeSafariBrowserManager != null) { - if (clickedId == -1) { - int id = b.getInt(KEY_ACTION_ID); - String title = b.getString(KEY_URL_TITLE); - - ChromeCustomTabsActivity browser = chromeSafariBrowserManager.browsers.get(viewId); - if (browser != null && browser.channelDelegate != null) { - browser.channelDelegate.onItemActionPerform(id, url, title); - } - } else { - ChromeCustomTabsActivity browser = chromeSafariBrowserManager.browsers.get(viewId); - if (browser != null && browser.channelDelegate != null) { - browser.channelDelegate.onSecondaryItemActionPerform(browser.getResources().getResourceName(clickedId), url); - } - } - } - } - } - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsActivity.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsActivity.java deleted file mode 100755 index aae335ebba..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsActivity.java +++ /dev/null @@ -1,472 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs; - -import android.app.Activity; -import android.app.PendingIntent; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Color; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.util.Log; -import android.widget.RemoteViews; - -import androidx.annotation.CallSuper; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.browser.customtabs.CustomTabColorSchemeParams; -import androidx.browser.customtabs.CustomTabsCallback; -import androidx.browser.customtabs.CustomTabsIntent; -import androidx.browser.customtabs.CustomTabsService; -import androidx.browser.customtabs.CustomTabsSession; -import androidx.browser.customtabs.EngagementSignalsCallback; - -import com.pichillilorenzo.flutter_inappwebview_android.R; -import com.pichillilorenzo.flutter_inappwebview_android.types.AndroidResource; -import com.pichillilorenzo.flutter_inappwebview_android.types.CustomTabsActionButton; -import com.pichillilorenzo.flutter_inappwebview_android.types.CustomTabsMenuItem; -import com.pichillilorenzo.flutter_inappwebview_android.types.CustomTabsSecondaryToolbar; -import com.pichillilorenzo.flutter_inappwebview_android.types.Disposable; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.flutter.plugin.common.MethodChannel; - -public class ChromeCustomTabsActivity extends Activity implements Disposable { - protected static final String LOG_TAG = "CustomTabsActivity"; - public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_chromesafaribrowser_"; - - public String id; - @Nullable - public CustomTabsIntent.Builder builder; - public ChromeCustomTabsSettings customSettings = new ChromeCustomTabsSettings(); - public CustomTabActivityHelper customTabActivityHelper = new CustomTabActivityHelper(); - @Nullable - public CustomTabsSession customTabsSession; - public final static int CHROME_CUSTOM_TAB_REQUEST_CODE = 100; - public final static int NO_HISTORY_CHROME_CUSTOM_TAB_REQUEST_CODE = 101; - protected boolean onOpened = false; - protected boolean onCompletedInitialLoad = false; - protected boolean isBindSuccess = false; - @Nullable - public ChromeSafariBrowserManager manager; - @Nullable - public String initialUrl; - @Nullable - public List initialOtherLikelyURLs; - @Nullable - public Map initialHeaders; - @Nullable - public String initialReferrer; - public List menuItems = new ArrayList<>(); - @Nullable - public CustomTabsActionButton actionButton; - @Nullable - public CustomTabsSecondaryToolbar secondaryToolbar; - @Nullable - public ChromeCustomTabsChannelDelegate channelDelegate; - - @CallSuper - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.chrome_custom_tabs_layout); - - Bundle b = getIntent().getExtras(); - if (b == null) { - if (savedInstanceState != null) { - close(); - } - return; - } - - id = b.getString("id"); - - String managerId = b.getString("managerId"); - manager = ChromeSafariBrowserManager.shared.get(managerId); - if (manager == null || manager.plugin == null || manager.plugin.messenger == null) { - if (savedInstanceState != null) { - close(); - } - return; - } - - manager.browsers.put(id, this); - - MethodChannel channel = new MethodChannel(manager.plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id); - channelDelegate = new ChromeCustomTabsChannelDelegate(this, channel); - - initialUrl = b.getString("url"); - initialHeaders = (Map) b.getSerializable("headers"); - initialReferrer = b.getString("referrer"); - initialOtherLikelyURLs = b.getStringArrayList("otherLikelyURLs"); - - customSettings = new ChromeCustomTabsSettings(); - customSettings.parse((HashMap) b.getSerializable("settings")); - actionButton = CustomTabsActionButton.fromMap((Map) b.getSerializable("actionButton")); - secondaryToolbar = CustomTabsSecondaryToolbar.fromMap((Map) b.getSerializable("secondaryToolbar")); - List> menuItemList = (List>) b.getSerializable("menuItemList"); - for (Map menuItem : menuItemList) { - menuItems.add(CustomTabsMenuItem.fromMap(menuItem)); - } - - if (customSettings.noHistory && manager.plugin.noHistoryCustomTabsActivityCallbacks != null) { - manager.plugin.noHistoryCustomTabsActivityCallbacks.noHistoryBrowserIDs.put(id, id); - } - - final ChromeCustomTabsActivity chromeCustomTabsActivity = this; - - customTabActivityHelper.setConnectionCallback(new CustomTabActivityHelper.ConnectionCallback() { - @Override - public void onCustomTabsConnected() { - customTabsConnected(); - if (channelDelegate != null) { - channelDelegate.onServiceConnected(); - } - } - - @Override - public void onCustomTabsDisconnected() { - chromeCustomTabsActivity.close(); - dispose(); - } - }); - - customTabActivityHelper.setCustomTabsCallback(new CustomTabsCallback() { - @Override - public void onNavigationEvent(int navigationEvent, Bundle extras) { - if (navigationEvent == TAB_SHOWN && !onOpened) { - onOpened = true; - if (channelDelegate != null) { - channelDelegate.onOpened(); - } - } - - if (navigationEvent == NAVIGATION_FINISHED && !onCompletedInitialLoad) { - onCompletedInitialLoad = true; - if (channelDelegate != null) { - channelDelegate.onCompletedInitialLoad(); - } - } - - if (channelDelegate != null) { - channelDelegate.onNavigationEvent(navigationEvent); - } - } - - @Override - public void extraCallback(@NonNull String callbackName, Bundle args) { - } - - @Override - public void onMessageChannelReady(Bundle extras) { - if (channelDelegate != null) { - channelDelegate.onMessageChannelReady(); - } - } - - @Override - public void onPostMessage(@NonNull String message, Bundle extras) { - if (channelDelegate != null) { - channelDelegate.onPostMessage(message); - } - } - - @Override - public void onRelationshipValidationResult(@CustomTabsService.Relation int relation, - @NonNull Uri requestedOrigin, - boolean result, Bundle extras) { - if (channelDelegate != null) { - channelDelegate.onRelationshipValidationResult(relation, requestedOrigin, result); - } - } - }); - } - - public void launchUrl(@NonNull String url, - @Nullable Map headers, - @Nullable String referrer, - @Nullable List otherLikelyURLs) { - launchUrlWithSession(customTabsSession, url, headers, referrer, otherLikelyURLs); - } - - public void launchUrlWithSession(@Nullable CustomTabsSession session, - @NonNull String url, - @Nullable Map headers, - @Nullable String referrer, - @Nullable List otherLikelyURLs) { - mayLaunchUrl(url, otherLikelyURLs); - builder = new CustomTabsIntent.Builder(session); - prepareCustomTabs(); - - CustomTabsIntent customTabsIntent = builder.build(); - prepareCustomTabsIntent(customTabsIntent); - - CustomTabActivityHelper.openCustomTab(this, customTabsIntent, Uri.parse(url), headers, - referrer != null ? Uri.parse(referrer) : null, CHROME_CUSTOM_TAB_REQUEST_CODE); - } - - public boolean mayLaunchUrl(@Nullable String url, @Nullable List otherLikelyURLs) { - Uri uri = url != null ? Uri.parse(url) : null; - - List bundleOtherLikelyURLs = new ArrayList<>(); - if (otherLikelyURLs != null) { - Bundle bundleOtherLikelyURL = new Bundle(); - for (String otherLikelyURL : otherLikelyURLs) { - bundleOtherLikelyURL.putString(CustomTabsService.KEY_URL, otherLikelyURL); - } - } - return customTabActivityHelper.mayLaunchUrl(uri, null, bundleOtherLikelyURLs); - } - - @CallSuper - public void customTabsConnected() { - customTabsSession = customTabActivityHelper.getSession(); - - if (customTabsSession != null) { - try { - Bundle bundle = new Bundle(); - if (customTabsSession.isEngagementSignalsApiAvailable(bundle)) { - customTabsSession.setEngagementSignalsCallback(new EngagementSignalsCallback() { - @Override - public void onVerticalScrollEvent(boolean isDirectionUp, @NonNull Bundle extras) { - if (channelDelegate != null) { - channelDelegate.onVerticalScrollEvent(isDirectionUp); - } - } - - @Override - public void onGreatestScrollPercentageIncreased(int scrollPercentage, @NonNull Bundle extras) { - if (channelDelegate != null) { - channelDelegate.onGreatestScrollPercentageIncreased(scrollPercentage); - } - } - - @Override - public void onSessionEnded(boolean didUserInteract, @NonNull Bundle extras) { - if (channelDelegate != null) { - channelDelegate.onSessionEnded(didUserInteract); - } - } - }, bundle); - } - } catch (Throwable e) { - Log.d(LOG_TAG, "Custom Tabs Engagement Signals API not supported", e); - } - } - - // avoid webpage reopen if isBindSuccess is false: onServiceConnected->launchUrl - if (isBindSuccess && initialUrl != null) { - launchUrl(initialUrl, initialHeaders, initialReferrer, initialOtherLikelyURLs); - } - } - - private void prepareCustomTabs() { - if (builder == null) { - return; - } - - if (customSettings.addDefaultShareMenuItem != null) { - builder.setShareState(customSettings.addDefaultShareMenuItem ? - CustomTabsIntent.SHARE_STATE_ON : CustomTabsIntent.SHARE_STATE_OFF); - } else { - builder.setShareState(customSettings.shareState); - } - - CustomTabColorSchemeParams.Builder defaultColorSchemeBuilder = new CustomTabColorSchemeParams.Builder(); - if (customSettings.toolbarBackgroundColor != null && !customSettings.toolbarBackgroundColor.isEmpty()) { - defaultColorSchemeBuilder.setToolbarColor(Color.parseColor(customSettings.toolbarBackgroundColor)); - } - if (customSettings.navigationBarColor != null && !customSettings.navigationBarColor.isEmpty()) { - defaultColorSchemeBuilder.setNavigationBarColor(Color.parseColor(customSettings.navigationBarColor)); - } - if (customSettings.navigationBarDividerColor != null && !customSettings.navigationBarDividerColor.isEmpty()) { - defaultColorSchemeBuilder.setNavigationBarDividerColor(Color.parseColor(customSettings.navigationBarDividerColor)); - } - if (customSettings.secondaryToolbarColor != null && !customSettings.secondaryToolbarColor.isEmpty()) { - defaultColorSchemeBuilder.setSecondaryToolbarColor(Color.parseColor(customSettings.secondaryToolbarColor)); - } - builder.setDefaultColorSchemeParams(defaultColorSchemeBuilder.build()); - - builder.setShowTitle(customSettings.showTitle); - builder.setUrlBarHidingEnabled(customSettings.enableUrlBarHiding); - builder.setInstantAppsEnabled(customSettings.instantAppsEnabled); - if (customSettings.startAnimations.size() == 2) { - builder.setStartAnimations(this, - customSettings.startAnimations.get(0).getIdentifier(this), - customSettings.startAnimations.get(1).getIdentifier(this)); - } - if (customSettings.exitAnimations.size() == 2) { - builder.setExitAnimations(this, - customSettings.exitAnimations.get(0).getIdentifier(this), - customSettings.exitAnimations.get(1).getIdentifier(this)); - } - - for (CustomTabsMenuItem menuItem : menuItems) { - builder.addMenuItem(menuItem.getLabel(), - createPendingIntent(menuItem.getId())); - } - - if (actionButton != null) { - byte[] data = actionButton.getIcon(); - BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); - bitmapOptions.inMutable = true; - Bitmap bmp = BitmapFactory.decodeByteArray( - data, 0, data.length, bitmapOptions - ); - builder.setActionButton(bmp, actionButton.getDescription(), - createPendingIntent(actionButton.getId()), - actionButton.isShouldTint()); - } - - if (secondaryToolbar != null) { - AndroidResource layout = secondaryToolbar.getLayout(); - RemoteViews remoteViews = new RemoteViews(layout.getDefPackage(), layout.getIdentifier(this)); - int[] clickableIDs = new int[secondaryToolbar.getClickableIDs().size()]; - for (int i = 0, length = secondaryToolbar.getClickableIDs().size(); i < length; i++) { - AndroidResource clickableID = secondaryToolbar.getClickableIDs().get(i); - clickableIDs[i] = clickableID.getIdentifier(this); - } - builder.setSecondaryToolbarViews(remoteViews, clickableIDs, getSecondaryToolbarOnClickPendingIntent()); - } - } - - public PendingIntent getSecondaryToolbarOnClickPendingIntent() { - Intent broadcastIntent = new Intent(this, ActionBroadcastReceiver.class); - - Bundle extras = new Bundle(); - extras.putString(ActionBroadcastReceiver.KEY_ACTION_VIEW_ID, id); - extras.putString(ActionBroadcastReceiver.KEY_ACTION_MANAGER_ID, manager != null ? manager.id : null); - broadcastIntent.putExtras(extras); - - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - return PendingIntent.getBroadcast( - this, 0, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); - } else { - return PendingIntent.getBroadcast( - this, 0, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT); - } - } - - private void prepareCustomTabsIntent(CustomTabsIntent customTabsIntent) { - if (customSettings.packageName != null) - customTabsIntent.intent.setPackage(customSettings.packageName); - else - customTabsIntent.intent.setPackage(CustomTabsHelper.getPackageNameToUse(this)); - - if (customSettings.keepAliveEnabled) - CustomTabsHelper.addKeepAliveExtra(this, customTabsIntent.intent); - - if (customSettings.alwaysUseBrowserUI) - CustomTabsIntent.setAlwaysUseBrowserUI(customTabsIntent.intent); - } - - public void updateActionButton(@NonNull byte[] icon, @NonNull String description) { - if (customTabsSession == null || actionButton == null) { - return; - } - BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); - bitmapOptions.inMutable = true; - Bitmap bmp = BitmapFactory.decodeByteArray( - icon, 0, icon.length, bitmapOptions - ); - customTabsSession.setActionButton(bmp, description); - actionButton.setIcon(icon); - actionButton.setDescription(description); - } - - public void updateSecondaryToolbar(CustomTabsSecondaryToolbar secondaryToolbar) { - if (customTabsSession == null) { - return; - } - AndroidResource layout = secondaryToolbar.getLayout(); - RemoteViews remoteViews = new RemoteViews(layout.getDefPackage(), layout.getIdentifier(this)); - int[] clickableIDs = new int[secondaryToolbar.getClickableIDs().size()]; - for (int i = 0, length = secondaryToolbar.getClickableIDs().size(); i < length; i++) { - AndroidResource clickableID = secondaryToolbar.getClickableIDs().get(i); - clickableIDs[i] = clickableID.getIdentifier(this); - } - customTabsSession.setSecondaryToolbarViews(remoteViews, clickableIDs, getSecondaryToolbarOnClickPendingIntent()); - this.secondaryToolbar = secondaryToolbar; - } - - @Override - protected void onStart() { - super.onStart(); - isBindSuccess = customTabActivityHelper.bindCustomTabsService(this); - - if (!isBindSuccess && initialUrl != null) { - // chrome process not running, start tab directly - launchUrlWithSession(null, initialUrl, initialHeaders, initialReferrer, initialOtherLikelyURLs); - } - } - - @Override - protected void onStop() { - super.onStop(); - customTabActivityHelper.unbindCustomTabsService(this); - isBindSuccess = false; - } - - @Override - public void onDestroy() { - super.onDestroy(); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == CHROME_CUSTOM_TAB_REQUEST_CODE) { - close(); - dispose(); - } - } - - private PendingIntent createPendingIntent(int actionSourceId) { - Intent actionIntent = new Intent(this, ActionBroadcastReceiver.class); - - Bundle extras = new Bundle(); - extras.putInt(ActionBroadcastReceiver.KEY_ACTION_ID, actionSourceId); - extras.putString(ActionBroadcastReceiver.KEY_ACTION_VIEW_ID, id); - extras.putString(ActionBroadcastReceiver.KEY_ACTION_MANAGER_ID, manager != null ? manager.id : null); - actionIntent.putExtras(extras); - - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - return PendingIntent.getBroadcast( - this, actionSourceId, actionIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); - } else { - return PendingIntent.getBroadcast( - this, actionSourceId, actionIntent, PendingIntent.FLAG_UPDATE_CURRENT); - } - } - - @Override - public void dispose() { - onStop(); - onDestroy(); - if (channelDelegate != null) { - channelDelegate.dispose(); - channelDelegate = null; - } - if (manager != null) { - if (manager.browsers.containsKey(id)) { - manager.browsers.put(id, null); - } - } - manager = null; - } - - public void close() { - onStop(); - onDestroy(); - customTabsSession = null; - finish(); - if (channelDelegate != null) { - channelDelegate.onClosed(); - } - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsActivitySingleInstance.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsActivitySingleInstance.java deleted file mode 100755 index 73d6de79ea..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsActivitySingleInstance.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs; - -public class ChromeCustomTabsActivitySingleInstance extends ChromeCustomTabsActivity { - - protected static final String LOG_TAG = "ChromeCustomTabsActivitySingleInstance"; - -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsChannelDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsChannelDelegate.java deleted file mode 100644 index 703a337f3b..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsChannelDelegate.java +++ /dev/null @@ -1,251 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs; - -import android.app.Activity; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.browser.customtabs.CustomTabsService; - -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; -import com.pichillilorenzo.flutter_inappwebview_android.types.CustomTabsSecondaryToolbar; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class ChromeCustomTabsChannelDelegate extends ChannelDelegateImpl { - @Nullable - private ChromeCustomTabsActivity chromeCustomTabsActivity; - - public ChromeCustomTabsChannelDelegate(@NonNull ChromeCustomTabsActivity chromeCustomTabsActivity, @NonNull MethodChannel channel) { - super(channel); - this.chromeCustomTabsActivity = chromeCustomTabsActivity; - } - - @Override - public void onMethodCall(@NonNull final MethodCall call, @NonNull final MethodChannel.Result result) { - switch (call.method) { - case "launchUrl": - if (chromeCustomTabsActivity != null) { - String url = (String) call.argument("url"); - if (url != null) { - Map headers = (Map) call.argument("headers"); - String referrer = (String) call.argument("referrer"); - List otherLikelyURLs = (List) call.argument("otherLikelyURLs"); - chromeCustomTabsActivity.launchUrl(url, headers, referrer, otherLikelyURLs); - result.success(true); - } else { - result.success(false); - } - } else { - result.success(false); - } - break; - case "mayLaunchUrl": - if (chromeCustomTabsActivity != null) { - String url = (String) call.argument("url"); - List otherLikelyURLs = (List) call.argument("otherLikelyURLs"); - result.success(chromeCustomTabsActivity.mayLaunchUrl(url, otherLikelyURLs)); - } else { - result.success(false); - } - break; - case "updateActionButton": - if (chromeCustomTabsActivity != null) { - byte[] icon = (byte[]) call.argument("icon"); - String description = (String) call.argument("description"); - chromeCustomTabsActivity.updateActionButton(icon, description); - result.success(true); - } else { - result.success(false); - } - break; - case "validateRelationship": - if (chromeCustomTabsActivity != null && chromeCustomTabsActivity.customTabsSession != null) { - Integer relation = (Integer) call.argument("relation"); - String origin = (String) call.argument("origin"); - result.success(chromeCustomTabsActivity.customTabsSession.validateRelationship(relation, Uri.parse(origin), null)); - } else { - result.success(false); - } - break; - case "updateSecondaryToolbar": - if (chromeCustomTabsActivity != null) { - CustomTabsSecondaryToolbar secondaryToolbar = CustomTabsSecondaryToolbar.fromMap((Map) call.argument("secondaryToolbar")); - chromeCustomTabsActivity.updateSecondaryToolbar(secondaryToolbar); - result.success(true); - } else { - result.success(false); - } - break; - case "requestPostMessageChannel": - if (chromeCustomTabsActivity != null && chromeCustomTabsActivity.customTabsSession != null) { - String sourceOrigin = (String) call.argument("sourceOrigin"); - String targetOrigin = (String) call.argument("targetOrigin"); - result.success(chromeCustomTabsActivity.customTabsSession.requestPostMessageChannel(Uri.parse(sourceOrigin), - targetOrigin != null ? Uri.parse(targetOrigin) : null, new Bundle())); - } else { - result.success(false); - } - break; - case "postMessage": - if (chromeCustomTabsActivity != null && chromeCustomTabsActivity.customTabsSession != null) { - String message = (String) call.argument("message"); - result.success(chromeCustomTabsActivity.customTabsSession.postMessage(message, new Bundle())); - } else { - result.success(CustomTabsService.RESULT_FAILURE_MESSAGING_ERROR); - } - break; - case "isEngagementSignalsApiAvailable": - if (chromeCustomTabsActivity != null && chromeCustomTabsActivity.customTabsSession != null) { - try { - result.success(chromeCustomTabsActivity.customTabsSession.isEngagementSignalsApiAvailable(new Bundle())); - } catch (Throwable e) { - result.success(false); - } - } else { - result.success(false); - } - break; - case "close": - if (chromeCustomTabsActivity != null) { - chromeCustomTabsActivity.onStop(); - chromeCustomTabsActivity.onDestroy(); - chromeCustomTabsActivity.close(); - - if (chromeCustomTabsActivity.manager != null && chromeCustomTabsActivity.manager.plugin != null && - chromeCustomTabsActivity.manager.plugin.activity != null) { - Activity activity = chromeCustomTabsActivity.manager.plugin.activity; - // https://stackoverflow.com/a/41596629/4637638 - Intent myIntent = new Intent(activity, activity.getClass()); - myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - myIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - activity.startActivity(myIntent); - } - chromeCustomTabsActivity.dispose(); - result.success(true); - } else { - result.success(false); - } - break; - default: - result.notImplemented(); - } - } - - public void onServiceConnected() { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onServiceConnected", obj); - } - - public void onOpened() { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onOpened", obj); - } - - public void onCompletedInitialLoad() { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onCompletedInitialLoad", obj); - } - - public void onNavigationEvent(int navigationEvent) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("navigationEvent", navigationEvent); - channel.invokeMethod("onNavigationEvent", obj); - } - - public void onClosed() { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onClosed", obj); - } - - public void onItemActionPerform(int id, String url, String title) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("id", id); - obj.put("url", url); - obj.put("title", title); - channel.invokeMethod("onItemActionPerform", obj); - } - - public void onSecondaryItemActionPerform(String name, String url) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("name", name); - obj.put("url", url); - channel.invokeMethod("onSecondaryItemActionPerform", obj); - } - - public void onRelationshipValidationResult(int relation, @NonNull Uri requestedOrigin, boolean result) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("relation", relation); - obj.put("requestedOrigin", requestedOrigin.toString()); - obj.put("result", result); - channel.invokeMethod("onRelationshipValidationResult", obj); - } - - public void onMessageChannelReady() { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onMessageChannelReady", obj); - } - - public void onPostMessage(@NonNull String message) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("message", message); - channel.invokeMethod("onPostMessage", obj); - } - - public void onVerticalScrollEvent(boolean isDirectionUp) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("isDirectionUp", isDirectionUp); - channel.invokeMethod("onVerticalScrollEvent", obj); - } - - public void onGreatestScrollPercentageIncreased(int scrollPercentage) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("scrollPercentage", scrollPercentage); - channel.invokeMethod("onGreatestScrollPercentageIncreased", obj); - } - - public void onSessionEnded(boolean didUserInteract) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("didUserInteract", didUserInteract); - channel.invokeMethod("onSessionEnded", obj); - } - - @Override - public void dispose() { - super.dispose(); - chromeCustomTabsActivity = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsSettings.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsSettings.java deleted file mode 100755 index b512cf48bd..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsSettings.java +++ /dev/null @@ -1,187 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs; - -import android.content.Intent; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.browser.customtabs.CustomTabsIntent; -import androidx.browser.trusted.ScreenOrientation; -import androidx.browser.trusted.TrustedWebActivityDisplayMode; - -import com.pichillilorenzo.flutter_inappwebview_android.ISettings; -import com.pichillilorenzo.flutter_inappwebview_android.types.AndroidResource; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ChromeCustomTabsSettings implements ISettings { - - final static String LOG_TAG = "ChromeCustomTabsSettings"; - - @Deprecated - public Boolean addDefaultShareMenuItem; - public Integer shareState = CustomTabsIntent.SHARE_STATE_DEFAULT; - public Boolean showTitle = true; - @Nullable - public String toolbarBackgroundColor; - @Nullable - public String navigationBarColor; - @Nullable - public String navigationBarDividerColor; - @Nullable - public String secondaryToolbarColor; - public Boolean enableUrlBarHiding = false; - public Boolean instantAppsEnabled = false; - public String packageName; - public Boolean keepAliveEnabled = false; - public Boolean isSingleInstance = false; - public Boolean noHistory = false; - public Boolean isTrustedWebActivity = false; - public List additionalTrustedOrigins = new ArrayList<>(); - public TrustedWebActivityDisplayMode displayMode = null; - public Integer screenOrientation = ScreenOrientation.DEFAULT; - public List startAnimations = new ArrayList<>(); - public List exitAnimations = new ArrayList<>(); - public Boolean alwaysUseBrowserUI = false; - - @NonNull - @Override - public ChromeCustomTabsSettings parse(@NonNull Map options) { - for (Map.Entry pair : options.entrySet()) { - String key = pair.getKey(); - Object value = pair.getValue(); - if (value == null) { - continue; - } - - switch (key) { - case "addDefaultShareMenuItem": - addDefaultShareMenuItem = (Boolean) value; - break; - case "shareState": - shareState = (Integer) value; - break; - case "showTitle": - showTitle = (Boolean) value; - break; - case "toolbarBackgroundColor": - toolbarBackgroundColor = (String) value; - break; - case "navigationBarColor": - navigationBarColor = (String) value; - break; - case "navigationBarDividerColor": - navigationBarDividerColor = (String) value; - break; - case "secondaryToolbarColor": - secondaryToolbarColor = (String) value; - break; - case "enableUrlBarHiding": - enableUrlBarHiding = (Boolean) value; - break; - case "instantAppsEnabled": - instantAppsEnabled = (Boolean) value; - break; - case "packageName": - packageName = (String) value; - break; - case "keepAliveEnabled": - keepAliveEnabled = (Boolean) value; - break; - case "isSingleInstance": - isSingleInstance = (Boolean) value; - break; - case "noHistory": - noHistory = (Boolean) value; - break; - case "isTrustedWebActivity": - isTrustedWebActivity = (Boolean) value; - break; - case "additionalTrustedOrigins": - additionalTrustedOrigins = (List) value; - break; - case "displayMode": - Map displayModeMap = (Map) value; - String displayModeType = (String) displayModeMap.get("type"); - if (displayModeType != null) { - switch (displayModeType) { - case "IMMERSIVE_MODE": - boolean isSticky = (boolean) displayModeMap.get("isSticky"); - int layoutInDisplayCutoutMode = (int) displayModeMap.get("displayCutoutMode"); - displayMode = new TrustedWebActivityDisplayMode.ImmersiveMode(isSticky, layoutInDisplayCutoutMode); - break; - case "DEFAULT_MODE": - displayMode = new TrustedWebActivityDisplayMode.DefaultMode(); - break; - } - } - break; - case "screenOrientation": - screenOrientation = (Integer) value; - break; - case "startAnimations": - List> startAnimationsList = (List>) value; - for (Map startAnimation : startAnimationsList) { - AndroidResource androidResource = AndroidResource.fromMap(startAnimation); - if (androidResource != null) { - startAnimations.add(AndroidResource.fromMap(startAnimation)); - } - } - break; - case "exitAnimations": - List> exitAnimationsList = (List>) value; - for (Map exitAnimation : exitAnimationsList) { - AndroidResource androidResource = AndroidResource.fromMap(exitAnimation); - if (androidResource != null) { - exitAnimations.add(AndroidResource.fromMap(exitAnimation)); - } - } - break; - case "alwaysUseBrowserUI": - alwaysUseBrowserUI = (Boolean) value; - break; - } - } - - return this; - } - - @NonNull - @Override - public Map toMap() { - Map options = new HashMap<>(); - options.put("addDefaultShareMenuItem", addDefaultShareMenuItem); - options.put("showTitle", showTitle); - options.put("toolbarBackgroundColor", toolbarBackgroundColor); - options.put("navigationBarColor", navigationBarColor); - options.put("navigationBarDividerColor", navigationBarDividerColor); - options.put("secondaryToolbarColor", secondaryToolbarColor); - options.put("enableUrlBarHiding", enableUrlBarHiding); - options.put("instantAppsEnabled", instantAppsEnabled); - options.put("packageName", packageName); - options.put("keepAliveEnabled", keepAliveEnabled); - options.put("isSingleInstance", isSingleInstance); - options.put("noHistory", noHistory); - options.put("isTrustedWebActivity", isTrustedWebActivity); - options.put("additionalTrustedOrigins", additionalTrustedOrigins); - options.put("screenOrientation", screenOrientation); - options.put("alwaysUseBrowserUI", alwaysUseBrowserUI); - return options; - } - - @NonNull - @Override - public Map getRealSettings(@NonNull ChromeCustomTabsActivity chromeCustomTabsActivity) { - Map realOptions = toMap(); - if (chromeCustomTabsActivity != null) { - Intent intent = chromeCustomTabsActivity.getIntent(); - if (intent != null) { - realOptions.put("packageName", intent.getPackage()); - realOptions.put("keepAliveEnabled", intent.hasExtra(CustomTabsHelper.EXTRA_CUSTOM_TABS_KEEP_ALIVE)); - } - } - return realOptions; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeSafariBrowserManager.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeSafariBrowserManager.java deleted file mode 100755 index 1fab2799f3..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeSafariBrowserManager.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; - -import androidx.annotation.Nullable; -import androidx.browser.customtabs.CustomTabsClient; -import androidx.browser.customtabs.CustomTabsIntent; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.Util; -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class ChromeSafariBrowserManager extends ChannelDelegateImpl { - protected static final String LOG_TAG = "ChromeBrowserManager"; - public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_chromesafaribrowser"; - - @Nullable - public InAppWebViewFlutterPlugin plugin; - public String id; - public static final Map shared = new HashMap<>(); - public final Map browsers = new HashMap<>(); - - public ChromeSafariBrowserManager(final InAppWebViewFlutterPlugin plugin) { - super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME)); - this.id = UUID.randomUUID().toString(); - this.plugin = plugin; - shared.put(this.id, this); - } - - @Override - public void onMethodCall(final MethodCall call, final MethodChannel.Result result) { - final String viewId = (String) call.argument("id"); - - switch (call.method) { - case "open": - if (plugin != null && plugin.activity != null) { - String url = (String) call.argument("url"); - HashMap headers = (HashMap) call.argument("headers"); - String referrer = (String) call.argument("referrer"); - ArrayList otherLikelyURLs = (ArrayList) call.argument("otherLikelyURLs"); - HashMap settings = (HashMap) call.argument("settings"); - HashMap actionButton = (HashMap) call.argument("actionButton"); - HashMap secondaryToolbar = (HashMap) call.argument("secondaryToolbar"); - List> menuItemList = (List>) call.argument("menuItemList"); - open(plugin.activity, viewId, url, headers, referrer, otherLikelyURLs, settings, actionButton, secondaryToolbar, menuItemList, result); - } else { - result.success(false); - } - break; - case "isAvailable": - if (plugin != null && plugin.activity != null) { - result.success(CustomTabActivityHelper.isAvailable(plugin.activity)); - } else { - result.success(false); - } - break; - case "getMaxToolbarItems": - result.success(CustomTabsIntent.getMaxToolbarItems()); - break; - case "getPackageName": - if (plugin != null && plugin.activity != null) { - ArrayList packages = (ArrayList) call.argument("packages"); - Boolean ignoreDefault = (Boolean) call.argument("ignoreDefault"); - result.success(CustomTabsClient.getPackageName(plugin.activity, packages, ignoreDefault)); - } else { - result.success(null); - } - break; - default: - result.notImplemented(); - } - } - - public void open(Activity activity, String viewId, @Nullable String url, @Nullable HashMap headers, - @Nullable String referrer, @Nullable ArrayList otherLikelyURLs, - HashMap settings, HashMap actionButton, - HashMap secondaryToolbar, - List> menuItemList, MethodChannel.Result result) { - - Intent intent = null; - Bundle extras = new Bundle(); - extras.putString("url", url); - extras.putString("id", viewId); - extras.putString("managerId", this.id); - extras.putSerializable("headers", headers); - extras.putString("referrer", referrer); - extras.putSerializable("otherLikelyURLs", otherLikelyURLs); - extras.putSerializable("settings", settings); - extras.putSerializable("actionButton", (Serializable) actionButton); - extras.putSerializable("secondaryToolbar", (Serializable) secondaryToolbar); - extras.putSerializable("menuItemList", (Serializable) menuItemList); - - Boolean isSingleInstance = Util.getOrDefault(settings, "isSingleInstance", false); - Boolean isTrustedWebActivity = Util.getOrDefault(settings, "isTrustedWebActivity", false); - if (CustomTabActivityHelper.isAvailable(activity)) { - intent = new Intent(activity, !isSingleInstance ? - (!isTrustedWebActivity ? ChromeCustomTabsActivity.class : TrustedWebActivity.class) : - (!isTrustedWebActivity ? ChromeCustomTabsActivitySingleInstance.class : TrustedWebActivitySingleInstance.class)); - intent.putExtras(extras); - Boolean noHistory = Util.getOrDefault(settings, "noHistory", false); - if (noHistory) { - intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - } - activity.startActivity(intent); - result.success(true); - return; - } - - result.error(LOG_TAG, "ChromeCustomTabs is not available!", null); - } - - @Override - public void dispose() { - super.dispose(); - Collection browserList = browsers.values(); - for (ChromeCustomTabsActivity browser : browserList) { - if (browser != null) { - browser.close(); - browser.dispose(); - } - } - browsers.clear(); - shared.remove(this.id); - plugin = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/CustomTabActivityHelper.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/CustomTabActivityHelper.java deleted file mode 100755 index 61d759c860..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/CustomTabActivityHelper.java +++ /dev/null @@ -1,177 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs; - -import android.app.Activity; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.provider.Browser; - -import androidx.annotation.Nullable; -import androidx.browser.customtabs.CustomTabsCallback; -import androidx.browser.customtabs.CustomTabsClient; -import androidx.browser.customtabs.CustomTabsIntent; -import androidx.browser.customtabs.CustomTabsServiceConnection; -import androidx.browser.customtabs.CustomTabsSession; -import androidx.browser.trusted.TrustedWebActivityIntent; - -import java.util.List; -import java.util.Map; - -/** - * This is a helper class to manage the connection to the Custom Tabs Service. - */ -public class CustomTabActivityHelper implements ServiceConnectionCallback { - private CustomTabsSession mCustomTabsSession; - private CustomTabsClient mClient; - private CustomTabsServiceConnection mConnection; - private ConnectionCallback mConnectionCallback; - private CustomTabsCallback mCustomTabsCallback; - - /** - * Opens the URL on a Custom Tab if possible. - * - * @param activity The host activity. - * @param intent a intent to be used if Custom Tabs is available. - * @param uri the Uri to be opened. - */ - public static void openCustomTab(Activity activity, - Intent intent, - Uri uri, - @Nullable Map headers, - @Nullable Uri referrer, - int requestCode) { - intent.setData(uri); - if (headers != null) { - Bundle bundleHeaders = new Bundle(); - for (Map.Entry header : headers.entrySet()) { - bundleHeaders.putString(header.getKey(), header.getValue()); - } - intent.putExtra(Browser.EXTRA_HEADERS, bundleHeaders); - } - if (referrer != null) { - intent.putExtra(Intent.EXTRA_REFERRER, referrer); - } - activity.startActivityForResult(intent, requestCode); - } - - public static void openCustomTab(Activity activity, - CustomTabsIntent customTabsIntent, - Uri uri, - @Nullable Map headers, - @Nullable Uri referrer, - int requestCode) { - CustomTabActivityHelper.openCustomTab(activity, customTabsIntent.intent, uri, - headers, referrer, requestCode); - } - - public static void openTrustedWebActivity(Activity activity, - TrustedWebActivityIntent trustedWebActivityIntent, - Uri uri, - @Nullable Map headers, - @Nullable Uri referrer, - int requestCode) { - CustomTabActivityHelper.openCustomTab(activity, trustedWebActivityIntent.getIntent(), uri, - headers, referrer, requestCode); - } - - - public static boolean isAvailable(Activity activity) { - return CustomTabsHelper.getPackageNameToUse(activity) != null; - } - - /** - * Unbinds the Activity from the Custom Tabs Service. - * @param activity the activity that is connected to the service. - */ - public void unbindCustomTabsService(Activity activity) { - if (mConnection == null) return; - activity.unbindService(mConnection); - mClient = null; - mCustomTabsSession = null; - mConnection = null; - } - - /** - * Creates or retrieves an exiting CustomTabsSession. - * - * @return a CustomTabsSession. - */ - @Nullable - public CustomTabsSession getSession() { - if (mClient == null) { - mCustomTabsSession = null; - } else if (mCustomTabsSession == null) { - mCustomTabsSession = mClient.newSession(mCustomTabsCallback); - } - return mCustomTabsSession; - } - - /** - * Register a Callback to be called when connected or disconnected from the Custom Tabs Service. - * @param connectionCallback - */ - public void setConnectionCallback(ConnectionCallback connectionCallback) { - this.mConnectionCallback = connectionCallback; - } - - public void setCustomTabsCallback(CustomTabsCallback customTabsCallback) { - this.mCustomTabsCallback = customTabsCallback; - } - - /** - * Binds the Activity to the Custom Tabs Service. - * @param activity the activity to be binded to the service. - */ - public boolean bindCustomTabsService(Activity activity) { - if (mClient != null) return true; - - String packageName = CustomTabsHelper.getPackageNameToUse(activity); - if (packageName == null) return false; - - mConnection = new ServiceConnection(this); - return CustomTabsClient.bindCustomTabsService(activity, packageName, mConnection); - } - - /** - * @see {@link CustomTabsSession#mayLaunchUrl(Uri, Bundle, List)}. - * @return true if call to mayLaunchUrl was accepted. - */ - public boolean mayLaunchUrl(Uri uri, Bundle extras, List otherLikelyBundles) { - if (mClient == null) return false; - - CustomTabsSession session = getSession(); - if (session == null) return false; - - return session.mayLaunchUrl(uri, extras, otherLikelyBundles); - } - - @Override - public void onServiceConnected(CustomTabsClient client) { - mClient = client; - mClient.warmup(0L); - if (mConnectionCallback != null) mConnectionCallback.onCustomTabsConnected(); - } - - @Override - public void onServiceDisconnected() { - mClient = null; - mCustomTabsSession = null; - if (mConnectionCallback != null) mConnectionCallback.onCustomTabsDisconnected(); - } - - /** - * A Callback for when the service is connected or disconnected. Use those callbacks to - * handle UI changes when the service is connected or disconnected. - */ - public interface ConnectionCallback { - /** - * Called when the service is connected. - */ - void onCustomTabsConnected(); - - /** - * Called when the service is disconnected. - */ - void onCustomTabsDisconnected(); - } -} \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/CustomTabsHelper.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/CustomTabsHelper.java deleted file mode 100755 index 6e3a216b06..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/CustomTabsHelper.java +++ /dev/null @@ -1,134 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs; - -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.net.Uri; -import android.os.Build; -import android.text.TextUtils; -import android.util.Log; - -import androidx.browser.customtabs.CustomTabsService; - -import java.util.ArrayList; -import java.util.List; - -/** - * Helper class for Custom Tabs. - */ -public class CustomTabsHelper { - protected static final String TAG = "CustomTabsHelper"; - static final String STABLE_PACKAGE = "com.android.chrome"; - static final String BETA_PACKAGE = "com.chrome.beta"; - static final String DEV_PACKAGE = "com.chrome.dev"; - static final String LOCAL_PACKAGE = "com.google.android.apps.chrome"; - protected static final String EXTRA_CUSTOM_TABS_KEEP_ALIVE = - "android.support.customtabs.extra.KEEP_ALIVE"; - - private static String sPackageNameToUse; - - private CustomTabsHelper() {} - - public static void addKeepAliveExtra(Context context, Intent intent) { - Intent keepAliveIntent = new Intent().setClassName( - context.getPackageName(), KeepAliveService.class.getCanonicalName()); - intent.putExtra(EXTRA_CUSTOM_TABS_KEEP_ALIVE, keepAliveIntent); - } - - /** - * Goes through all apps that handle VIEW intents and have a warmup service. Picks - * the one chosen by the user if there is one, otherwise makes a best effort to return a - * valid package name. - * - * This is not threadsafe. - * - * @param context {@link Context} to use for accessing {@link PackageManager}. - * @return The package name recommended to use for connecting to custom tabs related components. - */ - public static String getPackageNameToUse(Context context) { - if (sPackageNameToUse != null) return sPackageNameToUse; - - PackageManager pm = context.getPackageManager(); - // Get default VIEW intent handler. - Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com")); - activityIntent.addCategory(Intent.CATEGORY_BROWSABLE); - ResolveInfo defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0); - String defaultViewHandlerPackageName = null; - if (defaultViewHandlerInfo != null) { - defaultViewHandlerPackageName = defaultViewHandlerInfo.activityInfo.packageName; - } - - // Get all apps that can handle VIEW intents. - int flags = 0; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - flags |= PackageManager.MATCH_ALL; - } - List resolvedActivityList = pm.queryIntentActivities(activityIntent, flags); - List packagesSupportingCustomTabs = new ArrayList<>(); - for (ResolveInfo info : resolvedActivityList) { - Intent serviceIntent = new Intent(); - serviceIntent.setAction(CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION); - serviceIntent.setPackage(info.activityInfo.packageName); - if (pm.resolveService(serviceIntent, 0) != null) { - packagesSupportingCustomTabs.add(info.activityInfo.packageName); - } - } - - // Now packagesSupportingCustomTabs contains all apps that can handle both VIEW intents - // and service calls. - if (packagesSupportingCustomTabs.isEmpty()) { - sPackageNameToUse = null; - } else if (packagesSupportingCustomTabs.size() == 1) { - sPackageNameToUse = packagesSupportingCustomTabs.get(0); - } else if (!TextUtils.isEmpty(defaultViewHandlerPackageName) - && !hasSpecializedHandlerIntents(context, activityIntent) - && packagesSupportingCustomTabs.contains(defaultViewHandlerPackageName)) { - sPackageNameToUse = defaultViewHandlerPackageName; - } else if (packagesSupportingCustomTabs.contains(STABLE_PACKAGE)) { - sPackageNameToUse = STABLE_PACKAGE; - } else if (packagesSupportingCustomTabs.contains(BETA_PACKAGE)) { - sPackageNameToUse = BETA_PACKAGE; - } else if (packagesSupportingCustomTabs.contains(DEV_PACKAGE)) { - sPackageNameToUse = DEV_PACKAGE; - } else if (packagesSupportingCustomTabs.contains(LOCAL_PACKAGE)) { - sPackageNameToUse = LOCAL_PACKAGE; - } - return sPackageNameToUse; - } - - /** - * Used to check whether there is a specialized handler for a given intent. - * @param intent The intent to check with. - * @return Whether there is a specialized handler for the given intent. - */ - private static boolean hasSpecializedHandlerIntents(Context context, Intent intent) { - try { - PackageManager pm = context.getPackageManager(); - List handlers = pm.queryIntentActivities( - intent, - PackageManager.GET_RESOLVED_FILTER); - if (handlers == null || handlers.size() == 0) { - return false; - } - for (ResolveInfo resolveInfo : handlers) { - IntentFilter filter = resolveInfo.filter; - if (filter == null) continue; - if (filter.countDataAuthorities() == 0 || filter.countDataPaths() == 0) continue; - if (resolveInfo.activityInfo == null) continue; - return true; - } - } catch (RuntimeException e) { - Log.e(TAG, "Runtime exception while getting specialized handlers"); - } - return false; - } - - /** - * @return All possible chrome package names that provide custom tabs feature. - */ - public static String[] getPackages() { - return new String[]{"", STABLE_PACKAGE, BETA_PACKAGE, DEV_PACKAGE, LOCAL_PACKAGE}; - } -} \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/KeepAliveService.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/KeepAliveService.java deleted file mode 100755 index 87dc3af868..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/KeepAliveService.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs; - -import android.app.Service; -import android.content.Intent; -import android.os.Binder; -import android.os.IBinder; - -/** - * Empty service used by the custom tab to bind to, raising the application's importance. - */ -public class KeepAliveService extends Service { - private static final Binder sBinder = new Binder(); - - @Override - public IBinder onBind(Intent intent) { - return sBinder; - } -} \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/NoHistoryCustomTabsActivityCallbacks.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/NoHistoryCustomTabsActivityCallbacks.java deleted file mode 100644 index 3ada33e762..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/NoHistoryCustomTabsActivityCallbacks.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs; - -import android.app.Activity; -import android.app.Application; -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.types.Disposable; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import io.flutter.embedding.android.FlutterActivity; - -public class NoHistoryCustomTabsActivityCallbacks implements Disposable { - @Nullable - public InAppWebViewFlutterPlugin plugin; - - public final Map noHistoryBrowserIDs = new HashMap<>(); - - public NoHistoryCustomTabsActivityCallbacks(@NonNull final InAppWebViewFlutterPlugin plugin) { - this.plugin = plugin; - } - - public Application.ActivityLifecycleCallbacks activityLifecycleCallbacks = new Application.ActivityLifecycleCallbacks() { - @Override - public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) { - } - - @Override - public void onActivityStarted(@NonNull Activity activity) { - } - - @Override - public void onActivityResumed(@NonNull Activity activity) { - if (activity instanceof FlutterActivity && plugin != null && plugin.chromeSafariBrowserManager != null) { - Collection browserIds = noHistoryBrowserIDs.values(); - for (String browserId : browserIds) { - if (browserId != null) { - noHistoryBrowserIDs.put(browserId, null); - ChromeCustomTabsActivity browser = plugin.chromeSafariBrowserManager.browsers.get(browserId); - if (browser != null) { - browser.close(); - browser.dispose(); - } - } - } - } - } - - @Override - public void onActivityPaused(@NonNull Activity activity) { - } - - @Override - public void onActivityStopped(@NonNull Activity activity) { - } - - @Override - public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) { - } - - @Override - public void onActivityDestroyed(@NonNull Activity activity) { - } - }; - - @Override - public void dispose() { - noHistoryBrowserIDs.clear(); - plugin = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ServiceConnection.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ServiceConnection.java deleted file mode 100755 index de2361543a..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ServiceConnection.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs; - -import android.content.ComponentName; -import androidx.browser.customtabs.CustomTabsClient; -import androidx.browser.customtabs.CustomTabsServiceConnection; - -import java.lang.ref.WeakReference; - -/** - * Implementation for the CustomTabsServiceConnection that avoids leaking the - * ServiceConnectionCallback - */ -public class ServiceConnection extends CustomTabsServiceConnection { - // A weak reference to the ServiceConnectionCallback to avoid leaking it. - private WeakReference mConnectionCallback; - - public ServiceConnection(ServiceConnectionCallback connectionCallback) { - mConnectionCallback = new WeakReference<>(connectionCallback); - } - - @Override - public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) { - ServiceConnectionCallback connectionCallback = mConnectionCallback.get(); - if (connectionCallback != null) connectionCallback.onServiceConnected(client); - } - - @Override - public void onServiceDisconnected(ComponentName name) { - ServiceConnectionCallback connectionCallback = mConnectionCallback.get(); - if (connectionCallback != null) connectionCallback.onServiceDisconnected(); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ServiceConnectionCallback.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ServiceConnectionCallback.java deleted file mode 100755 index 3212b2f669..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ServiceConnectionCallback.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs; - -import androidx.browser.customtabs.CustomTabsClient; - -/** - * Callback for events when connecting and disconnecting from Custom Tabs Service. - */ -public interface ServiceConnectionCallback { - /** - * Called when the service is connected. - * @param client a CustomTabsClient - */ - void onServiceConnected(CustomTabsClient client); - - /** - * Called when the service is disconnected. - */ - void onServiceDisconnected(); -} \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/TrustedWebActivity.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/TrustedWebActivity.java deleted file mode 100755 index d5f70156c4..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/TrustedWebActivity.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs; - -import android.content.Intent; -import android.graphics.Color; -import android.net.Uri; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.browser.customtabs.CustomTabColorSchemeParams; -import androidx.browser.customtabs.CustomTabsIntent; -import androidx.browser.trusted.TrustedWebActivityIntent; -import androidx.browser.trusted.TrustedWebActivityIntentBuilder; - -import java.util.List; -import java.util.Map; - -public class TrustedWebActivity extends ChromeCustomTabsActivity { - - protected static final String LOG_TAG = "TrustedWebActivity"; - - public TrustedWebActivityIntentBuilder builder; - - @Override - public void launchUrl(@NonNull String url, - @Nullable Map headers, - @Nullable String referrer, - @Nullable List otherLikelyURLs) { - if (customTabsSession == null) { - return; - } - Uri uri = Uri.parse(url); - - mayLaunchUrl(url, otherLikelyURLs); - builder = new TrustedWebActivityIntentBuilder(uri); - prepareCustomTabs(); - - TrustedWebActivityIntent trustedWebActivityIntent = builder.build(customTabsSession); - prepareCustomTabsIntent(trustedWebActivityIntent); - - CustomTabActivityHelper.openTrustedWebActivity(this, trustedWebActivityIntent, uri, headers, - referrer != null ? Uri.parse(referrer) : null, CHROME_CUSTOM_TAB_REQUEST_CODE); - } - - private void prepareCustomTabs() { - CustomTabColorSchemeParams.Builder defaultColorSchemeBuilder = new CustomTabColorSchemeParams.Builder(); - if (customSettings.toolbarBackgroundColor != null && !customSettings.toolbarBackgroundColor.isEmpty()) { - defaultColorSchemeBuilder.setToolbarColor(Color.parseColor(customSettings.toolbarBackgroundColor)); - } - if (customSettings.navigationBarColor != null && !customSettings.navigationBarColor.isEmpty()) { - defaultColorSchemeBuilder.setNavigationBarColor(Color.parseColor(customSettings.navigationBarColor)); - } - if (customSettings.navigationBarDividerColor != null && !customSettings.navigationBarDividerColor.isEmpty()) { - defaultColorSchemeBuilder.setNavigationBarDividerColor(Color.parseColor(customSettings.navigationBarDividerColor)); - } - if (customSettings.secondaryToolbarColor != null && !customSettings.secondaryToolbarColor.isEmpty()) { - defaultColorSchemeBuilder.setSecondaryToolbarColor(Color.parseColor(customSettings.secondaryToolbarColor)); - } - builder.setDefaultColorSchemeParams(defaultColorSchemeBuilder.build()); - - if (customSettings.additionalTrustedOrigins != null && !customSettings.additionalTrustedOrigins.isEmpty()) { - builder.setAdditionalTrustedOrigins(customSettings.additionalTrustedOrigins); - } - - if (customSettings.displayMode != null) { - builder.setDisplayMode(customSettings.displayMode); - } - - builder.setScreenOrientation(customSettings.screenOrientation); - } - - private void prepareCustomTabsIntent(TrustedWebActivityIntent trustedWebActivityIntent) { - Intent intent = trustedWebActivityIntent.getIntent(); - if (customSettings.packageName != null) - intent.setPackage(customSettings.packageName); - else - intent.setPackage(CustomTabsHelper.getPackageNameToUse(this)); - - if (customSettings.keepAliveEnabled) - CustomTabsHelper.addKeepAliveExtra(this, intent); - - if (customSettings.alwaysUseBrowserUI) - CustomTabsIntent.setAlwaysUseBrowserUI(intent); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/TrustedWebActivitySingleInstance.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/TrustedWebActivitySingleInstance.java deleted file mode 100755 index d77c678209..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/TrustedWebActivitySingleInstance.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.chrome_custom_tabs; - -public class TrustedWebActivitySingleInstance extends TrustedWebActivity { - - protected static final String LOG_TAG = "TrustedWebActivitySingleInstance"; - -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlocker.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlocker.java deleted file mode 100755 index 5542196258..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlocker.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.content_blocker; - -import androidx.annotation.NonNull; - -public class ContentBlocker { - @NonNull - private ContentBlockerTrigger trigger; - @NonNull - private ContentBlockerAction action; - - public ContentBlocker (@NonNull ContentBlockerTrigger trigger, @NonNull ContentBlockerAction action) { - this.trigger = trigger; - this.action = action; - } - - @NonNull - public ContentBlockerTrigger getTrigger() { - return trigger; - } - - public void setTrigger(@NonNull ContentBlockerTrigger trigger) { - this.trigger = trigger; - } - - @NonNull - public ContentBlockerAction getAction() { - return action; - } - - public void setAction(@NonNull ContentBlockerAction action) { - this.action = action; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ContentBlocker that = (ContentBlocker) o; - - if (!trigger.equals(that.trigger)) return false; - return action.equals(that.action); - } - - @Override - public int hashCode() { - int result = trigger.hashCode(); - result = 31 * result + action.hashCode(); - return result; - } - - @Override - public String toString() { - return "ContentBlocker{" + - "trigger=" + trigger + - ", action=" + action + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerAction.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerAction.java deleted file mode 100755 index 1c2f38b125..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerAction.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.content_blocker; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Map; - -public class ContentBlockerAction { - @NonNull - private ContentBlockerActionType type; - - @Nullable - private String selector; - - ContentBlockerAction(@NonNull ContentBlockerActionType type, @Nullable String selector) { - this.type = type; - if (this.type.equals(ContentBlockerActionType.CSS_DISPLAY_NONE)) { - assert(selector != null); - } - this.selector = selector; - } - - public static ContentBlockerAction fromMap(Map map) { - ContentBlockerActionType type = ContentBlockerActionType.fromValue((String) map.get("type")); - String selector = (String) map.get("selector"); - return new ContentBlockerAction(type, selector); - } - - @NonNull - public ContentBlockerActionType getType() { - return type; - } - - public void setType(@NonNull ContentBlockerActionType type) { - this.type = type; - } - - public String getSelector() { - return selector; - } - - public void setSelector(String selector) { - this.selector = selector; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ContentBlockerAction that = (ContentBlockerAction) o; - - if (type != that.type) return false; - return selector != null ? selector.equals(that.selector) : that.selector == null; - } - - @Override - public int hashCode() { - int result = type.hashCode(); - result = 31 * result + (selector != null ? selector.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "ContentBlockerAction{" + - "type=" + type + - ", selector='" + selector + '\'' + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerActionType.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerActionType.java deleted file mode 100755 index 89825a2108..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerActionType.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.content_blocker; - -public enum ContentBlockerActionType { - BLOCK ("block"), - CSS_DISPLAY_NONE ("css-display-none"), - MAKE_HTTPS ("make-https"); - - private final String value; - - private ContentBlockerActionType(String value) { - this.value = value; - } - - public boolean equalsValue(String otherValue) { - return value.equals(otherValue); - } - - public static ContentBlockerActionType fromValue(String value) { - for( ContentBlockerActionType type : ContentBlockerActionType.values()) { - if(value.equals(type.value)) - return type; - } - throw new IllegalArgumentException("No enum constant: " + value); - } - - @Override - public String toString() { - return this.value; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerHandler.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerHandler.java deleted file mode 100755 index e4486848a3..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerHandler.java +++ /dev/null @@ -1,336 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.content_blocker; - -import android.os.Build; -import android.os.Handler; -import android.text.TextUtils; -import android.util.Log; -import android.webkit.WebResourceResponse; - -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.Util; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.JavaScriptBridgeJS; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebResourceRequestExt; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.InAppWebView; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.regex.Matcher; - -import javax.net.ssl.SSLHandshakeException; - -public class ContentBlockerHandler { - protected static final String LOG_TAG = "ContentBlockerHandler"; - - protected List ruleList = new ArrayList<>(); - - public ContentBlockerHandler() {} - - public ContentBlockerHandler(List ruleList) { - this.ruleList = ruleList; - } - - public List getRuleList() { - return this.ruleList; - } - - public void setRuleList(List newRuleList) { - this.ruleList = newRuleList; - } - - @Nullable - public WebResourceResponse checkUrl(final InAppWebView webView, WebResourceRequestExt request, - ContentBlockerTriggerResourceType responseResourceType) - throws URISyntaxException, InterruptedException, MalformedURLException { - if (webView.customSettings.contentBlockers == null) - return null; - - String url = request.getUrl(); - - URI u; - try { - u = new URI(url); - } catch (URISyntaxException e) { - String[] urlSplit = url.split(":"); - String scheme = urlSplit[0]; - URL tempUrl = new URL(url.replace(scheme, "https")); - u = new URI(scheme, tempUrl.getUserInfo(), tempUrl.getHost(), tempUrl.getPort(), tempUrl.getPath(), tempUrl.getQuery(), tempUrl.getRef()); - } - String host = u.getHost(); - int port = u.getPort(); - String scheme = u.getScheme(); - // thread safe copy list - List ruleListCopy = new CopyOnWriteArrayList(ruleList); - - for (ContentBlocker contentBlocker : ruleListCopy) { - ContentBlockerTrigger trigger = contentBlocker.getTrigger(); - List resourceTypes = trigger.getResourceType(); - if (resourceTypes.contains(ContentBlockerTriggerResourceType.IMAGE) && !resourceTypes.contains(ContentBlockerTriggerResourceType.SVG_DOCUMENT)) { - resourceTypes.add(ContentBlockerTriggerResourceType.SVG_DOCUMENT); - } - - ContentBlockerAction action = contentBlocker.getAction(); - - Matcher m = trigger.getUrlFilterPatternCompiled().matcher(url); - if (m.matches()) { - - if (!resourceTypes.isEmpty() && !resourceTypes.contains(responseResourceType)) { - return null; - } - if (!trigger.getIfDomain().isEmpty()) { - boolean matchFound = false; - for (String domain : trigger.getIfDomain()) { - if ((domain.startsWith("*") && host.endsWith(domain.replace("*", ""))) || domain.equals(host)) { - matchFound = true; - break; - } - } - if (!matchFound) - return null; - } - if (!trigger.getUnlessDomain().isEmpty()) { - for (String domain : trigger.getUnlessDomain()) - if ((domain.startsWith("*") && host.endsWith(domain.replace("*", ""))) || domain.equals(host)) - return null; - } - - final String[] webViewUrl = new String[1]; - if (!trigger.getLoadType().isEmpty() || !trigger.getIfTopUrl().isEmpty() || !trigger.getUnlessTopUrl().isEmpty()) { - final CountDownLatch latch = new CountDownLatch(1); - Handler handler = new Handler(webView.getWebViewLooper()); - handler.post(new Runnable() { - @Override - public void run() { - webViewUrl[0] = webView.getUrl(); - latch.countDown(); - } - }); - latch.await(); - } - - if (webViewUrl[0] != null) { - if (!trigger.getLoadType().isEmpty()) { - URI cUrl = new URI(webViewUrl[0]); - String cHost = cUrl.getHost(); - int cPort = cUrl.getPort(); - String cScheme = cUrl.getScheme(); - - if ( (trigger.getLoadType().contains("first-party") && cHost != null && !(cScheme.equals(scheme) && cHost.equals(host) && cPort == port)) || - (trigger.getLoadType().contains("third-party") && cHost != null && cHost.equals(host)) ) - return null; - } - if (!trigger.getIfTopUrl().isEmpty()) { - boolean matchFound = false; - for (String topUrl : trigger.getIfTopUrl()) { - if (webViewUrl[0].startsWith(topUrl)) { - matchFound = true; - break; - } - } - if (!matchFound) - return null; - } - if (!trigger.getUnlessTopUrl().isEmpty()) { - for (String topUrl : trigger.getUnlessTopUrl()) - if (webViewUrl[0].startsWith(topUrl)) - return null; - } - } - - switch (action.getType()) { - - case BLOCK: - return new WebResourceResponse("", "", null); - - case CSS_DISPLAY_NONE: - final String cssSelector = action.getSelector(); - final String jsScript = "(function(d) { " + - " function hide () { " + - " if (d.body != null && !d.getElementById('" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "-css-display-none-style')) { " + - " var c = d.createElement('style'); " + - " c.id = '" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "-css-display-none-style'; " + - " c.innerHTML = '" + cssSelector + " { display: none !important; }'; " + - " d.body.appendChild(c); " + - " }" + - " d.querySelectorAll('" + cssSelector + "').forEach(function (item, index) { " + - " item.setAttribute('style', 'display: none !important;'); " + - " }); " + - " }; " + - " hide(); " + - " d.addEventListener('DOMContentLoaded', function(event) { hide(); }); " + - "})(document);"; - - final Handler handler = new Handler(webView.getWebViewLooper()); - handler.postDelayed(new Runnable() { - @Override - public void run() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - webView.evaluateJavascript(jsScript, null); - } else { - webView.loadUrl("javascript:" + jsScript); - } - } - }, 800); - break; - - case MAKE_HTTPS: - if (scheme.equals("http") && (port == -1 || port == 80)) { - String urlHttps = url.replace("http://", "https://"); - - HttpURLConnection urlConnection = Util.makeHttpRequest(urlHttps, request.getMethod(), request.getHeaders()); - if (urlConnection != null) { - try { - byte[] dataBytes = Util.readAllBytes(urlConnection.getInputStream()); - if (dataBytes == null) { - return null; - } - InputStream dataStream = new ByteArrayInputStream(dataBytes); - - String encoding = urlConnection.getContentEncoding(); - String contentType = urlConnection.getContentType(); - if (contentType == null) { - contentType = "text/plain"; - } else { - String[] contentTypeSplit = contentType.split(";"); - contentType = contentTypeSplit[0].trim(); - if (encoding == null) { - encoding = (contentTypeSplit.length > 1 && contentTypeSplit[1].contains("charset=")) - ? contentTypeSplit[1].replace("charset=", "").trim() - : "utf-8"; - } - } - - String reasonPhrase = urlConnection.getResponseMessage(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && reasonPhrase != null) { - Map responseHeaders = new HashMap<>(); - for (Map.Entry> responseHeader : urlConnection.getHeaderFields().entrySet()) { - responseHeaders.put(responseHeader.getKey(), TextUtils.join(",", responseHeader.getValue())); - } - return new WebResourceResponse(contentType, - encoding, - urlConnection.getResponseCode(), - reasonPhrase, - responseHeaders, - dataStream); - } else { - return new WebResourceResponse(contentType, - encoding, - dataStream); - } - } catch (Exception e) { - if (!(e instanceof SSLHandshakeException)) { - Log.e(LOG_TAG, "", e); - } - } finally { - urlConnection.disconnect(); - } - } - -// Request mRequest = new Request.Builder().url(urlHttps).build(); -// Response response = null; -// -// try { -// response = Util.getBasicOkHttpClient().newCall(mRequest).execute(); -// byte[] dataBytes = response.body().bytes(); -// InputStream dataStream = new ByteArrayInputStream(dataBytes); -// -// String[] contentTypeSplit = response.header("content-type", "text/plain").split(";"); -// -// String contentType = contentTypeSplit[0].trim(); -// String encoding = (contentTypeSplit.length > 1 && contentTypeSplit[1].contains("charset=")) -// ? contentTypeSplit[1].replace("charset=", "").trim() -// : "utf-8"; -// -// response.body().close(); -// response.close(); -// -// return new WebResourceResponse(contentType, encoding, dataStream); -// -// } catch (Exception e) { -// if (response != null) { -// response.body().close(); -// response.close(); -// } -// if (!(e instanceof SSLHandshakeException)) { -// Log.e(LOG_TAG, "", e); -// } -// } - } - break; - } - } - } - return null; - } - - @Nullable - public WebResourceResponse checkUrl(final InAppWebView webView, WebResourceRequestExt request) throws URISyntaxException, InterruptedException, MalformedURLException { - ContentBlockerTriggerResourceType responseResourceType = getResourceTypeFromUrl(request); - return checkUrl(webView, request, responseResourceType); - } - - @Nullable - public WebResourceResponse checkUrl(final InAppWebView webView, WebResourceRequestExt request, String contentType) throws URISyntaxException, InterruptedException, MalformedURLException { - ContentBlockerTriggerResourceType responseResourceType = getResourceTypeFromContentType(contentType); - return checkUrl(webView, request, responseResourceType); - } - - public ContentBlockerTriggerResourceType getResourceTypeFromUrl(WebResourceRequestExt request) { - ContentBlockerTriggerResourceType responseResourceType = ContentBlockerTriggerResourceType.RAW; - String url = request.getUrl(); - - if (url.startsWith("http://") || url.startsWith("https://")) { - // make an HTTP "HEAD" request to the server for that URL. This will not return the full content of the URL. - HttpURLConnection urlConnection = Util.makeHttpRequest(url, "HEAD", request.getHeaders()); - if (urlConnection != null) { - try { - String contentType = urlConnection.getContentType(); - if (contentType != null) { - String[] contentTypeSplit = contentType.split(";"); - contentType = contentTypeSplit[0].trim(); - responseResourceType = getResourceTypeFromContentType(contentType); - } - } catch (Exception e) { - Log.e(LOG_TAG, "", e); - } finally { - urlConnection.disconnect(); - } - } - } - return responseResourceType; - } - - public ContentBlockerTriggerResourceType getResourceTypeFromContentType(String contentType) { - ContentBlockerTriggerResourceType responseResourceType = ContentBlockerTriggerResourceType.RAW; - - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types - if (contentType.equals("text/css")) { - responseResourceType = ContentBlockerTriggerResourceType.STYLE_SHEET; - } else if (contentType.equals("image/svg+xml")) { - responseResourceType = ContentBlockerTriggerResourceType.SVG_DOCUMENT; - } else if (contentType.startsWith("image/")) { - responseResourceType = ContentBlockerTriggerResourceType.IMAGE; - } else if (contentType.startsWith("font/")) { - responseResourceType = ContentBlockerTriggerResourceType.FONT; - } else if (contentType.startsWith("audio/") || contentType.startsWith("video/") || contentType.equals("application/ogg")) { - responseResourceType = ContentBlockerTriggerResourceType.MEDIA; - } else if (contentType.endsWith("javascript")) { - responseResourceType = ContentBlockerTriggerResourceType.SCRIPT; - } else if (contentType.startsWith("text/")) { - responseResourceType = ContentBlockerTriggerResourceType.DOCUMENT; - } - - return responseResourceType; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerTrigger.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerTrigger.java deleted file mode 100755 index 8efb3c07d3..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerTrigger.java +++ /dev/null @@ -1,185 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.content_blocker; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - -public class ContentBlockerTrigger { - - @NonNull - private String urlFilter; - private Pattern urlFilterPatternCompiled; - private Boolean urlFilterIsCaseSensitive; - private List resourceType = new ArrayList<>(); - private List ifDomain = new ArrayList<>(); - private List unlessDomain = new ArrayList<>(); - private List loadType = new ArrayList<>(); - private List ifTopUrl = new ArrayList<>(); - private List unlessTopUrl = new ArrayList<>(); - - public ContentBlockerTrigger(@NonNull String urlFilter, @Nullable Boolean urlFilterIsCaseSensitive, @Nullable List resourceType, - @Nullable List ifDomain, @Nullable List unlessDomain, @Nullable List loadType, - @Nullable List ifTopUrl, @Nullable List unlessTopUrl) { - this.urlFilterIsCaseSensitive = urlFilterIsCaseSensitive != null ? urlFilterIsCaseSensitive : false; - - this.urlFilter = urlFilter; - this.urlFilterPatternCompiled = Pattern.compile(this.urlFilter, this.urlFilterIsCaseSensitive ? 0 : Pattern.CASE_INSENSITIVE); - - this.resourceType = resourceType != null ? resourceType : this.resourceType; - this.ifDomain = ifDomain != null ? ifDomain : this.ifDomain; - this.unlessDomain = unlessDomain != null ? unlessDomain : this.unlessDomain; - if ((!(this.ifDomain.isEmpty() || this.unlessDomain.isEmpty()) != false)) - throw new AssertionError(); - this.loadType = loadType != null ? loadType : this.loadType; - if ((this.loadType.size() > 2)) throw new AssertionError(); - this.ifTopUrl = ifTopUrl != null ? ifTopUrl : this.ifTopUrl; - this.unlessTopUrl = unlessTopUrl != null ? unlessTopUrl : this.unlessTopUrl; - if ((!(this.ifTopUrl.isEmpty() || this.unlessTopUrl.isEmpty()) != false)) - throw new AssertionError(); - } - - public static ContentBlockerTrigger fromMap(Map map) { - String urlFilter = (String) map.get("url-filter"); - Boolean urlFilterIsCaseSensitive = (Boolean) map.get("url-filter-is-case-sensitive"); - List resourceTypeStringList = (List) map.get("resource-type"); - List resourceType = new ArrayList<>(); - if (resourceTypeStringList != null) { - for (String type : resourceTypeStringList) { - resourceType.add(ContentBlockerTriggerResourceType.fromValue(type)); - } - } else { - resourceType.addAll(Arrays.asList(ContentBlockerTriggerResourceType.values())); - } - List ifDomain = (List) map.get("if-domain"); - List unlessDomain = (List) map.get("unless-domain"); - List loadType = (List) map.get("load-type"); - List ifTopUrl = (List) map.get("if-top-url"); - List unlessTopUrl = (List) map.get("unless-top-url"); - return new ContentBlockerTrigger(urlFilter, urlFilterIsCaseSensitive, resourceType, ifDomain, unlessDomain, loadType, ifTopUrl, unlessTopUrl); - } - - @NonNull - public String getUrlFilter() { - return urlFilter; - } - - public void setUrlFilter(@NonNull String urlFilter) { - this.urlFilter = urlFilter; - } - - public Pattern getUrlFilterPatternCompiled() { - return urlFilterPatternCompiled; - } - - public void setUrlFilterPatternCompiled(Pattern urlFilterPatternCompiled) { - this.urlFilterPatternCompiled = urlFilterPatternCompiled; - } - - public Boolean getUrlFilterIsCaseSensitive() { - return urlFilterIsCaseSensitive; - } - - public void setUrlFilterIsCaseSensitive(Boolean urlFilterIsCaseSensitive) { - this.urlFilterIsCaseSensitive = urlFilterIsCaseSensitive; - } - - public List getResourceType() { - return resourceType; - } - - public void setResourceType(List resourceType) { - this.resourceType = resourceType; - } - - public List getIfDomain() { - return ifDomain; - } - - public void setIfDomain(List ifDomain) { - this.ifDomain = ifDomain; - } - - public List getUnlessDomain() { - return unlessDomain; - } - - public void setUnlessDomain(List unlessDomain) { - this.unlessDomain = unlessDomain; - } - - public List getLoadType() { - return loadType; - } - - public void setLoadType(List loadType) { - this.loadType = loadType; - } - - public List getIfTopUrl() { - return ifTopUrl; - } - - public void setIfTopUrl(List ifTopUrl) { - this.ifTopUrl = ifTopUrl; - } - - public List getUnlessTopUrl() { - return unlessTopUrl; - } - - public void setUnlessTopUrl(List unlessTopUrl) { - this.unlessTopUrl = unlessTopUrl; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ContentBlockerTrigger that = (ContentBlockerTrigger) o; - - if (!urlFilter.equals(that.urlFilter)) return false; - if (!urlFilterPatternCompiled.equals(that.urlFilterPatternCompiled)) return false; - if (!urlFilterIsCaseSensitive.equals(that.urlFilterIsCaseSensitive)) return false; - if (!resourceType.equals(that.resourceType)) return false; - if (!ifDomain.equals(that.ifDomain)) return false; - if (!unlessDomain.equals(that.unlessDomain)) return false; - if (!loadType.equals(that.loadType)) return false; - if (!ifTopUrl.equals(that.ifTopUrl)) return false; - return unlessTopUrl.equals(that.unlessTopUrl); - } - - @Override - public int hashCode() { - int result = urlFilter.hashCode(); - result = 31 * result + urlFilterPatternCompiled.hashCode(); - result = 31 * result + urlFilterIsCaseSensitive.hashCode(); - result = 31 * result + resourceType.hashCode(); - result = 31 * result + ifDomain.hashCode(); - result = 31 * result + unlessDomain.hashCode(); - result = 31 * result + loadType.hashCode(); - result = 31 * result + ifTopUrl.hashCode(); - result = 31 * result + unlessTopUrl.hashCode(); - return result; - } - - @Override - public String toString() { - return "ContentBlockerTrigger{" + - "urlFilter='" + urlFilter + '\'' + - ", urlFilterPatternCompiled=" + urlFilterPatternCompiled + - ", urlFilterIsCaseSensitive=" + urlFilterIsCaseSensitive + - ", resourceType=" + resourceType + - ", ifDomain=" + ifDomain + - ", unlessDomain=" + unlessDomain + - ", loadType=" + loadType + - ", ifTopUrl=" + ifTopUrl + - ", unlessTopUrl=" + unlessTopUrl + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerTriggerResourceType.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerTriggerResourceType.java deleted file mode 100755 index 25eb60b5ec..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerTriggerResourceType.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.content_blocker; - -public enum ContentBlockerTriggerResourceType { - DOCUMENT ("document"), - IMAGE ("image"), - STYLE_SHEET ("style-sheet"), - SCRIPT ("script"), - FONT ("font"), - SVG_DOCUMENT ("svg-document"), - MEDIA ("media"), - POPUP ("popup"), - RAW ("raw"); - - private final String value; - - private ContentBlockerTriggerResourceType(String value) { - this.value = value; - } - - public boolean equalsValue(String otherValue) { - return value.equals(otherValue); - } - - public static ContentBlockerTriggerResourceType fromValue(String value) { - for( ContentBlockerTriggerResourceType type : ContentBlockerTriggerResourceType.values()) { - if(value.equals(type.value)) - return type; - } - throw new IllegalArgumentException("No enum constant: " + value); - } - - @Override - public String toString() { - return this.value; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/CredentialDatabase.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/CredentialDatabase.java deleted file mode 100755 index 5d83b7e6d7..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/CredentialDatabase.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.credential_database; - -import android.content.Context; - -import com.pichillilorenzo.flutter_inappwebview_android.types.URLCredential; -import com.pichillilorenzo.flutter_inappwebview_android.types.URLProtectionSpace; - -import java.util.ArrayList; -import java.util.List; - -public class CredentialDatabase { - - private static CredentialDatabase instance; - static final String LOG_TAG = "CredentialDatabase"; - - // If you change the database schema, you must increment the database version. - public static final int DATABASE_VERSION = 2; - public static final String DATABASE_NAME = "CredentialDatabase.db"; - - public URLProtectionSpaceDao protectionSpaceDao; - public URLCredentialDao credentialDao; - public CredentialDatabaseHelper db; - - private CredentialDatabase() {} - - private CredentialDatabase(CredentialDatabaseHelper db, URLProtectionSpaceDao protectionSpaceDao, URLCredentialDao credentialDao) { - this.db = db; - this.protectionSpaceDao = protectionSpaceDao; - this.credentialDao = credentialDao; - } - - public static CredentialDatabase getInstance(Context context) { - if (instance != null) - return instance; - CredentialDatabaseHelper db = new CredentialDatabaseHelper(context); - instance = new CredentialDatabase(db, new URLProtectionSpaceDao(db), new URLCredentialDao(db)); - return instance; - } - - public List getHttpAuthCredentials(String host, String protocol, String realm, Integer port) { - List credentials = new ArrayList<>(); - URLProtectionSpace protectionSpace = protectionSpaceDao.find(host, protocol, realm, port); - if (protectionSpace != null) { - credentials = credentialDao.getAllByProtectionSpaceId(protectionSpace.getId()); - } - return credentials; - } - - public void clearAllAuthCredentials() { - db.clearAllTables(db.getWritableDatabase()); - } - - public void removeHttpAuthCredentials(String host, String protocol, String realm, Integer port) { - URLProtectionSpace URLProtectionSpace = protectionSpaceDao.find(host, protocol, realm, port); - if (URLProtectionSpace != null) { - protectionSpaceDao.delete(URLProtectionSpace); - } - } - - public void removeHttpAuthCredential(String host, String protocol, String realm, Integer port, String username, String password) { - URLProtectionSpace protectionSpace = protectionSpaceDao.find(host, protocol, realm, port); - if (protectionSpace != null) { - URLCredential credential = credentialDao.find(username, password, protectionSpace.getId()); - credentialDao.delete(credential); - } - } - - public void setHttpAuthCredential(String host, String protocol, String realm, Integer port, String username, String password) { - URLProtectionSpace protectionSpace = protectionSpaceDao.find(host, protocol, realm, port); - Long protectionSpaceId; - if (protectionSpace == null) { - protectionSpaceId = protectionSpaceDao.insert(new URLProtectionSpace(null, host, protocol, realm, port)); - } else { - protectionSpaceId = protectionSpace.getId(); - } - - URLCredential credential = credentialDao.find(username, password, protectionSpaceId); - if (credential != null) { - boolean needUpdate = false; - if (!credential.getUsername().equals(username)) { - credential.setUsername(username); - needUpdate = true; - } - if (!credential.getPassword().equals(password)) { - credential.setPassword(password); - needUpdate = true; - } - if (needUpdate) - credentialDao.update(credential); - } else { - credential = new URLCredential(null, username, password, protectionSpaceId); - credential.setId(credentialDao.insert(credential)); - } - } -} \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/CredentialDatabaseHandler.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/CredentialDatabaseHandler.java deleted file mode 100755 index 23052a180a..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/CredentialDatabaseHandler.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.credential_database; - -import android.os.Build; -import android.webkit.WebViewDatabase; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; -import com.pichillilorenzo.flutter_inappwebview_android.types.URLCredential; -import com.pichillilorenzo.flutter_inappwebview_android.types.URLProtectionSpace; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -@RequiresApi(api = Build.VERSION_CODES.O) -public class CredentialDatabaseHandler extends ChannelDelegateImpl { - protected static final String LOG_TAG = "CredentialDatabaseHandler"; - public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_credential_database"; - - @Nullable - public static CredentialDatabase credentialDatabase; - @Nullable - public InAppWebViewFlutterPlugin plugin; - - public CredentialDatabaseHandler(@NonNull final InAppWebViewFlutterPlugin plugin) { - super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME)); - this.plugin = plugin; - } - - public static void init(@NonNull InAppWebViewFlutterPlugin plugin) { - if (credentialDatabase == null) { - credentialDatabase = CredentialDatabase.getInstance(plugin.applicationContext); - } - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - if (plugin != null) { - init(plugin); - } - - switch (call.method) { - case "getAllAuthCredentials": - { - List> allCredentials = new ArrayList<>(); - if (credentialDatabase != null) { - List protectionSpaces = credentialDatabase.protectionSpaceDao.getAll(); - for (URLProtectionSpace protectionSpace : protectionSpaces) { - List> credentials = new ArrayList<>(); - for (URLCredential credential : credentialDatabase.credentialDao.getAllByProtectionSpaceId(protectionSpace.getId())) { - credentials.add(credential.toMap()); - } - Map obj = new HashMap<>(); - obj.put("protectionSpace", protectionSpace.toMap()); - obj.put("credentials", credentials); - allCredentials.add(obj); - } - } - result.success(allCredentials); - } - break; - case "getHttpAuthCredentials": - { - List> credentials = new ArrayList<>(); - if (credentialDatabase != null) { - String host = (String) call.argument("host"); - String protocol = (String) call.argument("protocol"); - String realm = (String) call.argument("realm"); - Integer port = (Integer) call.argument("port"); - - for (URLCredential credential : credentialDatabase.getHttpAuthCredentials(host, protocol, realm, port)) { - credentials.add(credential.toMap()); - } - } - result.success(credentials); - } - break; - case "setHttpAuthCredential": - { - if (credentialDatabase != null) { - String host = (String) call.argument("host"); - String protocol = (String) call.argument("protocol"); - String realm = (String) call.argument("realm"); - Integer port = (Integer) call.argument("port"); - String username = (String) call.argument("username"); - String password = (String) call.argument("password"); - - credentialDatabase.setHttpAuthCredential(host, protocol, realm, port, username, password); - result.success(true); - } else { - result.success(false); - } - } - break; - case "removeHttpAuthCredential": - { - if (credentialDatabase != null) { - String host = (String) call.argument("host"); - String protocol = (String) call.argument("protocol"); - String realm = (String) call.argument("realm"); - Integer port = (Integer) call.argument("port"); - String username = (String) call.argument("username"); - String password = (String) call.argument("password"); - - credentialDatabase.removeHttpAuthCredential(host, protocol, realm, port, username, password); - result.success(true); - } else { - result.success(false); - } - } - break; - case "removeHttpAuthCredentials": - { - if (credentialDatabase != null) { - String host = (String) call.argument("host"); - String protocol = (String) call.argument("protocol"); - String realm = (String) call.argument("realm"); - Integer port = (Integer) call.argument("port"); - - credentialDatabase.removeHttpAuthCredentials(host, protocol, realm, port); - result.success(true); - } else { - result.success(false); - } - } - break; - case "clearAllAuthCredentials": - if (credentialDatabase != null) { - credentialDatabase.clearAllAuthCredentials(); - if (plugin != null && plugin.applicationContext != null) { - WebViewDatabase.getInstance(plugin.applicationContext).clearHttpAuthUsernamePassword(); - } - result.success(true); - } else { - result.success(false); - } - break; - default: - result.notImplemented(); - } - } - - @Override - public void dispose() { - super.dispose(); - plugin = null; - credentialDatabase = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/CredentialDatabaseHelper.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/CredentialDatabaseHelper.java deleted file mode 100755 index ff67e2802c..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/CredentialDatabaseHelper.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.credential_database; - -import android.content.Context; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; - -public class CredentialDatabaseHelper extends SQLiteOpenHelper { - - private static final String SQL_CREATE_PROTECTION_SPACE_TABLE = - "CREATE TABLE " + URLProtectionSpaceContract.FeedEntry.TABLE_NAME + " (" + - URLProtectionSpaceContract.FeedEntry._ID + " INTEGER PRIMARY KEY," + - URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST + " TEXT NOT NULL," + - URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL + " TEXT," + - URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM + " TEXT," + - URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT + " INTEGER," + - "UNIQUE(" + URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST + ", " + URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL + ", " + - URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM + ", " + URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT + - ")" + - ");"; - - private static final String SQL_CREATE_CREDENTIAL_TABLE = - "CREATE TABLE " + URLCredentialContract.FeedEntry.TABLE_NAME + " (" + - URLCredentialContract.FeedEntry._ID + " INTEGER PRIMARY KEY," + - URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME + " TEXT NOT NULL," + - URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD + " TEXT NOT NULL," + - URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + " INTEGER NOT NULL," + - "UNIQUE(" + URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME + ", " + URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD + ", " + - URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + - ")," + - "FOREIGN KEY (" + URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + ") REFERENCES " + - URLProtectionSpaceContract.FeedEntry.TABLE_NAME + " (" + URLProtectionSpaceContract.FeedEntry._ID + ") ON DELETE CASCADE" + - ");"; - - private static final String SQL_DELETE_PROTECTION_SPACE_TABLE = - "DROP TABLE IF EXISTS " + URLProtectionSpaceContract.FeedEntry.TABLE_NAME; - - private static final String SQL_DELETE_CREDENTIAL_TABLE = - "DROP TABLE IF EXISTS " + URLCredentialContract.FeedEntry.TABLE_NAME; - - public CredentialDatabaseHelper(Context context) { - super(context, CredentialDatabase.DATABASE_NAME, null, CredentialDatabase.DATABASE_VERSION); - } - - public void onCreate(SQLiteDatabase db) { - db.execSQL(SQL_CREATE_PROTECTION_SPACE_TABLE); - db.execSQL(SQL_CREATE_CREDENTIAL_TABLE); - } - - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - // This database is only a cache for online data, so its upgrade policy is - // to simply to discard the data and start over - db.execSQL(SQL_DELETE_PROTECTION_SPACE_TABLE); - db.execSQL(SQL_DELETE_CREDENTIAL_TABLE); - onCreate(db); - } - - public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { - onUpgrade(db, oldVersion, newVersion); - } - - public void clearAllTables(SQLiteDatabase db) { - db.execSQL(SQL_DELETE_PROTECTION_SPACE_TABLE); - db.execSQL(SQL_DELETE_CREDENTIAL_TABLE); - onCreate(db); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/URLCredentialContract.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/URLCredentialContract.java deleted file mode 100755 index d837b5579e..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/URLCredentialContract.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.credential_database; - -import android.provider.BaseColumns; - -public class URLCredentialContract { - private URLCredentialContract() {} - - /* Inner class that defines the table contents */ - public static class FeedEntry implements BaseColumns { - public static final String TABLE_NAME = "credential"; - public static final String COLUMN_NAME_USERNAME = "username"; - public static final String COLUMN_NAME_PASSWORD = "password"; - public static final String COLUMN_NAME_PROTECTION_SPACE_ID = "protection_space_id"; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/URLCredentialDao.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/URLCredentialDao.java deleted file mode 100755 index 2c39a41e80..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/URLCredentialDao.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.credential_database; - -import android.content.ContentValues; -import android.database.Cursor; - -import com.pichillilorenzo.flutter_inappwebview_android.types.URLCredential; - -import java.util.ArrayList; -import java.util.List; - -public class URLCredentialDao { - - CredentialDatabaseHelper credentialDatabaseHelper; - String[] projection = { - URLCredentialContract.FeedEntry._ID, - URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME, - URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD, - URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID - }; - - public URLCredentialDao(CredentialDatabaseHelper credentialDatabaseHelper) { - this.credentialDatabaseHelper = credentialDatabaseHelper; - } - - public List getAllByProtectionSpaceId(Long protectionSpaceId) { - String selection = URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + " = ?"; - String[] selectionArgs = {protectionSpaceId.toString()}; - - Cursor cursor = credentialDatabaseHelper.getReadableDatabase().query( - URLCredentialContract.FeedEntry.TABLE_NAME, - projection, - selection, - selectionArgs, - null, - null, - null - ); - - List URLCredentials = new ArrayList<>(); - while (cursor.moveToNext()) { - Long id = cursor.getLong(cursor.getColumnIndexOrThrow(URLCredentialContract.FeedEntry._ID)); - String username = cursor.getString(cursor.getColumnIndexOrThrow(URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME)); - String password = cursor.getString(cursor.getColumnIndexOrThrow(URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD)); - URLCredentials.add(new URLCredential(id, username, password, protectionSpaceId)); - } - cursor.close(); - - return URLCredentials; - } - - public URLCredential find(String username, String password, Long protectionSpaceId) { - String selection = URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME + " = ? AND " + - URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD + " = ? AND " + - URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + " = ?"; - String[] selectionArgs = {username, password, protectionSpaceId.toString()}; - - Cursor cursor = credentialDatabaseHelper.getReadableDatabase().query( - URLCredentialContract.FeedEntry.TABLE_NAME, - projection, - selection, - selectionArgs, - null, - null, - null - ); - - URLCredential URLCredential = null; - if (cursor.moveToNext()) { - Long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(URLCredentialContract.FeedEntry._ID)); - String rowUsername = cursor.getString(cursor.getColumnIndexOrThrow(URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME)); - String rowPassword = cursor.getString(cursor.getColumnIndexOrThrow(URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD)); - URLCredential = new URLCredential(rowId, rowUsername, rowPassword, protectionSpaceId); - } - cursor.close(); - - return URLCredential; - } - - public long insert(URLCredential urlCredential) { - ContentValues credentialValues = new ContentValues(); - credentialValues.put(URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME, urlCredential.getUsername()); - credentialValues.put(URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD, urlCredential.getPassword()); - credentialValues.put(URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID, urlCredential.getProtectionSpaceId()); - - return credentialDatabaseHelper.getWritableDatabase().insert(URLCredentialContract.FeedEntry.TABLE_NAME, null, credentialValues); - } - - public long update(URLCredential urlCredential) { - ContentValues credentialValues = new ContentValues(); - credentialValues.put(URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME, urlCredential.getUsername()); - credentialValues.put(URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD, urlCredential.getPassword()); - - String whereClause = URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + " = ?"; - String[] whereArgs = {urlCredential.getProtectionSpaceId().toString()}; - - return credentialDatabaseHelper.getWritableDatabase().update(URLCredentialContract.FeedEntry.TABLE_NAME, credentialValues, whereClause, whereArgs); - } - - public long delete(URLCredential urlCredential) { - String whereClause = URLCredentialContract.FeedEntry._ID + " = ?"; - String[] whereArgs = {urlCredential.getId().toString()}; - - return credentialDatabaseHelper.getWritableDatabase().delete(URLCredentialContract.FeedEntry.TABLE_NAME, whereClause, whereArgs); - } - -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/URLProtectionSpaceContract.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/URLProtectionSpaceContract.java deleted file mode 100755 index 347ab5fd0b..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/URLProtectionSpaceContract.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.credential_database; - -import android.provider.BaseColumns; - -public class URLProtectionSpaceContract { - private URLProtectionSpaceContract() {} - - /* Inner class that defines the table contents */ - public static class FeedEntry implements BaseColumns { - public static final String TABLE_NAME = "protection_space"; - public static final String COLUMN_NAME_HOST = "host"; - public static final String COLUMN_NAME_PROTOCOL = "protocol"; - public static final String COLUMN_NAME_REALM = "realm"; - public static final String COLUMN_NAME_PORT = "port"; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/URLProtectionSpaceDao.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/URLProtectionSpaceDao.java deleted file mode 100755 index db85276f01..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/credential_database/URLProtectionSpaceDao.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.credential_database; - -import android.content.ContentValues; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; - -import com.pichillilorenzo.flutter_inappwebview_android.types.URLProtectionSpace; - -import java.util.ArrayList; -import java.util.List; - -public class URLProtectionSpaceDao { - CredentialDatabaseHelper credentialDatabaseHelper; - String[] projection = { - URLProtectionSpaceContract.FeedEntry._ID, - URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST, - URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL, - URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM, - URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT - }; - - public URLProtectionSpaceDao(CredentialDatabaseHelper credentialDatabaseHelper) { - this.credentialDatabaseHelper = credentialDatabaseHelper; - } - - public List getAll() { - SQLiteDatabase readableDatabase = credentialDatabaseHelper.getReadableDatabase(); - - Cursor cursor = readableDatabase.query( - URLProtectionSpaceContract.FeedEntry.TABLE_NAME, - projection, - null, - null, - null, - null, - null - ); - - List URLProtectionSpaces = new ArrayList<>(); - while (cursor.moveToNext()) { - Long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry._ID)); - String rowHost = cursor.getString(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST)); - String rowProtocol = cursor.getString(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL)); - String rowRealm = cursor.getString(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM)); - Integer rowPort = cursor.getInt(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT)); - URLProtectionSpaces.add(new URLProtectionSpace(rowId, rowHost, rowProtocol, rowRealm, rowPort)); - } - cursor.close(); - - return URLProtectionSpaces; - } - - public URLProtectionSpace find(String host, String protocol, String realm, Integer port) { - SQLiteDatabase readableDatabase = credentialDatabaseHelper.getReadableDatabase(); - - String selection = URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST + " = ? AND " + URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL + " = ? AND " + - URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM + " = ? AND " + URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT + " = ?"; - String[] selectionArgs = {host, protocol, realm, port.toString()}; - - Cursor cursor = readableDatabase.query( - URLProtectionSpaceContract.FeedEntry.TABLE_NAME, - projection, - selection, - selectionArgs, - null, - null, - null - ); - - URLProtectionSpace URLProtectionSpace = null; - if (cursor.moveToNext()) { - Long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry._ID)); - String rowHost = cursor.getString(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST)); - String rowProtocol = cursor.getString(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL)); - String rowRealm = cursor.getString(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM)); - Integer rowPort = cursor.getInt(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT)); - URLProtectionSpace = new URLProtectionSpace(rowId, rowHost, rowProtocol, rowRealm, rowPort); - } - cursor.close(); - - return URLProtectionSpace; - } - - public long insert(URLProtectionSpace URLProtectionSpace) { - ContentValues protectionSpaceValues = new ContentValues(); - protectionSpaceValues.put(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST, URLProtectionSpace.getHost()); - protectionSpaceValues.put(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL, URLProtectionSpace.getProtocol()); - protectionSpaceValues.put(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM, URLProtectionSpace.getRealm()); - protectionSpaceValues.put(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT, URLProtectionSpace.getPort()); - - return credentialDatabaseHelper.getWritableDatabase().insert(URLProtectionSpaceContract.FeedEntry.TABLE_NAME, null, protectionSpaceValues); - }; - - public long delete(URLProtectionSpace URLProtectionSpace) { - String whereClause = URLProtectionSpaceContract.FeedEntry._ID + " = ?"; - String[] whereArgs = {URLProtectionSpace.getId().toString()}; - - return credentialDatabaseHelper.getWritableDatabase().delete(URLProtectionSpaceContract.FeedEntry.TABLE_NAME, whereClause, whereArgs); - } -} \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/find_interaction/FindInteractionChannelDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/find_interaction/FindInteractionChannelDelegate.java deleted file mode 100644 index a0be164c46..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/find_interaction/FindInteractionChannelDelegate.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.find_interaction; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; -import com.pichillilorenzo.flutter_inappwebview_android.types.FindSession; - -import java.util.HashMap; -import java.util.Map; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class FindInteractionChannelDelegate extends ChannelDelegateImpl { - @Nullable - private FindInteractionController findInteractionController; - - public FindInteractionChannelDelegate(@NonNull FindInteractionController findInteractionController, @NonNull MethodChannel channel) { - super(channel); - this.findInteractionController = findInteractionController; - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) { - switch (call.method) { - case "findAll": - if (findInteractionController != null) { - String find = (String) call.argument("find"); - findInteractionController.findAll(find); - } - result.success(true); - break; - case "findNext": - if (findInteractionController != null) { - Boolean forward = (Boolean) call.argument("forward"); - findInteractionController.findNext(forward); - } - result.success(true); - break; - case "clearMatches": - if (findInteractionController != null) { - findInteractionController.clearMatches(); - } - result.success(true); - break; - case "setSearchText": - if (findInteractionController != null) { - findInteractionController.searchText = (String) call.argument("searchText"); - result.success(true); - } else { - result.success(false); - } - break; - case "getSearchText": - if (findInteractionController != null) { - result.success(findInteractionController.searchText); - } else { - result.success(false); - } - break; - case "getActiveFindSession": - if (findInteractionController != null && findInteractionController.activeFindSession != null) { - result.success(findInteractionController.activeFindSession.toMap()); - } else { - result.success(null); - } - break; - default: - result.notImplemented(); - } - } - - public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) { - MethodChannel channel = getChannel(); - if (channel == null) return; - - if (isDoneCounting && findInteractionController != null && findInteractionController.webView != null) { - findInteractionController.activeFindSession = new FindSession(numberOfMatches, activeMatchOrdinal); - } - - Map obj = new HashMap<>(); - obj.put("activeMatchOrdinal", activeMatchOrdinal); - obj.put("numberOfMatches", numberOfMatches); - obj.put("isDoneCounting", isDoneCounting); - channel.invokeMethod("onFindResultReceived", obj); - } - - @Override - public void dispose() { - super.dispose(); - findInteractionController = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/find_interaction/FindInteractionController.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/find_interaction/FindInteractionController.java deleted file mode 100644 index 64f93427e9..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/find_interaction/FindInteractionController.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.find_interaction; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.types.Disposable; -import com.pichillilorenzo.flutter_inappwebview_android.types.FindSession; -import com.pichillilorenzo.flutter_inappwebview_android.webview.InAppWebViewInterface; - -import io.flutter.plugin.common.MethodChannel; - -public class FindInteractionController implements Disposable { - static final String LOG_TAG = "FindInteractionController"; - public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_find_interaction_"; - - @Nullable - public InAppWebViewInterface webView; - @Nullable - public FindSession activeFindSession; - @Nullable - public FindInteractionChannelDelegate channelDelegate; - @Nullable - public FindInteractionSettings settings; - @Nullable - public String searchText; - - public FindInteractionController(@NonNull InAppWebViewInterface webView, @NonNull InAppWebViewFlutterPlugin plugin, - @NonNull Object id, @Nullable FindInteractionSettings settings) { - this.webView = webView; - this.settings = settings; - final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id); - this.channelDelegate = new FindInteractionChannelDelegate(this, channel); - } - - public void prepare() { - - } - - public void findAll(@Nullable String find) { - if (find == null) { - find = searchText; - } else { - // updated searchText - searchText = find; - } - if (webView != null && find != null) { - webView.findAllAsync(find); - } - } - - public void findNext(boolean forward) { - if (webView != null) { - webView.findNext(forward); - } - } - - public void clearMatches() { - if (webView != null) { - webView.clearMatches(); - } - } - - public void dispose() { - if (channelDelegate != null) { - channelDelegate.dispose(); - channelDelegate = null; - } - webView = null; - activeFindSession = null; - searchText = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/find_interaction/FindInteractionSettings.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/find_interaction/FindInteractionSettings.java deleted file mode 100644 index 1b4d0c6a9d..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/find_interaction/FindInteractionSettings.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.find_interaction; - -import androidx.annotation.NonNull; - -import com.pichillilorenzo.flutter_inappwebview_android.ISettings; - -import java.util.HashMap; -import java.util.Map; - -public class FindInteractionSettings implements ISettings { - public static final String LOG_TAG = "FindInteractionSettings"; - - - @NonNull - @Override - public FindInteractionSettings parse(@NonNull Map settings) { -// for (Map.Entry pair : settings.entrySet()) { -// String key = pair.getKey(); -// Object value = pair.getValue(); -// if (value == null) { -// continue; -// } -// -// switch (key) { -// -// } -// } - - return this; - } - - @NonNull - public Map toMap() { - Map settings = new HashMap<>(); - return settings; - } - - @NonNull - @Override - public Map getRealSettings(@NonNull FindInteractionController findInteractionController) { - Map realSettings = toMap(); - return realSettings; - } - -} \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/headless_in_app_webview/HeadlessInAppWebView.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/headless_in_app_webview/HeadlessInAppWebView.java deleted file mode 100644 index 129c1925dd..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/headless_in_app_webview/HeadlessInAppWebView.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.headless_in_app_webview; - -import android.app.Activity; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.Util; -import com.pichillilorenzo.flutter_inappwebview_android.types.Disposable; -import com.pichillilorenzo.flutter_inappwebview_android.types.Size2D; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.FlutterWebView; - -import java.util.Map; - -import io.flutter.plugin.common.MethodChannel; - -public class HeadlessInAppWebView implements Disposable { - protected static final String LOG_TAG = "HeadlessInAppWebView"; - public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_headless_inappwebview_"; - - @NonNull - public final String id; - @Nullable - public HeadlessWebViewChannelDelegate channelDelegate; - @Nullable - public FlutterWebView flutterWebView; - @Nullable - public InAppWebViewFlutterPlugin plugin; - - public HeadlessInAppWebView(@NonNull final InAppWebViewFlutterPlugin plugin, @NonNull String id, @NonNull FlutterWebView flutterWebView) { - this.id = id; - this.plugin = plugin; - this.flutterWebView = flutterWebView; - final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id); - this.channelDelegate = new HeadlessWebViewChannelDelegate(this, channel); - } - - public void onWebViewCreated() { - if (channelDelegate != null) { - channelDelegate.onWebViewCreated(); - } - } - - public void prepare(Map params) { - if (flutterWebView != null) { - View view = flutterWebView.getView(); - if (view != null) { - final Map initialSize = (Map) params.get("initialSize"); - Size2D size = Size2D.fromMap(initialSize); - if (size == null) { - size = new Size2D(-1, -1); - } - setSize(size); - view.setVisibility(View.INVISIBLE); - } - } - if (plugin != null && plugin.activity != null) { - // Add the headless WebView to the view hierarchy. - // This way is also possible to take screenshots. - ViewGroup contentView = (ViewGroup) plugin.activity.findViewById(android.R.id.content); - if (contentView != null) { - ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0); - if (mainView != null && flutterWebView != null) { - View view = flutterWebView.getView(); - if (view != null) { - mainView.addView(view, 0); - } - } - } - } - } - - public void setSize(@NonNull Size2D size) { - if (flutterWebView != null && flutterWebView.webView != null) { - View view = flutterWebView.getView(); - if (view != null) { - float scale = Util.getPixelDensity(view.getContext()); - Size2D fullscreenSize = Util.getFullscreenSize(view.getContext()); - int width = (int) (size.getWidth() == -1 ? fullscreenSize.getWidth() : (size.getWidth() * scale)); - int height = (int) (size.getWidth() == -1 ? fullscreenSize.getHeight() : (size.getHeight() * scale)); - view.setLayoutParams(new FrameLayout.LayoutParams(width, height)); - } - } - } - - @Nullable - public Size2D getSize() { - if (flutterWebView != null && flutterWebView.webView != null) { - View view = flutterWebView.getView(); - if (view != null) { - float scale = Util.getPixelDensity(view.getContext()); - Size2D fullscreenSize = Util.getFullscreenSize(view.getContext()); - ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); - return new Size2D( - fullscreenSize.getWidth() == layoutParams.width ? layoutParams.width : (layoutParams.width / scale), - fullscreenSize.getHeight() == layoutParams.height ? layoutParams.height : (layoutParams.height / scale) - ); - } - } - return null; - } - - @Nullable - public FlutterWebView disposeAndGetFlutterWebView() { - FlutterWebView newFlutterWebView = flutterWebView; - if (flutterWebView != null) { - View view = flutterWebView.getView(); - if (view != null) { - // restore WebView layout params and visibility - view.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - view.setVisibility(View.VISIBLE); - // remove from parent - ViewGroup parent = (ViewGroup) view.getParent(); - if (parent != null) { - parent.removeView(view); - } - } - // set to null to avoid to be disposed before calling "dispose()" - flutterWebView = null; - dispose(); - } - return newFlutterWebView; - } - - public void dispose() { - if (channelDelegate != null) { - channelDelegate.dispose(); - channelDelegate = null; - } - if (plugin != null) { - HeadlessInAppWebViewManager headlessInAppWebViewManager = plugin.headlessInAppWebViewManager; - if (headlessInAppWebViewManager != null && headlessInAppWebViewManager.webViews.containsKey(id)) { - headlessInAppWebViewManager.webViews.put(id, null); - } - Activity activity = plugin.activity; - if (activity != null) { - ViewGroup contentView = plugin.activity.findViewById(android.R.id.content); - if (contentView != null) { - ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0); - if (mainView != null && flutterWebView != null) { - View view = flutterWebView.getView(); - if (view != null) { - mainView.removeView(flutterWebView.getView()); - } - } - } - } - } - if (flutterWebView != null) { - flutterWebView.dispose(); - } - flutterWebView = null; - plugin = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/headless_in_app_webview/HeadlessInAppWebViewManager.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/headless_in_app_webview/HeadlessInAppWebViewManager.java deleted file mode 100755 index 619e174ff0..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/headless_in_app_webview/HeadlessInAppWebViewManager.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package com.pichillilorenzo.flutter_inappwebview_android.headless_in_app_webview; - -import android.content.Context; - -import androidx.annotation.Nullable; -import androidx.annotation.NonNull; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.FlutterWebView; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; -import io.flutter.plugin.common.MethodChannel.Result; - -public class HeadlessInAppWebViewManager extends ChannelDelegateImpl { - protected static final String LOG_TAG = "HeadlessInAppWebViewManager"; - public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_headless_inappwebview"; - - public final Map webViews = new HashMap<>(); - @Nullable - public InAppWebViewFlutterPlugin plugin; - - public HeadlessInAppWebViewManager(final InAppWebViewFlutterPlugin plugin) { - super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME)); - this.plugin = plugin; - } - - @Override - public void onMethodCall(final MethodCall call, @NonNull final Result result) { - final String id = (String) call.argument("id"); - - switch (call.method) { - case "run": - { - HashMap params = (HashMap) call.argument("params"); - run(id, params); - } - result.success(true); - break; - default: - result.notImplemented(); - } - } - - public void run(String id, HashMap params) { - if (plugin == null || (plugin.activity == null && plugin.applicationContext == null)) return; - Context context = plugin.activity; - if (context == null) { - context = plugin.applicationContext; - } - FlutterWebView flutterWebView = new FlutterWebView(plugin, context, id, params); - HeadlessInAppWebView headlessInAppWebView = new HeadlessInAppWebView(plugin, id, flutterWebView); - webViews.put(id, headlessInAppWebView); - - headlessInAppWebView.prepare(params); - headlessInAppWebView.onWebViewCreated(); - flutterWebView.makeInitialLoad(params); - } - - @Override - public void dispose() { - super.dispose(); - Collection headlessInAppWebViews = webViews.values(); - for (HeadlessInAppWebView headlessInAppWebView : headlessInAppWebViews) { - if (headlessInAppWebView != null) { - headlessInAppWebView.dispose(); - } - } - webViews.clear(); - plugin = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/headless_in_app_webview/HeadlessWebViewChannelDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/headless_in_app_webview/HeadlessWebViewChannelDelegate.java deleted file mode 100644 index 96d922c386..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/headless_in_app_webview/HeadlessWebViewChannelDelegate.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.headless_in_app_webview; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; -import com.pichillilorenzo.flutter_inappwebview_android.types.Size2D; - -import java.util.HashMap; -import java.util.Map; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class HeadlessWebViewChannelDelegate extends ChannelDelegateImpl { - @Nullable - private HeadlessInAppWebView headlessWebView; - - public HeadlessWebViewChannelDelegate(@NonNull HeadlessInAppWebView headlessWebView, @NonNull MethodChannel channel) { - super(channel); - this.headlessWebView = headlessWebView; - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - switch (call.method) { - case "dispose": - if (headlessWebView != null) { - headlessWebView.dispose(); - result.success(true); - } else { - result.success(false); - } - break; - case "setSize": - if (headlessWebView != null) { - Map sizeMap = (Map) call.argument("size"); - Size2D size = Size2D.fromMap(sizeMap); - if (size != null) - headlessWebView.setSize(size); - result.success(true); - } else { - result.success(false); - } - break; - case "getSize": - if (headlessWebView != null) { - Size2D size = headlessWebView.getSize(); - result.success(size != null ? size.toMap() : null); - } else { - result.success(null); - } - break; - default: - result.notImplemented(); - } - } - - public void onWebViewCreated() { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onWebViewCreated", obj); - } - - @Override - public void dispose() { - super.dispose(); - headlessWebView = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/ActivityResultListener.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/ActivityResultListener.java deleted file mode 100644 index a50f333dce..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/ActivityResultListener.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.in_app_browser; - -import android.content.Intent; - -public interface ActivityResultListener { - /** @return true if the result has been handled. */ - boolean onActivityResult(int requestCode, int resultCode, Intent data); -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserActivity.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserActivity.java deleted file mode 100755 index a8fbef9007..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserActivity.java +++ /dev/null @@ -1,680 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.in_app_browser; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.content.Intent; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.os.Build; -import android.os.Bundle; -import android.os.Message; -import android.util.Log; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.webkit.WebView; -import android.widget.ProgressBar; -import android.widget.RelativeLayout; -import android.widget.SearchView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.view.menu.MenuBuilder; -import androidx.appcompat.widget.Toolbar; -import androidx.core.graphics.Insets; -import androidx.core.view.ViewCompat; -import androidx.core.view.WindowCompat; -import androidx.core.view.WindowInsetsCompat; - -import com.pichillilorenzo.flutter_inappwebview_android.R; -import com.pichillilorenzo.flutter_inappwebview_android.Util; -import com.pichillilorenzo.flutter_inappwebview_android.find_interaction.FindInteractionController; -import com.pichillilorenzo.flutter_inappwebview_android.pull_to_refresh.PullToRefreshChannelDelegate; -import com.pichillilorenzo.flutter_inappwebview_android.pull_to_refresh.PullToRefreshLayout; -import com.pichillilorenzo.flutter_inappwebview_android.pull_to_refresh.PullToRefreshSettings; -import com.pichillilorenzo.flutter_inappwebview_android.types.AndroidResource; -import com.pichillilorenzo.flutter_inappwebview_android.types.Disposable; -import com.pichillilorenzo.flutter_inappwebview_android.types.InAppBrowserMenuItem; -import com.pichillilorenzo.flutter_inappwebview_android.types.URLRequest; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserScript; -import com.pichillilorenzo.flutter_inappwebview_android.webview.WebViewChannelDelegate; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.InAppWebView; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.InAppWebViewSettings; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.flutter.plugin.common.MethodChannel; - -public class InAppBrowserActivity extends AppCompatActivity implements InAppBrowserDelegate, Disposable { - protected static final String LOG_TAG = "InAppBrowserActivity"; - public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappbrowser_"; - - @Nullable - public Integer windowId; - public String id; - @Nullable - public InAppWebView webView; - @Nullable - public PullToRefreshLayout pullToRefreshLayout; - @Nullable - public ActionBar actionBar; - @Nullable - public Toolbar toolbar; - @Nullable - public Menu menu; - @Nullable - public SearchView searchView; - public InAppBrowserSettings customSettings = new InAppBrowserSettings(); - @Nullable - public ProgressBar progressBar; - public boolean isHidden = false; - @Nullable - public String fromActivity; - private List activityResultListeners = new ArrayList<>(); - @Nullable - public InAppBrowserManager manager; - @Nullable - public InAppBrowserChannelDelegate channelDelegate; - public List menuItems = new ArrayList<>(); - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Bundle b = getIntent().getExtras(); - if (b == null) { - if (savedInstanceState != null) { - finish(); - } - return; - } - - id = b.getString("id"); - - String managerId = b.getString("managerId"); - manager = InAppBrowserManager.shared.get(managerId); - if (manager == null || manager.plugin == null || manager.plugin.messenger == null) { - if (savedInstanceState != null) { - finish(); - } - return; - } - - Map settingsMap = (Map) b.getSerializable("settings"); - customSettings.parse(settingsMap); - - windowId = b.getInt("windowId"); - - setContentView(R.layout.activity_web_view); - - WindowCompat.setDecorFitsSystemWindows(getWindow(), false); - toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - getWindow().setStatusBarColor(Color.TRANSPARENT); - } - - ViewCompat.setOnApplyWindowInsetsListener(toolbar, (v, insets) -> { - Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.statusBars()); - v.setPadding(v.getPaddingLeft(), systemBars.top, v.getPaddingRight(), v.getPaddingBottom()); - return insets; - }); - - Map pullToRefreshInitialSettings = (Map) b.getSerializable("pullToRefreshInitialSettings"); - MethodChannel pullToRefreshLayoutChannel = new MethodChannel(manager.plugin.messenger, PullToRefreshLayout.METHOD_CHANNEL_NAME_PREFIX + id); - PullToRefreshSettings pullToRefreshSettings = new PullToRefreshSettings(); - pullToRefreshSettings.parse(pullToRefreshInitialSettings); - pullToRefreshLayout = findViewById(R.id.pullToRefresh); - pullToRefreshLayout.channelDelegate = new PullToRefreshChannelDelegate(pullToRefreshLayout, pullToRefreshLayoutChannel); - pullToRefreshLayout.settings = pullToRefreshSettings; - pullToRefreshLayout.prepare(); - - webView = findViewById(R.id.webView); - webView.id = id; - if (windowId != -1) { - webView.windowId = windowId; - } - webView.inAppBrowserDelegate = this; - webView.plugin = manager.plugin; - - FindInteractionController findInteractionController = new FindInteractionController(webView, manager.plugin, id, null); - webView.findInteractionController = findInteractionController; - findInteractionController.prepare(); - - final MethodChannel channel = new MethodChannel(manager.plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id); - channelDelegate = new InAppBrowserChannelDelegate(channel); - webView.channelDelegate = new WebViewChannelDelegate(webView, channel); - - fromActivity = b.getString("fromActivity"); - - Map contextMenu = (Map) b.getSerializable("contextMenu"); - List> initialUserScripts = (List>) b.getSerializable("initialUserScripts"); - List> menuItemList = (List>) b.getSerializable("menuItems"); - for (Map menuItem : menuItemList) { - menuItems.add(InAppBrowserMenuItem.fromMap(menuItem)); - } - - InAppWebViewSettings webViewSettings = new InAppWebViewSettings(); - webViewSettings.parse(settingsMap); - webView.customSettings = webViewSettings; - webView.contextMenu = contextMenu; - - List userScripts = new ArrayList<>(); - if (initialUserScripts != null) { - for (Map initialUserScript : initialUserScripts) { - userScripts.add(UserScript.fromMap(initialUserScript)); - } - } - webView.userContentController.addUserOnlyScripts(userScripts); - - actionBar = getSupportActionBar(); - - prepareView(); - - if (windowId != -1) { - if (webView.plugin != null && webView.plugin.inAppWebViewManager != null) { - Message resultMsg = webView.plugin.inAppWebViewManager.windowWebViewMessages.get(windowId); - if (resultMsg != null) { - ((WebView.WebViewTransport) resultMsg.obj).setWebView(webView); - resultMsg.sendToTarget(); - } - } - } else { - String initialFile = b.getString("initialFile"); - Map initialUrlRequest = (Map) b.getSerializable("initialUrlRequest"); - String initialData = b.getString("initialData"); - if (initialFile != null) { - try { - webView.loadFile(initialFile); - } catch (IOException e) { - Log.e(LOG_TAG, initialFile + " asset file cannot be found!", e); - return; - } - } else if (initialData != null) { - String mimeType = b.getString("initialMimeType"); - String encoding = b.getString("initialEncoding"); - String baseUrl = b.getString("initialBaseUrl"); - String historyUrl = b.getString("initialHistoryUrl"); - webView.loadDataWithBaseURL(baseUrl, initialData, mimeType, encoding, historyUrl); - } else if (initialUrlRequest != null) { - URLRequest urlRequest = URLRequest.fromMap(initialUrlRequest); - if (urlRequest != null) { - webView.loadUrl(urlRequest); - } - } - } - - if (channelDelegate != null) { - channelDelegate.onBrowserCreated(); - } - } - - private void prepareView() { - - if (webView != null) { - webView.prepare(); - } - - if (customSettings.hidden) - hide(); - else - show(); - - progressBar = findViewById(R.id.progressBar); - - if (progressBar != null) { - if (customSettings.hideProgressBar) - progressBar.setMax(0); - else - progressBar.setMax(100); - } - - if (actionBar != null) { - actionBar.setDisplayShowTitleEnabled(!customSettings.hideTitleBar); - - if (customSettings.hideToolbarTop) - actionBar.hide(); - - if (customSettings.toolbarTopBackgroundColor != null && !customSettings.toolbarTopBackgroundColor.isEmpty()) - actionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor(customSettings.toolbarTopBackgroundColor))); - - if (customSettings.toolbarTopFixedTitle != null && !customSettings.toolbarTopFixedTitle.isEmpty()) - actionBar.setTitle(customSettings.toolbarTopFixedTitle); - } - } - - @SuppressLint("RestrictedApi") - @Override - public boolean onCreateOptionsMenu(Menu m) { - menu = m; - - if (actionBar != null && (customSettings.toolbarTopFixedTitle == null || customSettings.toolbarTopFixedTitle.isEmpty())) - actionBar.setTitle(webView != null ? webView.getTitle() : ""); - - if (menu == null) - return super.onCreateOptionsMenu(m); - - if (menu instanceof MenuBuilder) { - ((MenuBuilder) menu).setOptionalIconsVisible(true); - } - - MenuInflater inflater = getMenuInflater(); - try { - // Inflate menu to add items to action bar if it is present. - inflater.inflate(R.menu.menu_main, menu); - } catch (Exception e) { - e.printStackTrace(); - Log.e(LOG_TAG, "Cannot inflate com.pichillilorenzo.flutter_inappwebview_android.R.menu.menu_main." + - "To make it work, you need to set minifyEnabled false and shrinkResources false in your build.gradle file."); - return super.onCreateOptionsMenu(m); - } - - MenuItem menuSearchItem = menu.findItem(R.id.menu_search); - if (menuSearchItem != null) { - if (customSettings.hideUrlBar) - menuSearchItem.setVisible(false); - - searchView = (SearchView) menuSearchItem.getActionView(); - if (searchView != null) { - searchView.setFocusable(true); - - searchView.setQuery(webView != null ? webView.getUrl() : "", false); - - searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { - @Override - public boolean onQueryTextSubmit(String query) { - if (!query.isEmpty()) { - if (webView != null) - webView.loadUrl(query); - if (searchView != null) { - searchView.setQuery("", false); - searchView.setIconified(true); - } - return true; - } - return false; - } - - @Override - public boolean onQueryTextChange(String newText) { - return false; - } - - }); - - searchView.setOnCloseListener(new SearchView.OnCloseListener() { - @Override - public boolean onClose() { - if (searchView != null && searchView.getQuery().toString().isEmpty()) - searchView.setQuery(webView != null ? webView.getUrl() : "", false); - return false; - } - }); - - searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() { - @Override - public void onFocusChange(View view, boolean b) { - if (!b && searchView != null) { - searchView.setQuery("", false); - searchView.setIconified(true); - } - } - }); - } - } - - if (customSettings.hideDefaultMenuItems) { - MenuItem actionClose = menu.findItem(R.id.action_close); - if (actionClose != null) { - actionClose.setVisible(false); - } - MenuItem actionGoBack = menu.findItem(R.id.action_go_back); - if (actionGoBack != null) { - actionGoBack.setVisible(false); - } - MenuItem actionReload = menu.findItem(R.id.action_reload); - if (actionReload != null) { - actionReload.setVisible(false); - } - MenuItem actionGoForward = menu.findItem(R.id.action_go_forward); - if (actionGoForward != null) { - actionGoForward.setVisible(false); - } - MenuItem actionShare = menu.findItem(R.id.action_share); - if (actionShare != null) { - actionShare.setVisible(false); - } - } - - for (final InAppBrowserMenuItem menuItem : menuItems) { - int order = menuItem.getOrder() != null ? menuItem.getOrder() : Menu.NONE; - MenuItem item = menu.add(Menu.NONE, menuItem.getId(), order, menuItem.getTitle()); - if (menuItem.isShowAsAction()) { - item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); - } - Object icon = menuItem.getIcon(); - if (icon != null) { - if (icon instanceof AndroidResource) { - item.setIcon(((AndroidResource) icon).getIdentifier(this)); - } else { - item.setIcon(Util.drawableFromBytes(this, (byte[]) icon)); - } - String iconColor = menuItem.getIconColor(); - if (iconColor != null && !iconColor.isEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - item.getIcon().setTint(Color.parseColor(iconColor)); - } - } - item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(@NonNull MenuItem item) { - if (channelDelegate != null) { - channelDelegate.onMenuItemClicked(menuItem); - } - return true; - } - }); - } - - return true; - } - - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - if (customSettings.shouldCloseOnBackButtonPressed) { - close(null); - return true; - } - if (customSettings.allowGoBackWithBackButton) { - if (canGoBack()) - goBack(); - else if (customSettings.closeOnCannotGoBack) - close(null); - return true; - } - if (!customSettings.shouldCloseOnBackButtonPressed) { - return true; - } - } - return super.onKeyDown(keyCode, event); - } - - public void close(final MethodChannel.Result result) { - if (channelDelegate != null) { - channelDelegate.onExit(); - } - - dispose(); - - if (result != null) { - result.success(true); - } - } - - public void reload() { - if (webView != null) - webView.reload(); - } - - public void goBack() { - if (webView != null && canGoBack()) - webView.goBack(); - } - - public boolean canGoBack() { - if (webView != null) - return webView.canGoBack(); - return false; - } - - public void goForward() { - if (webView != null && canGoForward()) - webView.goForward(); - } - - public boolean canGoForward() { - if (webView != null) - return webView.canGoForward(); - return false; - } - - public void hide() { - if (fromActivity != null) { - try { - isHidden = true; - Intent openActivity = new Intent(this, Class.forName(fromActivity)); - openActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - startActivityIfNeeded(openActivity, 0); - } catch (ClassNotFoundException e) { - Log.d(LOG_TAG, "", e); - } - } - } - - public void show() { - isHidden = false; - Intent openActivity = new Intent(this, InAppBrowserActivity.class); - openActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - startActivityIfNeeded(openActivity, 0); - } - - public void goBackButtonClicked(MenuItem item) { - goBack(); - } - - public void goForwardButtonClicked(MenuItem item) { - goForward(); - } - - public void shareButtonClicked(MenuItem item) { - Intent share = new Intent(Intent.ACTION_SEND); - share.setType("text/plain"); - share.putExtra(Intent.EXTRA_TEXT, webView != null ? webView.getUrl() : ""); - startActivity(Intent.createChooser(share, "Share")); - } - - public void reloadButtonClicked(MenuItem item) { - reload(); - } - - public void closeButtonClicked(MenuItem item) { - close(null); - } - - public void setSettings(InAppBrowserSettings newSettings, HashMap newSettingsMap) { - - InAppWebViewSettings newInAppWebViewSettings = new InAppWebViewSettings(); - newInAppWebViewSettings.parse(newSettingsMap); - if (webView != null) { - webView.setSettings(newInAppWebViewSettings, newSettingsMap); - } - - if (newSettingsMap.get("hidden") != null && customSettings.hidden != newSettings.hidden) { - if (newSettings.hidden) - hide(); - else - show(); - } - - if (newSettingsMap.get("hideProgressBar") != null && customSettings.hideProgressBar != newSettings.hideProgressBar && progressBar != null) { - if (newSettings.hideProgressBar) - progressBar.setMax(0); - else - progressBar.setMax(100); - } - - if (actionBar != null && newSettingsMap.get("hideTitleBar") != null && customSettings.hideTitleBar != newSettings.hideTitleBar) - actionBar.setDisplayShowTitleEnabled(!newSettings.hideTitleBar); - - if (actionBar != null && newSettingsMap.get("hideToolbarTop") != null && customSettings.hideToolbarTop != newSettings.hideToolbarTop) { - if (newSettings.hideToolbarTop) - actionBar.hide(); - else - actionBar.show(); - } - - if (actionBar != null && newSettingsMap.get("toolbarTopBackgroundColor") != null && - !Util.objEquals(customSettings.toolbarTopBackgroundColor, newSettings.toolbarTopBackgroundColor) && - newSettings.toolbarTopBackgroundColor != null && !newSettings.toolbarTopBackgroundColor.isEmpty()) - actionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor(newSettings.toolbarTopBackgroundColor))); - - if (actionBar != null && newSettingsMap.get("toolbarTopFixedTitle") != null && - !Util.objEquals(customSettings.toolbarTopFixedTitle, newSettings.toolbarTopFixedTitle) && - newSettings.toolbarTopFixedTitle != null && !newSettings.toolbarTopFixedTitle.isEmpty()) - actionBar.setTitle(newSettings.toolbarTopFixedTitle); - - if (menu != null && newSettingsMap.get("hideUrlBar") != null && customSettings.hideUrlBar != newSettings.hideUrlBar) { - MenuItem menuSearchItem = menu.findItem(R.id.menu_search); - if (menuSearchItem != null) { - menuSearchItem.setVisible(!newSettings.hideUrlBar); - } - } - - if (menu != null && newSettingsMap.get("hideDefaultMenuItems") != null && customSettings.hideDefaultMenuItems != newSettings.hideDefaultMenuItems) { - MenuItem actionClose = menu.findItem(R.id.action_close); - if (actionClose != null) { - actionClose.setVisible(!newSettings.hideDefaultMenuItems); - } - MenuItem actionGoBack = menu.findItem(R.id.action_go_back); - if (actionGoBack != null) { - actionGoBack.setVisible(!newSettings.hideDefaultMenuItems); - } - MenuItem actionReload = menu.findItem(R.id.action_reload); - if (actionReload != null) { - actionReload.setVisible(!newSettings.hideDefaultMenuItems); - } - MenuItem actionGoForward = menu.findItem(R.id.action_go_forward); - if (actionGoForward != null) { - actionGoForward.setVisible(!newSettings.hideDefaultMenuItems); - } - MenuItem actionShare = menu.findItem(R.id.action_share); - if (actionShare != null) { - actionShare.setVisible(!newSettings.hideDefaultMenuItems); - } - } - - customSettings = newSettings; - } - - public Map getCustomSettingsMap() { - Map webViewSettingsMap = webView != null ? webView.getCustomSettingsMap() : null; - if (customSettings == null || webViewSettingsMap == null) - return null; - - Map settingsMap = customSettings.getRealSettings(this); - settingsMap.putAll(webViewSettingsMap); - return settingsMap; - } - - @Override - public Activity getActivity() { - return this; - } - - @Override - public void didChangeTitle(String title) { - if (actionBar != null && (customSettings.toolbarTopFixedTitle == null || customSettings.toolbarTopFixedTitle.isEmpty())) { - actionBar.setTitle(title); - } - } - - @Override - public void didStartNavigation(String url) { - if (progressBar != null) { - progressBar.setProgress(0); - } - if (searchView != null) { - searchView.setQuery(url, false); - } - } - - @Override - public void didUpdateVisitedHistory(String url) { - if (searchView != null) { - searchView.setQuery(url, false); - } - } - - @Override - public void didFinishNavigation(String url) { - if (searchView != null) { - searchView.setQuery(url, false); - } - if (progressBar != null) { - progressBar.setProgress(0); - } - } - - @Override - public void didFailNavigation(String url, int errorCode, String description) { - if (progressBar != null) { - progressBar.setProgress(0); - } - } - - @Override - public void didChangeProgress(int progress) { - if (progressBar != null) { - progressBar.setVisibility(View.VISIBLE); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - progressBar.setProgress(progress, true); - } else { - progressBar.setProgress(progress); - } - if (progress == 100) { - progressBar.setVisibility(View.GONE); - } - } - } - - public List getActivityResultListeners() { - return activityResultListeners; - } - - @Override - protected void onActivityResult(int requestCode, - int resultCode, - Intent data) { - for (ActivityResultListener listener : activityResultListeners) { - if (listener.onActivityResult(requestCode, resultCode, data)) { - return; - } - } - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - public void dispose() { - if (channelDelegate != null) { - channelDelegate.dispose(); - channelDelegate = null; - } - activityResultListeners.clear(); - if (webView != null) { - if (manager != null && manager.plugin != null && - manager.plugin.activityPluginBinding != null && webView.inAppWebViewChromeClient != null) { - manager.plugin.activityPluginBinding.removeActivityResultListener(webView.inAppWebViewChromeClient); - } - RelativeLayout containerView = (RelativeLayout) findViewById(R.id.container); - if (containerView != null) { - containerView.removeAllViews(); - } - webView.dispose(); - webView = null; - finish(); - } - } - - @Override - public void onDestroy() { - dispose(); - super.onDestroy(); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserChannelDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserChannelDelegate.java deleted file mode 100644 index 7f4ec377d5..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserChannelDelegate.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.in_app_browser; - -import androidx.annotation.NonNull; - -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; -import com.pichillilorenzo.flutter_inappwebview_android.types.InAppBrowserMenuItem; - -import java.util.HashMap; -import java.util.Map; - -import io.flutter.plugin.common.MethodChannel; - -public class InAppBrowserChannelDelegate extends ChannelDelegateImpl { - public InAppBrowserChannelDelegate(@NonNull MethodChannel channel) { - super(channel); - } - - public void onBrowserCreated() { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onBrowserCreated", obj); - } - - public void onMenuItemClicked(InAppBrowserMenuItem menuItem) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("id", menuItem.getId()); - channel.invokeMethod("onMenuItemClicked", obj); - } - - public void onExit() { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onExit", obj); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserDelegate.java deleted file mode 100644 index 514866ff9d..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserDelegate.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.in_app_browser; - -import android.app.Activity; - -import java.util.List; - -public interface InAppBrowserDelegate { - Activity getActivity(); - List getActivityResultListeners(); - void didChangeTitle(String title); - void didStartNavigation(String url); - void didUpdateVisitedHistory(String url); - void didFinishNavigation(String url); - void didFailNavigation(String url, int errorCode, String description); - void didChangeProgress(int progress); -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserManager.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserManager.java deleted file mode 100755 index b2d648ea33..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserManager.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package com.pichillilorenzo.flutter_inappwebview_android.in_app_browser; - -import android.app.Activity; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.net.Uri; -import android.os.Bundle; -import android.os.Parcelable; -import android.provider.Browser; -import android.util.Log; -import android.webkit.MimeTypeMap; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; -import io.flutter.plugin.common.MethodChannel.Result; - -/** - * InAppBrowserManager - */ -public class InAppBrowserManager extends ChannelDelegateImpl { - protected static final String LOG_TAG = "InAppBrowserManager"; - public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappbrowser"; - - @Nullable - public InAppWebViewFlutterPlugin plugin; - public String id; - public static final Map shared = new HashMap<>(); - - public InAppBrowserManager(final InAppWebViewFlutterPlugin plugin) { - super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME)); - this.id = UUID.randomUUID().toString(); - this.plugin = plugin; - shared.put(this.id, this); - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - switch (call.method) { - case "open": - if (plugin != null && plugin.activity != null) { - open(plugin.activity, (Map) call.arguments()); - result.success(true); - } else { - result.success(false); - } - break; - case "openWithSystemBrowser": - if (plugin != null && plugin.activity != null) { - String url = (String) call.argument("url"); - openWithSystemBrowser(plugin.activity, url, result); - } else { - result.success(false); - } - break; - default: - result.notImplemented(); - } - } - - public static String getMimeType(String url) { - String type = null; - String extension = MimeTypeMap.getFileExtensionFromUrl(url); - if (extension != null) { - type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); - } - return type; - } - - /** - * Display a new browser with the specified URL. - * - * @param url the url to load. - * @param result - * @return "" if ok, or error message. - */ - public void openWithSystemBrowser(Activity activity, String url, Result result) { - try { - Intent intent; - intent = new Intent(Intent.ACTION_VIEW); - // Omitting the MIME type for file: URLs causes "No Activity found to handle Intent". - // Adding the MIME type to http: URLs causes them to not be handled by the downloader. - Uri uri = Uri.parse(url); - if ("file".equals(uri.getScheme())) { - intent.setDataAndType(uri, getMimeType(url)); - } else { - intent.setData(uri); - } - intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName()); - // CB-10795: Avoid circular loops by preventing it from opening in the current app - this.openExternalExcludeCurrentApp(activity, intent); - result.success(true); - // not catching FileUriExposedException explicitly because buildtools<24 doesn't know about it - } catch (java.lang.RuntimeException e) { - Log.d(LOG_TAG, url + " cannot be opened: " + e.toString()); - result.error(LOG_TAG, url + " cannot be opened!", null); - } - } - - /** - * Opens the intent, providing a chooser that excludes the current app to avoid - * circular loops. - */ - public void openExternalExcludeCurrentApp(Activity activity, Intent intent) { - String currentPackage = activity.getPackageName(); - boolean hasCurrentPackage = false; - PackageManager pm = activity.getPackageManager(); - List activities = pm.queryIntentActivities(intent, 0); - ArrayList targetIntents = new ArrayList(); - for (ResolveInfo ri : activities) { - if (!currentPackage.equals(ri.activityInfo.packageName)) { - Intent targetIntent = (Intent) intent.clone(); - targetIntent.setPackage(ri.activityInfo.packageName); - targetIntents.add(targetIntent); - } else { - hasCurrentPackage = true; - } - } - // If the current app package isn't a target for this URL, then use - // the normal launch behavior - if (!hasCurrentPackage || targetIntents.size() == 0) { - activity.startActivity(intent); - } - // If there's only one possible intent, launch it directly - else if (targetIntents.size() == 1) { - activity.startActivity(targetIntents.get(0)); - } - // Otherwise, show a custom chooser without the current app listed - else if (targetIntents.size() > 0) { - Intent chooser = Intent.createChooser(targetIntents.remove(targetIntents.size() - 1), null); - chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[]{})); - activity.startActivity(chooser); - } - } - - public void open(Activity activity, Map arguments) { - String id = (String) arguments.get("id"); - Map urlRequest = (Map) arguments.get("urlRequest"); - String assetFilePath = (String) arguments.get("assetFilePath"); - String data = (String) arguments.get("data"); - String mimeType = (String) arguments.get("mimeType"); - String encoding = (String) arguments.get("encoding"); - String baseUrl = (String) arguments.get("baseUrl"); - String historyUrl = (String) arguments.get("historyUrl"); - Map settings = (Map) arguments.get("settings"); - Map contextMenu = (Map) arguments.get("contextMenu"); - Integer windowId = (Integer) arguments.get("windowId"); - List> initialUserScripts = (List>) arguments.get("initialUserScripts"); - Map pullToRefreshInitialSettings = (Map) arguments.get("pullToRefreshSettings"); - List> menuItems = (List>) arguments.get("menuItems"); - - Bundle extras = new Bundle(); - extras.putString("fromActivity", activity.getClass().getName()); - extras.putSerializable("initialUrlRequest", (Serializable) urlRequest); - extras.putString("initialFile", assetFilePath); - extras.putString("initialData", data); - extras.putString("initialMimeType", mimeType); - extras.putString("initialEncoding", encoding); - extras.putString("initialBaseUrl", baseUrl); - extras.putString("initialHistoryUrl", historyUrl); - extras.putString("id", id); - extras.putString("managerId", this.id); - extras.putSerializable("settings", (Serializable) settings); - extras.putSerializable("contextMenu", (Serializable) contextMenu); - extras.putInt("windowId", windowId != null ? windowId : -1); - extras.putSerializable("initialUserScripts", (Serializable) initialUserScripts); - extras.putSerializable("pullToRefreshInitialSettings", (Serializable) pullToRefreshInitialSettings); - extras.putSerializable("menuItems", (Serializable) menuItems); - startInAppBrowserActivity(activity, extras); - } - - public void startInAppBrowserActivity(Activity activity, Bundle extras) { - Intent intent = new Intent(activity, InAppBrowserActivity.class); - if (extras != null) - intent.putExtras(extras); - activity.startActivity(intent); - } - - @Override - public void dispose() { - super.dispose(); - shared.remove(this.id); - plugin = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserSettings.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserSettings.java deleted file mode 100755 index bdec8217ad..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserSettings.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.in_app_browser; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.ISettings; -import com.pichillilorenzo.flutter_inappwebview_android.R; - -import java.util.HashMap; -import java.util.Map; - -public class InAppBrowserSettings implements ISettings { - - public static final String LOG_TAG = "InAppBrowserSettings"; - - public Boolean hidden = false; - public Boolean hideToolbarTop = false; - @Nullable - public String toolbarTopBackgroundColor; - @Nullable - public String toolbarTopFixedTitle; - public Boolean hideUrlBar = false; - public Boolean hideProgressBar = false; - - public Boolean hideTitleBar = false; - public Boolean closeOnCannotGoBack = true; - public Boolean allowGoBackWithBackButton = true; - public Boolean shouldCloseOnBackButtonPressed = false; - public Boolean hideDefaultMenuItems = false; - - @NonNull - @Override - public InAppBrowserSettings parse(@NonNull Map settings) { - for (Map.Entry pair : settings.entrySet()) { - String key = pair.getKey(); - Object value = pair.getValue(); - if (value == null) { - continue; - } - - switch (key) { - case "hidden": - hidden = (Boolean) value; - break; - case "hideToolbarTop": - hideToolbarTop = (Boolean) value; - break; - case "toolbarTopBackgroundColor": - toolbarTopBackgroundColor = (String) value; - break; - case "toolbarTopFixedTitle": - toolbarTopFixedTitle = (String) value; - break; - case "hideUrlBar": - hideUrlBar = (Boolean) value; - break; - case "hideTitleBar": - hideTitleBar = (Boolean) value; - break; - case "closeOnCannotGoBack": - closeOnCannotGoBack = (Boolean) value; - break; - case "hideProgressBar": - hideProgressBar = (Boolean) value; - break; - case "allowGoBackWithBackButton": - allowGoBackWithBackButton = (Boolean) value; - break; - case "shouldCloseOnBackButtonPressed": - shouldCloseOnBackButtonPressed = (Boolean) value; - break; - case "hideDefaultMenuItems": - hideDefaultMenuItems = (Boolean) value; - break; - } - } - - return this; - } - - @NonNull - @Override - public Map toMap() { - Map settings = new HashMap<>(); - settings.put("hidden", hidden); - settings.put("hideToolbarTop", hideToolbarTop); - settings.put("toolbarTopBackgroundColor", toolbarTopBackgroundColor); - settings.put("toolbarTopFixedTitle", toolbarTopFixedTitle); - settings.put("hideUrlBar", hideUrlBar); - settings.put("hideTitleBar", hideTitleBar); - settings.put("closeOnCannotGoBack", closeOnCannotGoBack); - settings.put("hideProgressBar", hideProgressBar); - settings.put("allowGoBackWithBackButton", allowGoBackWithBackButton); - settings.put("shouldCloseOnBackButtonPressed", shouldCloseOnBackButtonPressed); - settings.put("hideDefaultMenuItems", hideDefaultMenuItems); - return settings; - } - - @NonNull - @Override - public Map getRealSettings(@NonNull InAppBrowserActivity inAppBrowserActivity) { - Map realSettings = toMap(); - realSettings.put("hidden", inAppBrowserActivity.isHidden); - realSettings.put("hideToolbarTop", inAppBrowserActivity.actionBar == null || !inAppBrowserActivity.actionBar.isShowing()); - realSettings.put("hideUrlBar", inAppBrowserActivity.menu == null || !inAppBrowserActivity.menu.findItem(R.id.menu_search).isVisible()); - realSettings.put("hideProgressBar", inAppBrowserActivity.progressBar == null || inAppBrowserActivity.progressBar.getMax() == 0); - return realSettings; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/InterceptAjaxRequestJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/InterceptAjaxRequestJS.java deleted file mode 100644 index 8ac66dcb4f..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/InterceptAjaxRequestJS.java +++ /dev/null @@ -1,303 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; - -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; - -import java.util.Set; - -public class InterceptAjaxRequestJS { - - public static final String INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT"; - - public static String FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() { - return - JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "._useShouldInterceptAjaxRequest"; - } - - public static String FLAG_VARIABLE_FOR_ON_AJAX_READY_STATE_CHANGE() { - return JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "._useOnAjaxReadyStateChange"; - } - - public static String FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS() { - return JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "._useOnAjaxProgress"; - } - - public static String FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE() { - return - JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "._interceptOnlyAsyncAjaxRequests"; - } - - public static PluginScript INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules, - boolean forMainFrameOnly, - boolean initialUseOnAjaxReadyStateChange, - boolean initialUseOnAjaxProgress) { - return - new PluginScript( - InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, - InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_SOURCE(initialUseOnAjaxReadyStateChange, initialUseOnAjaxProgress), - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - true, - allowedOriginRules, - forMainFrameOnly - ); - } - - public static PluginScript createInterceptOnlyAsyncAjaxRequestsPluginScript(boolean onlyAsync) { - return new PluginScript( - InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, - "window." + FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE() + " = " + onlyAsync + ";", - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - true, - null, - false - ); - } - - public static String INTERCEPT_AJAX_REQUEST_JS_SOURCE(boolean initialUseOnAjaxReadyStateChange, boolean initialUseOnAjaxProgress) { - return - "(function(ajax) {" + - " var w = (window.top == null || window.top === window) ? window : window.top;" + - " w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() + " = true;" + - " w." + FLAG_VARIABLE_FOR_ON_AJAX_READY_STATE_CHANGE() + " = " + initialUseOnAjaxReadyStateChange + ";" + - " w." + FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS() + " = " + initialUseOnAjaxProgress + ";" + - " var send = ajax.prototype.send;" + - " var open = ajax.prototype.open;" + - " var setRequestHeader = ajax.prototype.setRequestHeader;" + - " ajax.prototype._flutter_inappwebview_url = null;" + - " ajax.prototype._flutter_inappwebview_method = null;" + - " ajax.prototype._flutter_inappwebview_isAsync = null;" + - " ajax.prototype._flutter_inappwebview_user = null;" + - " ajax.prototype._flutter_inappwebview_password = null;" + - " ajax.prototype._flutter_inappwebview_password = null;" + - " ajax.prototype._flutter_inappwebview_already_onreadystatechange_wrapped = false;" + - " ajax.prototype._flutter_inappwebview_request_headers = {};" + - " function convertRequestResponse(request, callback) {" + - " if (request.response != null && request.responseType != null) {" + - " switch (request.responseType) {" + - " case 'arraybuffer':" + - " callback(new Uint8Array(request.response));" + - " return;" + - " case 'blob':" + - " const reader = new FileReader();" + - " reader.addEventListener('loadend', function() { " + - " callback(new Uint8Array(reader.result));" + - " });" + - " reader.readAsArrayBuffer(blob);" + - " return;" + - " case 'document':" + - " callback(request.response.documentElement.outerHTML);" + - " return;" + - " case 'json':" + - " callback(request.response);" + - " return;" + - " };" + - " }" + - " callback(null);" + - " };" + - " ajax.prototype.open = function(method, url, isAsync, user, password) {" + - " isAsync = (isAsync != null) ? isAsync : true;" + - " this._flutter_inappwebview_url = url;" + - " this._flutter_inappwebview_method = method;" + - " this._flutter_inappwebview_isAsync = isAsync;" + - " this._flutter_inappwebview_user = user;" + - " this._flutter_inappwebview_password = password;" + - " this._flutter_inappwebview_request_headers = {};" + - " open.call(this, method, url, isAsync, user, password);" + - " };" + - " ajax.prototype.setRequestHeader = function(header, value) {" + - " this._flutter_inappwebview_request_headers[header] = value;" + - " setRequestHeader.call(this, header, value);" + - " };" + - " function handleEvent(e) {" + - " var w = (window.top == null || window.top === window) ? window : window.top;" + - " if (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() + " === false || w." + FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS() + " == null || w." + FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS() + " === false) {" + - " return;" + - " }" + - " var self = this;" + - " if (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() + " == true) {" + - " var headers = this.getAllResponseHeaders();" + - " var responseHeaders = {};" + - " if (headers != null) {" + - " var arr = headers.trim().split(/[\\r\\n]+/);" + - " arr.forEach(function (line) {" + - " var parts = line.split(': ');" + - " var header = parts.shift();" + - " var value = parts.join(': ');" + - " responseHeaders[header] = value;" + - " });" + - " }" + - " convertRequestResponse(this, function(response) {" + - " var ajaxRequest = {" + - " method: self._flutter_inappwebview_method," + - " url: self._flutter_inappwebview_url," + - " isAsync: self._flutter_inappwebview_isAsync," + - " user: self._flutter_inappwebview_user," + - " password: self._flutter_inappwebview_password," + - " withCredentials: self.withCredentials," + - " headers: self._flutter_inappwebview_request_headers," + - " readyState: self.readyState," + - " status: self.status," + - " responseURL: self.responseURL," + - " responseType: self.responseType," + - " response: response," + - " responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null," + - " responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null," + - " statusText: self.statusText," + - " responseHeaders, responseHeaders," + - " event: {" + - " type: e.type," + - " loaded: e.loaded," + - " lengthComputable: e.lengthComputable," + - " total: e.total" + - " }" + - " };" + - " window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onAjaxProgress', ajaxRequest).then(function(result) {" + - " if (result != null) {" + - " switch (result) {" + - " case 0:" + - " self.abort();" + - " return;" + - " };" + - " }" + - " });" + - " });" + - " }" + - " };" + - " ajax.prototype.send = function(data) {" + - " var self = this;" + - " var w = (window.top == null || window.top === window) ? window : window.top;" + - " var canBeIntercepted = self._flutter_inappwebview_isAsync || w." + FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE() + " === false;" + - " if (canBeIntercepted && (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() + " == true)) {" + - " if (w." + FLAG_VARIABLE_FOR_ON_AJAX_READY_STATE_CHANGE() + " === true && !this._flutter_inappwebview_already_onreadystatechange_wrapped) {" + - " this._flutter_inappwebview_already_onreadystatechange_wrapped = true;" + - " var realOnreadystatechange = this.onreadystatechange;" + - " this.onreadystatechange = function() {" + - " var w = (window.top == null || window.top === window) ? window : window.top;" + - " if (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() + " == true) {" + - " var headers = this.getAllResponseHeaders();" + - " var responseHeaders = {};" + - " if (headers != null) {" + - " var arr = headers.trim().split(/[\\r\\n]+/);" + - " arr.forEach(function (line) {" + - " var parts = line.split(': ');" + - " var header = parts.shift();" + - " var value = parts.join(': ');" + - " responseHeaders[header] = value;" + - " });" + - " }" + - " convertRequestResponse(this, function(response) {" + - " var ajaxRequest = {" + - " method: self._flutter_inappwebview_method," + - " url: self._flutter_inappwebview_url," + - " isAsync: self._flutter_inappwebview_isAsync," + - " user: self._flutter_inappwebview_user," + - " password: self._flutter_inappwebview_password," + - " withCredentials: self.withCredentials," + - " headers: self._flutter_inappwebview_request_headers," + - " readyState: self.readyState," + - " status: self.status," + - " responseURL: self.responseURL," + - " responseType: self.responseType," + - " response: response," + - " responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null," + - " responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null," + - " statusText: self.statusText," + - " responseHeaders: responseHeaders" + - " };" + - " window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onAjaxReadyStateChange', ajaxRequest).then(function(result) {" + - " if (result != null) {" + - " switch (result) {" + - " case 0:" + - " self.abort();" + - " return;" + - " };" + - " }" + - " if (realOnreadystatechange != null) {" + - " realOnreadystatechange();" + - " }" + - " });" + - " });" + - " } else if (realOnreadystatechange != null) {" + - " realOnreadystatechange();" + - " }" + - " };" + - " }" + - " this.addEventListener('loadstart', handleEvent);" + - " this.addEventListener('load', handleEvent);" + - " this.addEventListener('loadend', handleEvent);" + - " this.addEventListener('progress', handleEvent);" + - " this.addEventListener('error', handleEvent);" + - " this.addEventListener('abort', handleEvent);" + - " this.addEventListener('timeout', handleEvent);" + - " " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".convertBodyRequest(data).then(function(data) {" + - " var ajaxRequest = {" + - " data: data," + - " method: self._flutter_inappwebview_method," + - " url: self._flutter_inappwebview_url," + - " isAsync: self._flutter_inappwebview_isAsync," + - " user: self._flutter_inappwebview_user," + - " password: self._flutter_inappwebview_password," + - " withCredentials: self.withCredentials," + - " headers: self._flutter_inappwebview_request_headers," + - " responseType: self.responseType" + - " };" + - " window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler('shouldInterceptAjaxRequest', ajaxRequest).then(function(result) {" + - " if (result != null) {" + - " switch (result) {" + - " case 0:" + - " self.abort();" + - " return;" + - " };" + - " if (result.data != null && !" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".isString(result.data) && result.data.length > 0) {" + - " var bodyString = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".arrayBufferToString(result.data);" + - " if (" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".isBodyFormData(bodyString)) {" + - " var formDataContentType = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".getFormDataContentType(bodyString);" + - " if (result.headers != null) {" + - " result.headers['Content-Type'] = result.headers['Content-Type'] == null ? formDataContentType : result.headers['Content-Type'];" + - " } else {" + - " result.headers = { 'Content-Type': formDataContentType };" + - " }" + - " }" + - " }" + - " if (" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".isString(result.data) || result.data == null) {" + - " data = result.data;" + - " } else if (result.data.length > 0) {" + - " data = new Uint8Array(result.data);" + - " }" + - " self.withCredentials = result.withCredentials;" + - " if (result.responseType != null && self._flutter_inappwebview_isAsync) {" + - " self.responseType = result.responseType;" + - " };" + - " for (var header in result.headers) {" + - " var value = result.headers[header];" + - " var flutter_inappwebview_value = self._flutter_inappwebview_request_headers[header];" + - " if (flutter_inappwebview_value == null) {" + - " self._flutter_inappwebview_request_headers[header] = value;" + - " } else {" + - " self._flutter_inappwebview_request_headers[header] += ', ' + value;" + - " }" + - " setRequestHeader.call(self, header, value);" + - " };" + - " if ((self._flutter_inappwebview_method != result.method && result.method != null) ||" + - " (self._flutter_inappwebview_url != result.url && result.url != null) ||" + - " (self._flutter_inappwebview_isAsync != result.isAsync && result.isAsync != null) ||" + - " (self._flutter_inappwebview_user != result.user && result.user != null) ||" + - " (self._flutter_inappwebview_password != result.password && result.password != null)) {" + - " self.abort();" + - " self.open(result.method, result.url, result.isAsync, result.user, result.password);" + - " }" + - " }" + - " send.call(self, data);" + - " });" + - " });" + - " } else {" + - " send.call(this, data);" + - " }" + - " };" + - "})(window.XMLHttpRequest);"; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/InterceptFetchRequestJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/InterceptFetchRequestJS.java deleted file mode 100644 index 4547179852..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/InterceptFetchRequestJS.java +++ /dev/null @@ -1,166 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; - -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; - -import java.util.Set; - -public class InterceptFetchRequestJS { - - public static final String INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT"; - - public static String FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE() { - return JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "._useShouldInterceptFetchRequest"; - } - - public static PluginScript INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules, - boolean forMainFrameOnly) { - return new PluginScript( - InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, - InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_SOURCE(), - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - true, - allowedOriginRules, - forMainFrameOnly - ); - } - - public static String INTERCEPT_FETCH_REQUEST_JS_SOURCE() { - return "(function(fetch) {" + - " var w = (window.top == null || window.top === window) ? window : window.top;" + - " w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE() + " = true;" + - " if (fetch == null) {" + - " return;" + - " }" + - " window.fetch = async function(resource, init) {" + - " var w = (window.top == null || window.top === window) ? window : window.top;" + - " if (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE() + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE() + " == true) {" + - " var fetchRequest = {" + - " url: null," + - " method: null," + - " headers: null," + - " body: null," + - " mode: null," + - " credentials: null," + - " cache: null," + - " redirect: null," + - " referrer: null," + - " referrerPolicy: null," + - " integrity: null," + - " keepalive: null" + - " };" + - " if (resource instanceof Request) {" + - " fetchRequest.url = resource.url;" + - " fetchRequest.method = resource.method;" + - " fetchRequest.headers = resource.headers;" + - " fetchRequest.body = resource.body;" + - " fetchRequest.mode = resource.mode;" + - " fetchRequest.credentials = resource.credentials;" + - " fetchRequest.cache = resource.cache;" + - " fetchRequest.redirect = resource.redirect;" + - " fetchRequest.referrer = resource.referrer;" + - " fetchRequest.referrerPolicy = resource.referrerPolicy;" + - " fetchRequest.integrity = resource.integrity;" + - " fetchRequest.keepalive = resource.keepalive;" + - " } else {" + - " fetchRequest.url = resource != null ? resource.toString() : null;" + - " if (init != null) {" + - " fetchRequest.method = init.method;" + - " fetchRequest.headers = init.headers;" + - " fetchRequest.body = init.body;" + - " fetchRequest.mode = init.mode;" + - " fetchRequest.credentials = init.credentials;" + - " fetchRequest.cache = init.cache;" + - " fetchRequest.redirect = init.redirect;" + - " fetchRequest.referrer = init.referrer;" + - " fetchRequest.referrerPolicy = init.referrerPolicy;" + - " fetchRequest.integrity = init.integrity;" + - " fetchRequest.keepalive = init.keepalive;" + - " }" + - " }" + - " if (fetchRequest.headers instanceof Headers) {" + - " fetchRequest.headers = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".convertHeadersToJson(fetchRequest.headers);" + - " }" + - " fetchRequest.credentials = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".convertCredentialsToJson(fetchRequest.credentials);" + - " return " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".convertBodyRequest(fetchRequest.body).then(function(body) {" + - " fetchRequest.body = body;" + - " return window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler('shouldInterceptFetchRequest', fetchRequest).then(function(result) {" + - " if (result != null) {" + - " switch (result.action) {" + - " case 0:" + - " var controller = new AbortController();" + - " if (init != null) {" + - " init.signal = controller.signal;" + - " } else {" + - " init = {" + - " signal: controller.signal" + - " };" + - " }" + - " controller.abort();" + - " break;" + - " }" + - " if (result.body != null && !" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".isString(result.body) && result.body.length > 0) {" + - " var bodyString = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".arrayBufferToString(result.body);" + - " if (" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".isBodyFormData(bodyString)) {" + - " var formDataContentType = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".getFormDataContentType(bodyString);" + - " if (result.headers != null) {" + - " result.headers['Content-Type'] = result.headers['Content-Type'] == null ? formDataContentType : result.headers['Content-Type'];" + - " } else {" + - " result.headers = { 'Content-Type': formDataContentType };" + - " }" + - " }" + - " }" + - " resource = result.url;" + - " if (init == null) {" + - " init = {};" + - " }" + - " if (result.method != null && result.method.length > 0) {" + - " init.method = result.method;" + - " }" + - " if (result.headers != null && Object.keys(result.headers).length > 0) {" + - " init.headers = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".convertJsonToHeaders(result.headers);" + - " }" + - " if (" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".isString(result.body) || result.body == null) {" + - " init.body = result.body;" + - " } else if (result.body.length > 0) {" + - " init.body = new Uint8Array(result.body);" + - " }" + - " if (result.mode != null && result.mode.length > 0) {" + - " init.mode = result.mode;" + - " }" + - " if (result.credentials != null) {" + - " init.credentials = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".convertJsonToCredential(result.credentials);" + - " }" + - " if (result.cache != null && result.cache.length > 0) {" + - " init.cache = result.cache;" + - " }" + - " if (result.redirect != null && result.redirect.length > 0) {" + - " init.redirect = result.redirect;" + - " }" + - " if (result.referrer != null && result.referrer.length > 0) {" + - " init.referrer = result.referrer;" + - " }" + - " if (result.referrerPolicy != null && result.referrerPolicy.length > 0) {" + - " init.referrerPolicy = result.referrerPolicy;" + - " }" + - " if (result.integrity != null && result.integrity.length > 0) {" + - " init.integrity = result.integrity;" + - " }" + - " if (result.keepalive != null) {" + - " init.keepalive = result.keepalive;" + - " }" + - " return fetch(resource, init);" + - " }" + - " return fetch(resource, init);" + - " });" + - " });" + - " } else {" + - " return fetch(resource, init);" + - " }" + - " };" + - "})(window.fetch);"; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/JavaScriptBridgeJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/JavaScriptBridgeJS.java deleted file mode 100644 index d9d4552045..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/JavaScriptBridgeJS.java +++ /dev/null @@ -1,367 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.Util; -import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; - -import java.util.Set; - -public class JavaScriptBridgeJS { - @NonNull - private static String _JAVASCRIPT_BRIDGE_NAME = "flutter_inappwebview"; - - public static void set_JAVASCRIPT_BRIDGE_NAME(@NonNull String bridgeName) { - _JAVASCRIPT_BRIDGE_NAME = bridgeName; - } - - @NonNull - public static String get_JAVASCRIPT_BRIDGE_NAME() { - return _JAVASCRIPT_BRIDGE_NAME; - } - - public static final String JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT"; - - private static final String VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET = "$IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_BRIDGE_SECRET"; - - public static PluginScript JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT(@NonNull String expectedBridgeSecret, - @Nullable Set allowedOriginRules, - boolean forMainFrameOnly) { - String source = Util.replaceAll(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_SOURCE(), VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET, expectedBridgeSecret); - return new PluginScript( - JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME, - source, - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - true, - allowedOriginRules, - forMainFrameOnly - ); - } - - public static String JAVASCRIPT_UTIL_VAR_NAME() { - return "window." + get_JAVASCRIPT_BRIDGE_NAME() + "._Util"; - } - - public static String WEB_MESSAGE_CHANNELS_VARIABLE_NAME() { - return "window." + get_JAVASCRIPT_BRIDGE_NAME() + "._webMessageChannels"; - } - - public static String UTIL_JS_SOURCE() { - return JAVASCRIPT_UTIL_VAR_NAME() + " = {" + - " support: {" + - " searchParams: 'URLSearchParams' in window," + - " iterable: 'Symbol' in window && 'iterator' in Symbol," + - " blob:" + - " 'FileReader' in window &&" + - " 'Blob' in window &&" + - " (function() {" + - " try {" + - " new Blob();" + - " return true;" + - " } catch (e) {" + - " return false;" + - " }" + - " })()," + - " formData: 'FormData' in window," + - " arrayBuffer: 'ArrayBuffer' in window" + - " }," + - " isDataView: function(obj) {" + - " return obj && DataView.prototype.isPrototypeOf(obj);" + - " }," + - " fileReaderReady: function(reader) {" + - " return new Promise(function(resolve, reject) {" + - " reader.onload = function() {" + - " resolve(reader.result);" + - " };" + - " reader.onerror = function() {" + - " reject(reader.error);" + - " };" + - " });" + - " }," + - " readBlobAsArrayBuffer: function(blob) {" + - " var reader = new FileReader();" + - " var promise = " + JAVASCRIPT_UTIL_VAR_NAME() + ".fileReaderReady(reader);" + - " reader.readAsArrayBuffer(blob);" + - " return promise;" + - " }," + - " convertBodyToArrayBuffer: function(body) {" + - " var viewClasses = [" + - " '[object Int8Array]'," + - " '[object Uint8Array]'," + - " '[object Uint8ClampedArray]'," + - " '[object Int16Array]'," + - " '[object Uint16Array]'," + - " '[object Int32Array]'," + - " '[object Uint32Array]'," + - " '[object Float32Array]'," + - " '[object Float64Array]'" + - " ];" + - " var isArrayBufferView = null;" + - " if (" + JAVASCRIPT_UTIL_VAR_NAME() + ".support.arrayBuffer) {" + - " isArrayBufferView =" + - " ArrayBuffer.isView ||" + - " function(obj) {" + - " return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1;" + - " };" + - " }" + - " var bodyUsed = false;" + - " this._bodyInit = body;" + - " if (!body) {" + - " this._bodyText = '';" + - " } else if (typeof body === 'string') {" + - " this._bodyText = body;" + - " } else if (" + JAVASCRIPT_UTIL_VAR_NAME() + ".support.blob && Blob.prototype.isPrototypeOf(body)) {" + - " this._bodyBlob = body;" + - " } else if (" + JAVASCRIPT_UTIL_VAR_NAME() + ".support.formData && FormData.prototype.isPrototypeOf(body)) {" + - " this._bodyFormData = body;" + - " } else if (" + JAVASCRIPT_UTIL_VAR_NAME() + ".support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {" + - " this._bodyText = body.toString();" + - " } else if (" + JAVASCRIPT_UTIL_VAR_NAME() + ".support.arrayBuffer && " + JAVASCRIPT_UTIL_VAR_NAME() + ".support.blob && " + JAVASCRIPT_UTIL_VAR_NAME() + ".isDataView(body)) {" + - " this._bodyArrayBuffer = bufferClone(body.buffer);" + - " this._bodyInit = new Blob([this._bodyArrayBuffer]);" + - " } else if (" + JAVASCRIPT_UTIL_VAR_NAME() + ".support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {" + - " this._bodyArrayBuffer = bufferClone(body);" + - " } else {" + - " this._bodyText = body = Object.prototype.toString.call(body);" + - " }" + - " this.blob = function () {" + - " if (bodyUsed) {" + - " return Promise.reject(new TypeError('Already read'));" + - " }" + - " bodyUsed = true;" + - " if (this._bodyBlob) {" + - " return Promise.resolve(this._bodyBlob);" + - " } else if (this._bodyArrayBuffer) {" + - " return Promise.resolve(new Blob([this._bodyArrayBuffer]));" + - " } else if (this._bodyFormData) {" + - " throw new Error('could not read FormData body as blob');" + - " } else {" + - " return Promise.resolve(new Blob([this._bodyText]));" + - " }" + - " };" + - " if (this._bodyArrayBuffer) {" + - " if (bodyUsed) {" + - " return Promise.reject(new TypeError('Already read'));" + - " }" + - " bodyUsed = true;" + - " if (ArrayBuffer.isView(this._bodyArrayBuffer)) {" + - " return Promise.resolve(" + - " this._bodyArrayBuffer.buffer.slice(" + - " this._bodyArrayBuffer.byteOffset," + - " this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength" + - " )" + - " );" + - " } else {" + - " return Promise.resolve(this._bodyArrayBuffer);" + - " }" + - " }" + - " return this.blob().then(" + JAVASCRIPT_UTIL_VAR_NAME() + ".readBlobAsArrayBuffer);" + - " }," + - " isString: function(variable) {" + - " return typeof variable === 'string' || variable instanceof String;" + - " }," + - " convertBodyRequest: function(body) {" + - " if (body == null) {" + - " return new Promise(function(resolve, reject) { resolve(null); });" + - " }" + - " if (" + JAVASCRIPT_UTIL_VAR_NAME() + ".isString(body) || (" + JAVASCRIPT_UTIL_VAR_NAME() + ".support.searchParams && body instanceof URLSearchParams)) {" + - " return new Promise(function(resolve, reject) { resolve(body.toString()); });" + - " }" + - " if (window.Response != null) {" + - " return new Response(body).arrayBuffer().then(function(arrayBuffer) {" + - " return Array.from(new Uint8Array(arrayBuffer));" + - " });" + - " }" + - " return " + JAVASCRIPT_UTIL_VAR_NAME() + ".convertBodyToArrayBuffer(body).then(function(arrayBuffer) {" + - " return Array.from(new Uint8Array(arrayBuffer));" + - " });" + - " }," + - " arrayBufferToString: function(arrayBuffer) {" + - " var uint8Array = new Uint8Array(arrayBuffer);" + - " return uint8Array.reduce(function(acc, i) { return acc += String.fromCharCode.apply(null, [i]); }, '');" + - " }," + - " isBodyFormData: function(bodyString) {" + - " return bodyString.indexOf('------WebKitFormBoundary') >= 0;" + - " }," + - " getFormDataContentType: function(bodyString) {" + - " var boundary = bodyString.substr(2, 40);" + - " return 'multipart/form-data; boundary=' + boundary;" + - " }," + - " convertHeadersToJson: function(headers) {" + - " var headersObj = {};" + - " for (var header of headers.keys()) {" + - " var value = headers.get(header);" + - " headersObj[header] = value;" + - " }" + - " return headersObj;" + - " }," + - " convertJsonToHeaders: function(headersJson) {" + - " return new Headers(headersJson);" + - " }," + - " convertCredentialsToJson: function(credentials) {" + - " var credentialsObj = {};" + - " if (window.FederatedCredential != null && credentials instanceof FederatedCredential) {" + - " credentialsObj.type = credentials.type;" + - " credentialsObj.id = credentials.id;" + - " credentialsObj.name = credentials.name;" + - " credentialsObj.protocol = credentials.protocol;" + - " credentialsObj.provider = credentials.provider;" + - " credentialsObj.iconURL = credentials.iconURL;" + - " } else if (window.PasswordCredential != null && credentials instanceof PasswordCredential) {" + - " credentialsObj.type = credentials.type;" + - " credentialsObj.id = credentials.id;" + - " credentialsObj.name = credentials.name;" + - " credentialsObj.password = credentials.password;" + - " credentialsObj.iconURL = credentials.iconURL;" + - " } else {" + - " credentialsObj.type = 'default';" + - " credentialsObj.value = credentials;" + - " }" + - " return credentialsObj;" + - " }," + - " convertJsonToCredential: function(credentialsJson) {" + - " var credentials;" + - " if (window.FederatedCredential != null && credentialsJson.type === 'federated') {" + - " credentials = new FederatedCredential({" + - " id: credentialsJson.id," + - " name: credentialsJson.name," + - " protocol: credentialsJson.protocol," + - " provider: credentialsJson.provider," + - " iconURL: credentialsJson.iconURL" + - " });" + - " } else if (window.PasswordCredential != null && credentialsJson.type === 'password') {" + - " credentials = new PasswordCredential({" + - " id: credentialsJson.id," + - " name: credentialsJson.name," + - " password: credentialsJson.password," + - " iconURL: credentialsJson.iconURL" + - " });" + - " } else {" + - " credentials = credentialsJson.value == null ? undefined : credentialsJson.value;" + - " }" + - " return credentials;" + - " }" + - "};"; - } - - public static String JAVASCRIPT_BRIDGE_JS_SOURCE() { - return "if (window." + get_JAVASCRIPT_BRIDGE_NAME() + " != null) {" + - " (function(window) {" + - " var bridgeSecret = '" + VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET + "';" + - " var origin = '';" + - " var requestUrl = '';" + - " var isMainFrame = false;" + - " var _JSON_stringify;" + - " var _Array_slice;" + - " var _setTimeout;" + - " var _Promise;" + - " var _javaInjectedObject;" + - " try {" + - " origin = window.location.origin;" + - " } catch (_) {}" + - " try {" + - " requestUrl = window.location.href;" + - " } catch (_) {}" + - " try {" + - " isMainFrame = window === window.top;" + - " } catch (_) {}" + - " try {" + - " _JSON_stringify = window.JSON.stringify;" + - " _Array_slice = window.Array.prototype.slice;" + - " _Array_slice.call = window.Function.prototype.call;" + - " _setTimeout = window.setTimeout;" + - " _Promise = window.Promise;" + - " _javaInjectedObject = window." + get_JAVASCRIPT_BRIDGE_NAME() + ";" + - " } catch (_) { return; }" + - " window." + get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler = function() {" + - " try {" + - " requestUrl = window.location.href;" + - " } catch (_) {}" + - " var _callHandlerID = _setTimeout(function(){});" + - " _javaInjectedObject._callHandler(_JSON_stringify({" + - " 'handlerName': arguments[0]," + - " '_callHandlerID': _callHandlerID," + - " '_bridgeSecret': bridgeSecret," + - " 'origin': origin," + - " 'requestUrl': requestUrl," + - " 'isMainFrame': isMainFrame," + - " 'args': _JSON_stringify(_Array_slice.call(arguments, 1))" + - " }));" + - " return new _Promise(function(resolve, reject) {" + - " try {" + - " (isMainFrame ? window : window.top)." + get_JAVASCRIPT_BRIDGE_NAME() + "[_callHandlerID] = {resolve: resolve, reject: reject};" + - " } catch(e) { resolve(); }" + - " });" + - " };" + - " })(window);" + - "}" + - "if (window.top != null && window.top !== window && window." + get_JAVASCRIPT_BRIDGE_NAME() + " == null) {" + - " window." + get_JAVASCRIPT_BRIDGE_NAME() + " = {};" + - " (function(window) {" + - " var bridgeSecret = '" + VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET + "';" + - " var origin = '';" + - " var requestUrl = '';" + - " var isMainFrame = false;" + - " var _JSON_stringify;" + - " var _Array_slice;" + - " var _setTimeout;" + - " var _Promise;" + - " var _javaInjectedObject;" + - " try {" + - " origin = window.location.origin;" + - " } catch (_) {}" + - " try {" + - " requestUrl = window.location.href;" + - " } catch (_) {}" + - " try {" + - " isMainFrame = window === window.top;" + - " } catch (_) {}" + - " try {" + - " _JSON_stringify = window.JSON.stringify;" + - " _Array_slice = window.Array.prototype.slice;" + - " _Array_slice.call = window.Function.prototype.call;" + - " _setTimeout = window.setTimeout;" + - " _Promise = window.Promise;" + - " _javaInjectedObject = window.top." + get_JAVASCRIPT_BRIDGE_NAME() + ";" + - " } catch (_) { return; }" + - " window." + get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler = function() {" + - " try {" + - " requestUrl = window.location.href;" + - " } catch (_) {}" + - " var _callHandlerID = _setTimeout(function(){});" + - " try {" + - " _javaInjectedObject._callHandler(_JSON_stringify({" + - " 'handlerName': arguments[0]," + - " '_callHandlerID': _callHandlerID," + - " '_bridgeSecret': bridgeSecret," + - " 'origin': origin," + - " 'requestUrl': requestUrl," + - " 'isMainFrame': isMainFrame," + - " 'args': _JSON_stringify(_Array_slice.call(arguments, 1))" + - " }));" + - " return new _Promise(function(resolve, reject) {" + - " _javaInjectedObject[_callHandlerID] = {resolve: resolve, reject: reject};" + - " });" + - " } catch (error) {" + - " return new _Promise(function(resolve, reject) { resolve(); });" + - " }" + - " };" + - " })(window);" + - "}" + - "if (window." + get_JAVASCRIPT_BRIDGE_NAME() + " != null) {" + - " " + UTIL_JS_SOURCE() + - "}"; - } - - public static String PLATFORM_READY_JS_SOURCE() { - return "(function() {" + - " if ((window.top == null || window.top === window) && window." + get_JAVASCRIPT_BRIDGE_NAME() + " != null && window." + get_JAVASCRIPT_BRIDGE_NAME() + "._platformReady == null) {" + - " window.dispatchEvent(new Event('flutterInAppWebViewPlatformReady'));" + - " window." + get_JAVASCRIPT_BRIDGE_NAME() + "._platformReady = true;" + - " }" + - "})();"; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnLoadResourceJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnLoadResourceJS.java deleted file mode 100644 index fdc512a505..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnLoadResourceJS.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; - -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; - -import java.util.Set; - -public class OnLoadResourceJS { - public static final String ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT"; - public static String FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE() { - return - JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "._useOnLoadResource"; - } - public static PluginScript ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules, - boolean forMainFrameOnly) { - return - new PluginScript( - OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT_GROUP_NAME, - OnLoadResourceJS.ON_LOAD_RESOURCE_JS_SOURCE(), - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - false, - allowedOriginRules, - forMainFrameOnly - ); - } - - public static String ON_LOAD_RESOURCE_JS_SOURCE() { - return - "window." + FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE() + " = true;" + - "(function() {" + - " var observer = new PerformanceObserver(function(list) {" + - " list.getEntries().forEach(function(entry) {" + - " if (" + FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE() + " == null || " + FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE() + " == true) {" + - " var resource = {" + - " 'url': entry.name," + - " 'initiatorType': entry.initiatorType," + - " 'startTime': entry.startTime," + - " 'duration': entry.duration" + - " };" + - " window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onLoadResource', resource);" + - " }" + - " });" + - " });" + - " observer.observe({entryTypes: ['resource']});" + - "})();"; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnWindowBlurEventJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnWindowBlurEventJS.java deleted file mode 100644 index ef2ba8c375..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnWindowBlurEventJS.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; - -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; - -import java.util.Set; - -public class OnWindowBlurEventJS { - public static final String ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT"; - - // This plugin is only for main frame - public static PluginScript ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules) { - return - new PluginScript( - OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME, - OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_SOURCE(), - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - false, - allowedOriginRules, - true - ); - } - - public static String ON_WINDOW_BLUR_EVENT_JS_SOURCE() { - return - "(function(){" + - " window.addEventListener('blur', function(e) {" + - " window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onWindowBlur');" + - " });" + - "})();"; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnWindowFocusEventJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnWindowFocusEventJS.java deleted file mode 100644 index bf2e9a4546..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnWindowFocusEventJS.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; - -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; - -import java.util.Set; - -public class OnWindowFocusEventJS { - public static final String ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT"; - - // This plugin is only for main frame - public static PluginScript ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules) { - return - new PluginScript( - OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME, - OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_SOURCE(), - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - false, - allowedOriginRules, - true - ); - } - - public static String ON_WINDOW_FOCUS_EVENT_JS_SOURCE() { - return - "(function(){" + - " window.addEventListener('focus', function(e) {" + - " window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onWindowFocus');" + - " });" + - "})();"; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PluginScriptsUtil.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PluginScriptsUtil.java deleted file mode 100644 index de6c271d10..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PluginScriptsUtil.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; - -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; - -import java.util.Set; - -public class PluginScriptsUtil { - - public static final String VAR_PLACEHOLDER_VALUE = "$IN_APP_WEBVIEW_PLACEHOLDER_VALUE"; - public static final String VAR_CONTENT_WORLD_NAME_ARRAY = "$IN_APP_WEBVIEW_CONTENT_WORLD_NAME_ARRAY"; - public static final String VAR_CONTENT_WORLD_NAME = "$IN_APP_WEBVIEW_CONTENT_WORLD_NAME"; - public static final String VAR_JSON_SOURCE_ENCODED = "$IN_APP_WEBVIEW_JSON_SOURCE_ENCODED"; - public static final String VAR_FUNCTION_ARGUMENT_NAMES = "$IN_APP_WEBVIEW_FUNCTION_ARGUMENT_NAMES"; - public static final String VAR_FUNCTION_ARGUMENT_VALUES = "$IN_APP_WEBVIEW_FUNCTION_ARGUMENT_VALUES"; - public static final String VAR_FUNCTION_ARGUMENTS_OBJ = "$IN_APP_WEBVIEW_FUNCTION_ARGUMENTS_OBJ"; - public static final String VAR_FUNCTION_BODY = "$IN_APP_WEBVIEW_FUNCTION_BODY"; - public static final String VAR_RESULT_UUID = "$IN_APP_WEBVIEW_RESULT_UUID"; - public static final String VAR_RANDOM_NAME = "$IN_APP_WEBVIEW_VARIABLE_RANDOM_NAME"; - - public static String CALL_ASYNC_JAVA_SCRIPT_WRAPPER_JS_SOURCE() { - return - "(function(obj) {" + - " (async function(" + VAR_FUNCTION_ARGUMENT_NAMES + ") {" + - " \n" + VAR_FUNCTION_BODY + "\n" + - " })(" + VAR_FUNCTION_ARGUMENT_VALUES + ").then(function(value) {" + - " window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler('callAsyncJavaScript', {'value': value, 'error': null, 'resultUuid': '" + VAR_RESULT_UUID + "'});" + - " }).catch(function(error) {" + - " window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler('callAsyncJavaScript', {'value': null, 'error': error + '', 'resultUuid': '" + VAR_RESULT_UUID + "'});" + - " });" + - " return null;" + - "})(" + VAR_FUNCTION_ARGUMENTS_OBJ + ");"; - } - - public static String EVALUATE_JAVASCRIPT_WITH_CONTENT_WORLD_WRAPPER_JS_SOURCE() { - return - "var $IN_APP_WEBVIEW_VARIABLE_RANDOM_NAME = null;" + - "try {" + - " $IN_APP_WEBVIEW_VARIABLE_RANDOM_NAME = eval(" + VAR_PLACEHOLDER_VALUE + ");" + - "} catch(e) {" + - " console.error(e);" + - "}" + - "window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler('evaluateJavaScriptWithContentWorld', {'value': $IN_APP_WEBVIEW_VARIABLE_RANDOM_NAME, 'resultUuid': '" + VAR_RESULT_UUID + "'});"; - } - - public static final String IS_ACTIVE_ELEMENT_INPUT_EDITABLE_JS_SOURCE = - "var activeEl = document.activeElement;" + - "var nodeName = (activeEl != null) ? activeEl.nodeName.toLowerCase() : '';" + - "var isActiveElementInputEditable = activeEl != null && " + - "(activeEl.nodeType == 1 && (nodeName == 'textarea' || (nodeName == 'input' && /^(?:text|email|number|search|tel|url|password)$/i.test(activeEl.type != null ? activeEl.type : 'text')))) && " + - "!activeEl.disabled && !activeEl.readOnly;" + - "var isActiveElementEditable = isActiveElementInputEditable || (activeEl != null && activeEl.isContentEditable) || document.designMode === 'on';"; - - // android Workaround to hide context menu when selected text is empty - // and the document active element is not an input element. - public static final String CHECK_CONTEXT_MENU_SHOULD_BE_HIDDEN_JS_SOURCE = "(function(){" + - " var txt;" + - " if (window.getSelection) {" + - " txt = window.getSelection().toString();" + - " } else if (window.document.getSelection) {" + - " txt = window.document.getSelection().toString();" + - " } else if (window.document.selection) {" + - " txt = window.document.selection.createRange().text;" + - " }" + - IS_ACTIVE_ELEMENT_INPUT_EDITABLE_JS_SOURCE + - " return txt === '' && !isActiveElementEditable;" + - "})();"; - - public static final String GET_SELECTED_TEXT_JS_SOURCE = "(function(){" + - " var txt;" + - " if (window.getSelection) {" + - " txt = window.getSelection().toString();" + - " } else if (window.document.getSelection) {" + - " txt = window.document.getSelection().toString();" + - " } else if (window.document.selection) {" + - " txt = window.document.selection.createRange().text;" + - " }" + - " return txt;" + - "})();"; - - public static final String CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT_GROUP_NAME = "CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT"; - public static PluginScript CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules, - boolean forMainFrameOnly) { - return - new PluginScript( - PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT_GROUP_NAME, - PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_SOURCE(), - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - false, - allowedOriginRules, - forMainFrameOnly - ); - } - - // android Workaround to hide context menu when user emit a keydown event - public static String CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_SOURCE() { - return - "(function(){" + - " document.addEventListener('keydown', function(e) {" + - " window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "._hideContextMenu();" + - " });" + - "})();"; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PrintJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PrintJS.java deleted file mode 100644 index dc273457f0..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PrintJS.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; - -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; - -import java.util.Set; - -public class PrintJS { - public static final String PRINT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_PRINT_JS_PLUGIN_SCRIPT"; - public static PluginScript PRINT_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules, - boolean forMainFrameOnly) { - return - new PluginScript( - PrintJS.PRINT_JS_PLUGIN_SCRIPT_GROUP_NAME, - PrintJS.PRINT_JS_SOURCE(), - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - false, - allowedOriginRules, - forMainFrameOnly - ); - } - - public static String PRINT_JS_SOURCE() { - return - "window.print = function() {" + - " if (window.top == null || window.top === window) {" + - " window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onPrintRequest', window.location.href);" + - " } else {" + - " window.top.print();" + - " }" + - "};"; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PromisePolyfillJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PromisePolyfillJS.java deleted file mode 100644 index 3331c63a05..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PromisePolyfillJS.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; - -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; - -import java.util.Set; - -public class PromisePolyfillJS { - public static final String PROMISE_POLYFILL_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_PROMISE_POLYFILL_JS_PLUGIN_SCRIPT"; - public static final PluginScript PROMISE_POLYFILL_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules, - boolean forMainFrameOnly) { - return new PluginScript( - PromisePolyfillJS.PROMISE_POLYFILL_JS_PLUGIN_SCRIPT_GROUP_NAME, - PromisePolyfillJS.PROMISE_POLYFILL_JS_SOURCE, - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - true, - allowedOriginRules, - forMainFrameOnly - ); - } - - // https://github.com/tildeio/rsvp.js - public static final String PROMISE_POLYFILL_JS_SOURCE = "if (window.Promise == null) {" + - " !function(t,e){\"object\"==typeof exports&&\"undefined\"!=typeof module?e(exports):\"function\"==typeof define&&define.amd?define([\"exports\"],e):e(t.RSVP={})}(this,function(t){\"use strict\";function e(t){var e=t._promiseCallbacks;return e||(e=t._promiseCallbacks={}),e}var r={mixin:function(t){return t.on=this.on,t.off=this.off,t.trigger=this.trigger,t._promiseCallbacks=void 0,t},on:function(t,r){if(\"function\"!=typeof r)throw new TypeError(\"Callback must be a function\");var n=e(this),o=n[t];o||(o=n[t]=[]),-1===o.indexOf(r)&&o.push(r)},off:function(t,r){var n=e(this);if(r){var o=n[t],i=o.indexOf(r);-1!==i&&o.splice(i,1)}else n[t]=[]},trigger:function(t,r,n){var o=e(this)[t];if(o)for(var i=0;i2&&void 0!==arguments[2])||arguments[2],o=arguments[3];return function(t,e){if(!t)throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");return!e||\"object\"!=typeof e&&\"function\"!=typeof e?t:e}(this,t.call(this,e,r,n,o))}return function(t,e){if(\"function\"!=typeof e&&null!==e)throw new TypeError(\"Super expression must either be null or a function, not \"+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,t),e.prototype._init=function(t,e){this._result={},this._enumerate(e)},e.prototype._enumerate=function(t){var e=Object.keys(t),r=e.length,n=this.promise;this._remaining=r;for(var o=void 0,i=void 0,s=0;n._state===a&&s obj = new HashMap<>(); - obj.put("completed", completed); - obj.put("error", error); - channel.invokeMethod("onComplete", obj); - } - - @Override - public void dispose() { - super.dispose(); - printJobController = null; - } -} \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobController.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobController.java deleted file mode 100644 index 6d962e29c4..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobController.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.print_job; - -import android.os.Build; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.types.Disposable; -import com.pichillilorenzo.flutter_inappwebview_android.types.PrintJobInfoExt; - -import io.flutter.plugin.common.MethodChannel; - -@RequiresApi(api = Build.VERSION_CODES.KITKAT) -public class PrintJobController implements Disposable { - protected static final String LOG_TAG = "PrintJob"; - public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_printjobcontroller_"; - - @NonNull - public String id; - @Nullable - public InAppWebViewFlutterPlugin plugin; - @Nullable - public PrintJobChannelDelegate channelDelegate; - @Nullable - public android.print.PrintJob job; - @Nullable - public PrintJobSettings settings; - - public PrintJobController(@NonNull String id, @Nullable PrintJobSettings settings, - @NonNull InAppWebViewFlutterPlugin plugin) { - this.id = id; - this.plugin = plugin; - this.settings = settings; - final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id); - this.channelDelegate = new PrintJobChannelDelegate(this, channel); - } - - public void setJob(@Nullable android.print.PrintJob job) { - this.job = job; - } - - public void cancel() { - if (this.job != null) { - this.job.cancel(); - } - } - - public void restart() { - if (this.job != null) { - this.job.restart(); - } - } - - @Nullable - public PrintJobInfoExt getInfo() { - if (this.job != null) { - return PrintJobInfoExt.fromPrintJobInfo(this.job.getInfo()); - } - return null; - } - - public void disposeNoCancel() { - if (channelDelegate != null) { - channelDelegate.dispose(); - channelDelegate = null; - } - if (plugin != null) { - PrintJobManager printJobManager = plugin.printJobManager; - if (printJobManager != null && printJobManager.jobs.containsKey(id)) { - printJobManager.jobs.put(id, null); - } - } - if (job != null) { - job = null; - } - plugin = null; - } - - @Override - public void dispose() { - if (channelDelegate != null) { - channelDelegate.dispose(); - channelDelegate = null; - } - if (plugin != null) { - PrintJobManager printJobManager = plugin.printJobManager; - if (printJobManager != null && printJobManager.jobs.containsKey(id)) { - printJobManager.jobs.put(id, null); - } - } - if (job != null) { - job.cancel(); - job = null; - } - plugin = null; - } - - public void onComplete(boolean completed, @Nullable String error) { - if (channelDelegate != null) channelDelegate.onComplete(completed, error); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobManager.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobManager.java deleted file mode 100755 index 581130c7db..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobManager.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package com.pichillilorenzo.flutter_inappwebview_android.print_job; - -import android.os.Build; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.types.Disposable; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -@RequiresApi(api = Build.VERSION_CODES.KITKAT) -public class PrintJobManager implements Disposable { - protected static final String LOG_TAG = "PrintJobManager"; - @Nullable - public InAppWebViewFlutterPlugin plugin; - public final Map jobs = new HashMap<>(); - - public PrintJobManager(@NonNull final InAppWebViewFlutterPlugin plugin) { - super(); - this.plugin = plugin; - } - - public void dispose() { - Collection printJobControllers = jobs.values(); - for (PrintJobController job : printJobControllers) { - if (job != null) { - job.dispose(); - } - } - jobs.clear(); - plugin = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobSettings.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobSettings.java deleted file mode 100755 index 7df47bbb25..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobSettings.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.print_job; - -import android.os.Build; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; - -import com.pichillilorenzo.flutter_inappwebview_android.ISettings; -import com.pichillilorenzo.flutter_inappwebview_android.types.MediaSizeExt; -import com.pichillilorenzo.flutter_inappwebview_android.types.ResolutionExt; - -import java.util.HashMap; -import java.util.Map; - -@RequiresApi(api = Build.VERSION_CODES.KITKAT) -public class PrintJobSettings implements ISettings { - - public static final String LOG_TAG = "PrintJobSettings"; - - public Boolean handledByClient = false; - @Nullable - public String jobName; - @Nullable - public Integer orientation; -// @Nullable -// public MarginsExt margins; - @Nullable - public MediaSizeExt mediaSize; - @Nullable - public Integer colorMode; - @Nullable - public Integer duplexMode; - @Nullable - public ResolutionExt resolution; - - @NonNull - @Override - public PrintJobSettings parse(@NonNull Map settings) { - for (Map.Entry pair : settings.entrySet()) { - String key = pair.getKey(); - Object value = pair.getValue(); - if (value == null) { - continue; - } - - switch (key) { - case "handledByClient": - handledByClient = (Boolean) value; - break; - case "jobName": - jobName = (String) value; - break; - case "orientation": - orientation = (Integer) value; - break; -// case "margins": -// margins = MarginsExt.fromMap((Map) value); -// break; - case "mediaSize": - mediaSize = MediaSizeExt.fromMap((Map) value); - break; - case "colorMode": - colorMode = (Integer) value; - break; - case "duplexMode": - duplexMode = (Integer) value; - break; - case "resolution": - resolution = ResolutionExt.fromMap((Map) value); - break; - } - } - - return this; - } - - @NonNull - @Override - public Map toMap() { - Map settings = new HashMap<>(); - settings.put("handledByClient", handledByClient); - settings.put("jobName", jobName); - settings.put("orientation", orientation); -// settings.put("margins", margins != null ? margins.toMap() : null); - settings.put("mediaSize", mediaSize != null ? mediaSize.toMap() : null); - settings.put("colorMode", colorMode); - settings.put("duplexMode", duplexMode); - settings.put("resolution", resolution != null ? resolution.toMap() : null); - return settings; - } - - @NonNull - @Override - public Map getRealSettings(@NonNull PrintJobController printJobController) { - Map realSettings = toMap(); - return realSettings; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/process_global_config/ProcessGlobalConfigManager.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/process_global_config/ProcessGlobalConfigManager.java deleted file mode 100755 index 0b63e3f4c8..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/process_global_config/ProcessGlobalConfigManager.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.process_global_config; - -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.ProcessGlobalConfig; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; - -import java.util.Map; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class ProcessGlobalConfigManager extends ChannelDelegateImpl { - protected static final String LOG_TAG = "ProcessGlobalConfigM"; - public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_processglobalconfig"; - - @Nullable - public InAppWebViewFlutterPlugin plugin; - - public ProcessGlobalConfigManager(@NonNull final InAppWebViewFlutterPlugin plugin) { - super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME)); - this.plugin = plugin; - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - switch (call.method) { - case "apply": - if (plugin != null && plugin.activity != null) { - ProcessGlobalConfigSettings settings = (new ProcessGlobalConfigSettings()) - .parse((Map) call.argument("settings")); - try { - ProcessGlobalConfig.apply(settings.toProcessGlobalConfig(plugin.activity)); - result.success(true); - } catch (Exception e) { - result.error(LOG_TAG, "", e); - } - } else { - result.success(false); - } - break; - default: - result.notImplemented(); - } - } - - @Override - public void dispose() { - super.dispose(); - plugin = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/process_global_config/ProcessGlobalConfigSettings.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/process_global_config/ProcessGlobalConfigSettings.java deleted file mode 100644 index 0736be3430..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/process_global_config/ProcessGlobalConfigSettings.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.process_global_config; - -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.ProcessGlobalConfig; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.ISettings; - -import java.io.File; -import java.util.HashMap; -import java.util.Map; - -public class ProcessGlobalConfigSettings implements ISettings { - public static final String LOG_TAG = "ProcessGlobalConfigSettings"; - - @Nullable - public String dataDirectorySuffix; - @Nullable - public DirectoryBasePaths directoryBasePaths; - - @NonNull - @Override - public ProcessGlobalConfigSettings parse(@NonNull Map settings) { - for (Map.Entry pair : settings.entrySet()) { - String key = pair.getKey(); - Object value = pair.getValue(); - if (value == null) { - continue; - } - - switch (key) { - case "dataDirectorySuffix": - dataDirectorySuffix = (String) value; - break; - case "directoryBasePaths": - directoryBasePaths = (new DirectoryBasePaths()).parse((Map) value); - break; - } - } - - return this; - } - - public ProcessGlobalConfig toProcessGlobalConfig(@NonNull Context context) { - ProcessGlobalConfig config = new ProcessGlobalConfig(); - if (dataDirectorySuffix != null && - WebViewFeature.isStartupFeatureSupported(context, WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX)) { - config.setDataDirectorySuffix(context, dataDirectorySuffix); - } - if (directoryBasePaths != null && - WebViewFeature.isStartupFeatureSupported(context, WebViewFeature.STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS)) { - config.setDirectoryBasePaths(context, - new File(directoryBasePaths.dataDirectoryBasePath), - new File(directoryBasePaths.cacheDirectoryBasePath)); - } - return config; - } - @NonNull - public Map toMap() { - Map settings = new HashMap<>(); - settings.put("dataDirectorySuffix", dataDirectorySuffix); - return settings; - } - - @NonNull - @Override - public Map getRealSettings(@NonNull ProcessGlobalConfig processGlobalConfig) { - Map realSettings = toMap(); - return realSettings; - } - - static class DirectoryBasePaths implements ISettings { - public static final String LOG_TAG = "ProcessGlobalConfigSettings"; - - public String cacheDirectoryBasePath; - public String dataDirectoryBasePath; - - @NonNull - @Override - public DirectoryBasePaths parse(@NonNull Map settings) { - for (Map.Entry pair : settings.entrySet()) { - String key = pair.getKey(); - Object value = pair.getValue(); - if (value == null) { - continue; - } - - switch (key) { - case "cacheDirectoryBasePath": - cacheDirectoryBasePath = (String) value; - break; - case "dataDirectoryBasePath": - dataDirectoryBasePath = (String) value; - break; - } - } - - return this; - } - - @NonNull - public Map toMap() { - Map settings = new HashMap<>(); - settings.put("cacheDirectoryBasePath", cacheDirectoryBasePath); - settings.put("dataDirectoryBasePath", dataDirectoryBasePath); - return settings; - } - - @NonNull - @Override - public Map getRealSettings(@NonNull Object obj) { - Map realSettings = toMap(); - return realSettings; - } - } -} \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/proxy/ProxyManager.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/proxy/ProxyManager.java deleted file mode 100755 index a576cfe7b2..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/proxy/ProxyManager.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.proxy; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.ProxyConfig; -import androidx.webkit.ProxyController; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; -import com.pichillilorenzo.flutter_inappwebview_android.types.ProxyRuleExt; - -import java.util.HashMap; -import java.util.concurrent.Executor; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class ProxyManager extends ChannelDelegateImpl { - protected static final String LOG_TAG = "ProxyManager"; - public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_proxycontroller"; - - @Nullable - public static ProxyController proxyController; - @Nullable - public InAppWebViewFlutterPlugin plugin; - - public ProxyManager(@NonNull final InAppWebViewFlutterPlugin plugin) { - super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME)); - this.plugin = plugin; - } - - public static void init() { - if (proxyController == null && - WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE)) { - proxyController = ProxyController.getInstance(); - } - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - init(); - - switch (call.method) { - case "setProxyOverride": - if (proxyController != null) { - HashMap settingsMap = (HashMap) call.argument("settings"); - ProxySettings settings = new ProxySettings(); - if (settingsMap != null) { - settings.parse(settingsMap); - } - setProxyOverride(settings, result); - } else { - result.success(false); - } - break; - case "clearProxyOverride": - if (proxyController != null ) { - clearProxyOverride(result); - } else { - result.success(false); - } - break; - default: - result.notImplemented(); - } - } - - private void setProxyOverride(ProxySettings settings, final MethodChannel.Result result) { - if (proxyController != null) { - ProxyConfig.Builder proxyConfigBuilder = new ProxyConfig.Builder(); - for (String bypassRule : settings.bypassRules) { - proxyConfigBuilder.addBypassRule(bypassRule); - } - for (String direct : settings.directs) { - proxyConfigBuilder.addDirect(direct); - } - for (ProxyRuleExt proxyRule : settings.proxyRules) { - if (proxyRule.getSchemeFilter() != null) { - proxyConfigBuilder.addProxyRule(proxyRule.getUrl(), proxyRule.getSchemeFilter()); - } else { - proxyConfigBuilder.addProxyRule(proxyRule.getUrl()); - } - } - if (settings.bypassSimpleHostnames != null && settings.bypassSimpleHostnames) { - proxyConfigBuilder.bypassSimpleHostnames(); - } - if (settings.removeImplicitRules != null && settings.removeImplicitRules) { - proxyConfigBuilder.removeImplicitRules(); - } - if (settings.reverseBypassEnabled != null && WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE_REVERSE_BYPASS)) { - proxyConfigBuilder.setReverseBypassEnabled(settings.reverseBypassEnabled); - } - proxyController.setProxyOverride(proxyConfigBuilder.build(), new Executor() { - @Override - public void execute(Runnable command) { - command.run(); - } - }, new Runnable() { - @Override - public void run() { - result.success(true); - } - }); - } - } - - private void clearProxyOverride(final MethodChannel.Result result) { - if (proxyController != null) { - proxyController.clearProxyOverride(new Executor() { - @Override - public void execute(Runnable command) { - command.run(); - } - }, new Runnable() { - @Override - public void run() { - result.success(true); - } - }); - } - } - - @Override - public void dispose() { - super.dispose(); - plugin = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/proxy/ProxySettings.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/proxy/ProxySettings.java deleted file mode 100644 index 4834131f46..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/proxy/ProxySettings.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.proxy; - -import androidx.annotation.NonNull; -import androidx.webkit.ProxyConfig; - -import com.pichillilorenzo.flutter_inappwebview_android.ISettings; -import com.pichillilorenzo.flutter_inappwebview_android.types.ProxyRuleExt; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ProxySettings implements ISettings { - List bypassRules = new ArrayList<>(); - List directs = new ArrayList<>(); - List proxyRules = new ArrayList<>(); - Boolean bypassSimpleHostnames = null; - Boolean removeImplicitRules = null; - Boolean reverseBypassEnabled = false; - - @NonNull - @Override - public ProxySettings parse(@NonNull Map settings) { - for (Map.Entry pair : settings.entrySet()) { - String key = pair.getKey(); - Object value = pair.getValue(); - if (value == null) { - continue; - } - - switch (key) { - case "bypassRules": - bypassRules = (List) value; - break; - case "directs": - directs = (List) value; - break; - case "proxyRules": - proxyRules = new ArrayList<>(); - List> proxyRuleMapList = (List>) value; - for (Map proxyRuleMap : proxyRuleMapList) { - ProxyRuleExt proxyRuleExt = ProxyRuleExt.fromMap(proxyRuleMap); - if (proxyRuleExt != null) { - proxyRules.add(proxyRuleExt); - } - } - break; - case "bypassSimpleHostnames": - bypassSimpleHostnames = (Boolean) value; - break; - case "removeImplicitRules": - removeImplicitRules = (Boolean) value; - break; - case "reverseBypassEnabled": - reverseBypassEnabled = (Boolean) value; - break; - } - } - - return this; - } - - @NonNull - @Override - public Map toMap() { - List> proxyRuleMapList = new ArrayList<>(); - for (ProxyRuleExt proxyRuleExt : proxyRules) { - proxyRuleMapList.add(proxyRuleExt.toMap()); - } - Map settings = new HashMap<>(); - settings.put("bypassRules", bypassRules); - settings.put("directs", directs); - settings.put("proxyRules", proxyRuleMapList); - settings.put("bypassSimpleHostnames", bypassSimpleHostnames); - settings.put("removeImplicitRules", removeImplicitRules); - settings.put("reverseBypassEnabled", reverseBypassEnabled); - return settings; - } - - @NonNull - @Override - public Map getRealSettings(@NonNull ProxyConfig proxyConfig) { - Map realSettings = toMap(); - List> proxyRuleMapList = new ArrayList<>(); - List proxyRules = proxyConfig.getProxyRules(); - for (ProxyConfig.ProxyRule proxyRule : proxyRules) { - Map proxyRuleMap = new HashMap<>(); - proxyRuleMap.put("url", proxyRule.getUrl()); - proxyRuleMap.put("schemeFilter", proxyRule.getSchemeFilter()); - proxyRuleMapList.add(proxyRuleMap); - } - realSettings.put("bypassRules", proxyConfig.getBypassRules()); - realSettings.put("proxyRules", proxyRuleMapList); - realSettings.put("reverseBypassEnabled", proxyConfig.isReverseBypassEnabled()); - return realSettings; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/pull_to_refresh/PullToRefreshChannelDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/pull_to_refresh/PullToRefreshChannelDelegate.java deleted file mode 100644 index 8ec3eb5779..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/pull_to_refresh/PullToRefreshChannelDelegate.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.pull_to_refresh; - -import android.graphics.Color; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; - -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; - -import java.util.HashMap; -import java.util.Map; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class PullToRefreshChannelDelegate extends ChannelDelegateImpl { - @Nullable - private PullToRefreshLayout pullToRefreshView; - - public PullToRefreshChannelDelegate(@NonNull PullToRefreshLayout pullToRefreshView, @NonNull MethodChannel channel) { - super(channel); - this.pullToRefreshView = pullToRefreshView; - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) { - switch (call.method) { - case "setEnabled": - if (pullToRefreshView != null) { - Boolean enabled = (Boolean) call.argument("enabled"); - pullToRefreshView.settings.enabled = enabled; // used by InAppWebView.onOverScrolled - pullToRefreshView.setEnabled(enabled); - result.success(true); - } else { - result.success(false); - } - break; - case "isEnabled": - if (pullToRefreshView != null) { - result.success(pullToRefreshView.isEnabled()); - } else { - result.success(false); - } - break; - case "setRefreshing": - if (pullToRefreshView != null) { - Boolean refreshing = (Boolean) call.argument("refreshing"); - pullToRefreshView.setRefreshing(refreshing); - result.success(true); - } else { - result.success(false); - } - break; - case "isRefreshing": - result.success(pullToRefreshView != null && pullToRefreshView.isRefreshing()); - break; - case "setColor": - if (pullToRefreshView != null) { - String color = (String) call.argument("color"); - pullToRefreshView.setColorSchemeColors(Color.parseColor(color)); - result.success(true); - } else { - result.success(false); - } - break; - case "setBackgroundColor": - if (pullToRefreshView != null) { - String color = (String) call.argument("color"); - pullToRefreshView.setProgressBackgroundColorSchemeColor(Color.parseColor(color)); - result.success(true); - } else { - result.success(false); - } - break; - case "setDistanceToTriggerSync": - if (pullToRefreshView != null) { - Integer distanceToTriggerSync = (Integer) call.argument("distanceToTriggerSync"); - pullToRefreshView.setDistanceToTriggerSync(distanceToTriggerSync); - result.success(true); - } else { - result.success(false); - } - break; - case "setSlingshotDistance": - if (pullToRefreshView != null) { - Integer slingshotDistance = (Integer) call.argument("slingshotDistance"); - pullToRefreshView.setSlingshotDistance(slingshotDistance); - result.success(true); - } else { - result.success(false); - } - break; - case "getDefaultSlingshotDistance": - result.success(SwipeRefreshLayout.DEFAULT_SLINGSHOT_DISTANCE); - break; - case "setSize": - if (pullToRefreshView != null) { - Integer size = (Integer) call.argument("size"); - pullToRefreshView.setSize(size); - result.success(true); - } else { - result.success(false); - } - break; - default: - result.notImplemented(); - } - } - - public void onRefresh() { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onRefresh", obj); - } - - @Override - public void dispose() { - super.dispose(); - pullToRefreshView = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/pull_to_refresh/PullToRefreshLayout.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/pull_to_refresh/PullToRefreshLayout.java deleted file mode 100644 index 3f6367329c..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/pull_to_refresh/PullToRefreshLayout.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.pull_to_refresh; - -import android.content.Context; -import android.graphics.Color; -import android.util.AttributeSet; -import android.view.View; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.types.Disposable; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.InAppWebView; - -import io.flutter.plugin.common.MethodChannel; - -public class PullToRefreshLayout extends SwipeRefreshLayout implements Disposable { - static final String LOG_TAG = "PullToRefreshLayout"; - public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_"; - - @Nullable - public PullToRefreshChannelDelegate channelDelegate; - public PullToRefreshSettings settings = new PullToRefreshSettings(); - - public PullToRefreshLayout(@NonNull Context context, @NonNull InAppWebViewFlutterPlugin plugin, - @NonNull Object id, @NonNull PullToRefreshSettings settings) { - super(context); - this.settings = settings; - final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id); - this.channelDelegate = new PullToRefreshChannelDelegate(this, channel); - } - - public PullToRefreshLayout(@NonNull Context context) { - super(context); - } - - public PullToRefreshLayout(@NonNull Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - } - - public void prepare() { - setFocusable(true); - - final PullToRefreshLayout self = this; - - setEnabled(settings.enabled); - setOnChildScrollUpCallback(new OnChildScrollUpCallback() { - @Override - public boolean canChildScrollUp(@NonNull SwipeRefreshLayout parent, @Nullable View child) { - if (child instanceof InAppWebView) { - InAppWebView inAppWebView = (InAppWebView) child; - return (inAppWebView.canScrollVertically() && inAppWebView.getScrollY() > 0) || - (!inAppWebView.canScrollVertically() && inAppWebView.getScrollY() == 0); - } - return true; - } - }); - setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { - @Override - public void onRefresh() { - if (channelDelegate == null) { - self.setRefreshing(false); - return; - } - channelDelegate.onRefresh(); - } - }); - if (settings.color != null) - setColorSchemeColors(Color.parseColor(settings.color)); - if (settings.backgroundColor != null) - setProgressBackgroundColorSchemeColor(Color.parseColor(settings.backgroundColor)); - if (settings.distanceToTriggerSync != null) - setDistanceToTriggerSync(settings.distanceToTriggerSync); - if (settings.slingshotDistance != null) - setSlingshotDistance(settings.slingshotDistance); - if (settings.size != null) - setSize(settings.size); - } - - public void dispose() { - if (channelDelegate != null) { - channelDelegate.dispose(); - channelDelegate = null; - } - removeAllViews(); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/pull_to_refresh/PullToRefreshSettings.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/pull_to_refresh/PullToRefreshSettings.java deleted file mode 100644 index 866ed89024..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/pull_to_refresh/PullToRefreshSettings.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.pull_to_refresh; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.ISettings; - -import java.util.HashMap; -import java.util.Map; - -public class PullToRefreshSettings implements ISettings { - public static final String LOG_TAG = "PullToRefreshSettings"; - - public Boolean enabled = true; - @Nullable - public String color; - @Nullable - public String backgroundColor; - @Nullable - public Integer distanceToTriggerSync; - @Nullable - public Integer slingshotDistance; - @Nullable - public Integer size; - - @NonNull - @Override - public PullToRefreshSettings parse(@NonNull Map settings) { - for (Map.Entry pair : settings.entrySet()) { - String key = pair.getKey(); - Object value = pair.getValue(); - if (value == null) { - continue; - } - - switch (key) { - case "enabled": - enabled = (Boolean) value; - break; - case "color": - color = (String) value; - break; - case "backgroundColor": - backgroundColor = (String) value; - break; - case "distanceToTriggerSync": - distanceToTriggerSync = (Integer) value; - break; - case "slingshotDistance": - slingshotDistance = (Integer) value; - break; - case "size": - size = (Integer) value; - break; - } - } - - return this; - } - - @NonNull - public Map toMap() { - Map settings = new HashMap<>(); - settings.put("enabled", enabled); - settings.put("color", color); - settings.put("backgroundColor", backgroundColor); - settings.put("distanceToTriggerSync", distanceToTriggerSync); - settings.put("slingshotDistance", slingshotDistance); - settings.put("size", size); - return settings; - } - - @NonNull - @Override - public Map getRealSettings(@NonNull PullToRefreshLayout pullToRefreshLayout) { - Map realSettings = toMap(); - return realSettings; - } - -} \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/service_worker/ServiceWorkerChannelDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/service_worker/ServiceWorkerChannelDelegate.java deleted file mode 100755 index 19a4ea38b4..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/service_worker/ServiceWorkerChannelDelegate.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.service_worker; - -import android.os.Build; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; -import androidx.webkit.ServiceWorkerControllerCompat; -import androidx.webkit.ServiceWorkerWebSettingsCompat; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.Util; -import com.pichillilorenzo.flutter_inappwebview_android.types.BaseCallbackResultImpl; -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; -import com.pichillilorenzo.flutter_inappwebview_android.types.SyncBaseCallbackResultImpl; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebResourceRequestExt; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebResourceResponseExt; - -import java.util.Map; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -@RequiresApi(api = Build.VERSION_CODES.N) -public class ServiceWorkerChannelDelegate extends ChannelDelegateImpl { - @Nullable - private ServiceWorkerManager serviceWorkerManager; - - public ServiceWorkerChannelDelegate(@NonNull ServiceWorkerManager serviceWorkerManager, @NonNull MethodChannel channel) { - super(channel); - this.serviceWorkerManager = serviceWorkerManager; - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - ServiceWorkerManager.init(); - ServiceWorkerControllerCompat serviceWorkerController = ServiceWorkerManager.serviceWorkerController; - ServiceWorkerWebSettingsCompat serviceWorkerWebSettings = (serviceWorkerController != null) ? - serviceWorkerController.getServiceWorkerWebSettings() : null; - - switch (call.method) { - case "setServiceWorkerClient": - if (serviceWorkerManager != null) { - Boolean isNull = (Boolean) call.argument("isNull"); - serviceWorkerManager.setServiceWorkerClient(isNull); - result.success(true); - } else { - result.success(false); - } - break; - case "getAllowContentAccess": - if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS)) { - result.success(serviceWorkerWebSettings.getAllowContentAccess()); - } else { - result.success(false); - } - break; - case "getAllowFileAccess": - if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_FILE_ACCESS)) { - result.success(serviceWorkerWebSettings.getAllowFileAccess()); - } else { - result.success(false); - } - break; - case "getBlockNetworkLoads": - if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS)) { - result.success(serviceWorkerWebSettings.getBlockNetworkLoads()); - } else { - result.success(false); - } - break; - case "getCacheMode": - if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_CACHE_MODE)) { - result.success(serviceWorkerWebSettings.getCacheMode()); - } else { - result.success(null); - } - break; - case "setAllowContentAccess": - if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS)) { - Boolean allow = (Boolean) call.argument("allow"); - serviceWorkerWebSettings.setAllowContentAccess(allow); - } - result.success(true); - break; - case "setAllowFileAccess": - if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_FILE_ACCESS)) { - Boolean allow = (Boolean) call.argument("allow"); - serviceWorkerWebSettings.setAllowFileAccess(allow); - } - result.success(true); - break; - case "setBlockNetworkLoads": - if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS)) { - Boolean flag = (Boolean) call.argument("flag"); - serviceWorkerWebSettings.setBlockNetworkLoads(flag); - } - result.success(true); - break; - case "setCacheMode": - if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_CACHE_MODE)) { - Integer mode = (Integer) call.argument("mode"); - serviceWorkerWebSettings.setCacheMode(mode); - } - result.success(true); - break; - default: - result.notImplemented(); - } - } - - public static class ShouldInterceptRequestCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public WebResourceResponseExt decodeResult(@Nullable Object obj) { - return WebResourceResponseExt.fromMap((Map) obj); - } - } - - public void shouldInterceptRequest(WebResourceRequestExt request, @NonNull ShouldInterceptRequestCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) return; - channel.invokeMethod("shouldInterceptRequest", request.toMap(), callback); - } - - public static class SyncShouldInterceptRequestCallback extends SyncBaseCallbackResultImpl { - @Nullable - @Override - public WebResourceResponseExt decodeResult(@Nullable Object obj) { - return (new ShouldInterceptRequestCallback()).decodeResult(obj); - } - } - - @Nullable - public WebResourceResponseExt shouldInterceptRequest(WebResourceRequestExt request) throws InterruptedException { - MethodChannel channel = getChannel(); - if (channel == null) return null; - final SyncShouldInterceptRequestCallback callback = new SyncShouldInterceptRequestCallback(); - return Util.invokeMethodAndWaitResult(channel, "shouldInterceptRequest", request.toMap(), callback); - } - - @Override - public void dispose() { - super.dispose(); - serviceWorkerManager = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/service_worker/ServiceWorkerManager.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/service_worker/ServiceWorkerManager.java deleted file mode 100755 index 4dde63e7ea..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/service_worker/ServiceWorkerManager.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.service_worker; - -import android.os.Build; -import android.util.Log; -import android.webkit.WebResourceRequest; -import android.webkit.WebResourceResponse; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; -import androidx.webkit.ServiceWorkerClientCompat; -import androidx.webkit.ServiceWorkerControllerCompat; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.types.Disposable; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebResourceRequestExt; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebResourceResponseExt; - -import java.io.ByteArrayInputStream; -import java.util.Map; - -import io.flutter.plugin.common.MethodChannel; - -@RequiresApi(api = Build.VERSION_CODES.N) -public class ServiceWorkerManager implements Disposable { - protected static final String LOG_TAG = "ServiceWorkerManager"; - public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_serviceworkercontroller"; - - @Nullable - public ServiceWorkerChannelDelegate channelDelegate; - @Nullable - public static ServiceWorkerControllerCompat serviceWorkerController; - @Nullable - public InAppWebViewFlutterPlugin plugin; - - public ServiceWorkerManager(@NonNull final InAppWebViewFlutterPlugin plugin) { - this.plugin = plugin; - final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME); - this.channelDelegate = new ServiceWorkerChannelDelegate(this, channel); - } - - public static void init() { - if (serviceWorkerController == null && - WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_BASIC_USAGE)) { - serviceWorkerController = ServiceWorkerControllerCompat.getInstance(); - } - } - - public void setServiceWorkerClient(Boolean isNull) { - if (serviceWorkerController != null) { - // set ServiceWorkerClient as null makes the app crashes, so just set a dummy ServiceWorkerClientCompat. - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1151 - serviceWorkerController.setServiceWorkerClient(isNull ? dummyServiceWorkerClientCompat() : new ServiceWorkerClientCompat() { - @Nullable - @Override - public WebResourceResponse shouldInterceptRequest(@NonNull WebResourceRequest request) { - WebResourceRequestExt requestExt = WebResourceRequestExt.fromWebResourceRequest(request); - - WebResourceResponseExt response = null; - if (channelDelegate != null) { - try { - response = channelDelegate.shouldInterceptRequest(requestExt); - } catch (InterruptedException e) { - Log.e(LOG_TAG, "", e); - return null; - } - } - - if (response != null) { - String contentType = response.getContentType(); - String contentEncoding = response.getContentEncoding(); - byte[] data = response.getData(); - Map responseHeaders = response.getHeaders(); - Integer statusCode = response.getStatusCode(); - String reasonPhrase = response.getReasonPhrase(); - - ByteArrayInputStream inputStream = (data != null) ? new ByteArrayInputStream(data) : null; - - if (statusCode != null && reasonPhrase != null) { - return new WebResourceResponse(contentType, contentEncoding, statusCode, reasonPhrase, responseHeaders, inputStream); - } else { - return new WebResourceResponse(contentType, contentEncoding, inputStream); - } - } - - return null; - } - }); - } - } - - private ServiceWorkerClientCompat dummyServiceWorkerClientCompat() { - return DummyServiceWorkerClientCompat.INSTANCE; - } - - @Override - public void dispose() { - if (channelDelegate != null) { - channelDelegate.dispose(); - channelDelegate = null; - } - plugin = null; - } - - private static final class DummyServiceWorkerClientCompat extends ServiceWorkerClientCompat { - static final ServiceWorkerClientCompat INSTANCE = new DummyServiceWorkerClientCompat(); - - @Nullable - @Override - public WebResourceResponse shouldInterceptRequest(@NonNull WebResourceRequest request) { - return null; - } - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/tracing/TracingControllerChannelDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/tracing/TracingControllerChannelDelegate.java deleted file mode 100755 index e6b957a540..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/tracing/TracingControllerChannelDelegate.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.tracing; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.TracingConfig; -import androidx.webkit.TracingController; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; - -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.util.Map; -import java.util.concurrent.Executors; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class TracingControllerChannelDelegate extends ChannelDelegateImpl { - @Nullable - private TracingControllerManager tracingControllerManager; - - public TracingControllerChannelDelegate(@NonNull TracingControllerManager tracingControllerManager, @NonNull MethodChannel channel) { - super(channel); - this.tracingControllerManager = tracingControllerManager; - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - TracingControllerManager.init(); - TracingController tracingController = TracingControllerManager.tracingController; - - switch (call.method) { - case "isTracing": - if (tracingController != null) { - result.success(tracingController.isTracing()); - } else { - result.success(false); - } - break; - case "start": - if (tracingController != null && WebViewFeature.isFeatureSupported(WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE)) { - Map settingsMap = (Map) call.argument("settings"); - TracingSettings settings = new TracingSettings(); - settings.parse(settingsMap); - TracingConfig config = TracingControllerManager.buildTracingConfig(settings); - tracingController.start(config); - result.success(true); - } else { - result.success(false); - } - break; - case "stop": - if (tracingController != null && WebViewFeature.isFeatureSupported(WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE)) { - String filePath = (String) call.argument("filePath"); - try { - result.success(tracingController.stop( - filePath != null ? new FileOutputStream(filePath) : null, - Executors.newSingleThreadExecutor())); - } catch (FileNotFoundException e) { - e.printStackTrace(); - result.success(false); - } - } else { - result.success(false); - } - break; - default: - result.notImplemented(); - } - } - - @Override - public void dispose() { - super.dispose(); - tracingControllerManager = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/tracing/TracingControllerManager.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/tracing/TracingControllerManager.java deleted file mode 100755 index 6c48c5bb57..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/tracing/TracingControllerManager.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.tracing; - -import androidx.annotation.Nullable; -import androidx.webkit.TracingConfig; -import androidx.webkit.TracingController; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.types.Disposable; - -import io.flutter.plugin.common.MethodChannel; - -public class TracingControllerManager implements Disposable { - protected static final String LOG_TAG = "TracingControllerMan"; - public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_tracingcontroller"; - - @Nullable - public TracingControllerChannelDelegate channelDelegate; - @Nullable - public static TracingController tracingController; - @Nullable - public InAppWebViewFlutterPlugin plugin; - - public TracingControllerManager(final InAppWebViewFlutterPlugin plugin) { - this.plugin = plugin; - final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME); - this.channelDelegate = new TracingControllerChannelDelegate(this, channel); - } - - public static void init() { - if (tracingController == null && - WebViewFeature.isFeatureSupported(WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE)) { - tracingController = TracingController.getInstance(); - } - } - - public static TracingConfig buildTracingConfig(TracingSettings settings) { - TracingConfig.Builder builder = new TracingConfig.Builder(); - for (Object category : settings.categories) { - if (category instanceof String) { - builder.addCategories((String) category); - } - if (category instanceof Integer) { - builder.addCategories((Integer) category); - } - } - if (settings.tracingMode != null) { - builder.setTracingMode(settings.tracingMode); - } - return builder.build(); - } - - @Override - public void dispose() { - if (channelDelegate != null) { - channelDelegate.dispose(); - channelDelegate = null; - } - plugin = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/tracing/TracingSettings.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/tracing/TracingSettings.java deleted file mode 100755 index bcf0bd550b..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/tracing/TracingSettings.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.tracing; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.TracingController; - -import com.pichillilorenzo.flutter_inappwebview_android.ISettings; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class TracingSettings implements ISettings { - - public static final String LOG_TAG = "TracingSettings"; - - @NonNull - public List categories = new ArrayList<>(); - @Nullable - public Integer tracingMode; - - @NonNull - @Override - public TracingSettings parse(@NonNull Map settings) { - for (Map.Entry pair : settings.entrySet()) { - String key = pair.getKey(); - Object value = pair.getValue(); - if (value == null) { - continue; - } - - switch (key) { - case "categories": - categories = (List) value; - break; - case "tracingMode": - tracingMode = (Integer) value; - break; - } - } - - return this; - } - - @NonNull - @Override - public Map toMap() { - Map settings = new HashMap<>(); - settings.put("categories", categories); - settings.put("tracingMode", tracingMode); - return settings; - } - - @NonNull - @Override - public Map getRealSettings(@NonNull TracingController tracingController) { - Map realSettings = toMap(); - return realSettings; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/AndroidResource.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/AndroidResource.java deleted file mode 100644 index 6db0d083ad..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/AndroidResource.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.HashMap; -import java.util.Map; - -public class AndroidResource { - @NonNull - private String name; - @Nullable - private String defType; - @Nullable - private String defPackage; - - public AndroidResource(@NonNull String name, @Nullable String defType, @Nullable String defPackage) { - this.name = name; - this.defType = defType; - this.defPackage = defPackage; - } - - @Nullable - public static AndroidResource fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String name = (String) map.get("name"); - String defType = (String) map.get("defType"); - String defPackage = (String) map.get("defPackage"); - return new AndroidResource(name, defType, defPackage); - } - - public Map toMap() { - Map urlRequestMap = new HashMap<>(); - urlRequestMap.put("name", name); - urlRequestMap.put("defType", defType); - urlRequestMap.put("defPackage", defPackage); - return urlRequestMap; - } - - @NonNull - public String getName() { - return name; - } - - public void setName(@NonNull String name) { - this.name = name; - } - - @Nullable - public String getDefType() { - return defType; - } - - public void setDefType(@Nullable String defType) { - this.defType = defType; - } - - @Nullable - public String getDefPackage() { - return defPackage; - } - - public void setDefPackage(@Nullable String defPackage) { - this.defPackage = defPackage; - } - - public int getIdentifier(@NonNull Context ctx) { - return ctx.getResources().getIdentifier(name, defType, defPackage); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - AndroidResource that = (AndroidResource) o; - - if (!name.equals(that.name)) return false; - if (defType != null ? !defType.equals(that.defType) : that.defType != null) return false; - return defPackage != null ? defPackage.equals(that.defPackage) : that.defPackage == null; - } - - @Override - public int hashCode() { - int result = name.hashCode(); - result = 31 * result + (defType != null ? defType.hashCode() : 0); - result = 31 * result + (defPackage != null ? defPackage.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "AndroidResource{" + - "name='" + name + '\'' + - ", type='" + defType + '\'' + - ", defPackage='" + defPackage + '\'' + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/BaseCallbackResultImpl.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/BaseCallbackResultImpl.java deleted file mode 100644 index bd23e53a39..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/BaseCallbackResultImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -public class BaseCallbackResultImpl implements ICallbackResult { - @Override - public boolean nonNullSuccess(@NonNull T result) { - return true; - } - - @Override - public boolean nullSuccess() { - return true; - } - - @Override - public void defaultBehaviour(@Nullable T result) {} - - @Override - public void success(@Nullable Object obj) { - T result = decodeResult(obj); - boolean shouldRunDefaultBehaviour; - if (result == null) { - shouldRunDefaultBehaviour = nullSuccess(); - } else { - shouldRunDefaultBehaviour = nonNullSuccess(result); - } - if (shouldRunDefaultBehaviour) { - defaultBehaviour(result); - } - } - - @Nullable - @Override - public T decodeResult(@Nullable Object obj) { - return null; - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) {} - - @Override - public void notImplemented() { - defaultBehaviour(null); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ChannelDelegateImpl.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ChannelDelegateImpl.java deleted file mode 100644 index 450a61b023..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ChannelDelegateImpl.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.CallSuper; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class ChannelDelegateImpl implements IChannelDelegate { - @Nullable - private MethodChannel channel; - - public ChannelDelegateImpl(@NonNull MethodChannel channel) { - this.channel = channel; - this.channel.setMethodCallHandler(this); - } - - @Override - @Nullable - public MethodChannel getChannel() { - return channel; - } - - @CallSuper - public void dispose() { - if (channel != null) { - channel.setMethodCallHandler(null); - channel = null; - } - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ClientCertChallenge.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ClientCertChallenge.java deleted file mode 100644 index 1bb5afebb4..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ClientCertChallenge.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.Nullable; - -import java.security.Principal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -public class ClientCertChallenge extends URLAuthenticationChallenge { - @Nullable - private Principal[] principals; - @Nullable - private String[] keyTypes; - - public ClientCertChallenge(URLProtectionSpace protectionSpace, @Nullable Principal[] principals, @Nullable String[] keyTypes) { - super(protectionSpace); - this.principals = principals; - this.keyTypes = keyTypes; - } - - public Map toMap() { - List principalList = null; - if (principals != null) { - principalList = new ArrayList<>(); - for (Principal principal : principals) { - principalList.add(principal.getName()); - } - } - - Map challengeMap = super.toMap(); - challengeMap.put("principals", principalList); - challengeMap.put("keyTypes", keyTypes != null ? Arrays.asList(keyTypes) : null); - return challengeMap; - } - - @Nullable - public Principal[] getPrincipals() { - return principals; - } - - public void setPrincipals(@Nullable Principal[] principals) { - this.principals = principals; - } - - @Nullable - public String[] getKeyTypes() { - return keyTypes; - } - - public void setKeyTypes(@Nullable String[] keyTypes) { - this.keyTypes = keyTypes; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - - ClientCertChallenge that = (ClientCertChallenge) o; - - // Probably incorrect - comparing Object[] arrays with Arrays.equals - if (!Arrays.equals(principals, that.principals)) return false; - // Probably incorrect - comparing Object[] arrays with Arrays.equals - return Arrays.equals(keyTypes, that.keyTypes); - } - - @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + Arrays.hashCode(principals); - result = 31 * result + Arrays.hashCode(keyTypes); - return result; - } - - @Override - public String toString() { - return "ClientCertChallenge{" + - "principals=" + Arrays.toString(principals) + - ", keyTypes=" + Arrays.toString(keyTypes) + - "} " + super.toString(); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ClientCertResponse.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ClientCertResponse.java deleted file mode 100644 index cbd4349d0d..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ClientCertResponse.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Map; - -public class ClientCertResponse { - @NonNull - private String certificatePath; - @Nullable - private String certificatePassword; - @NonNull - private String keyStoreType; - @Nullable - private Integer action; - - public ClientCertResponse(@NonNull String certificatePath, @Nullable String certificatePassword, @NonNull String keyStoreType, @Nullable Integer action) { - this.certificatePath = certificatePath; - this.certificatePassword = certificatePassword; - this.keyStoreType = keyStoreType; - this.action = action; - } - - @Nullable - public static ClientCertResponse fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String certificatePath = (String) map.get("certificatePath"); - String certificatePassword = (String) map.get("certificatePassword"); - String keyStoreType = (String) map.get("keyStoreType"); - Integer action = (Integer) map.get("action"); - return new ClientCertResponse(certificatePath, certificatePassword, keyStoreType, action); - } - - @NonNull - public String getCertificatePath() { - return certificatePath; - } - - public void setCertificatePath(@NonNull String certificatePath) { - this.certificatePath = certificatePath; - } - - @Nullable - public String getCertificatePassword() { - return certificatePassword; - } - - public void setCertificatePassword(@Nullable String certificatePassword) { - this.certificatePassword = certificatePassword; - } - - @NonNull - public String getKeyStoreType() { - return keyStoreType; - } - - public void setKeyStoreType(@NonNull String keyStoreType) { - this.keyStoreType = keyStoreType; - } - - @Nullable - public Integer getAction() { - return action; - } - - public void setAction(@Nullable Integer action) { - this.action = action; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ClientCertResponse that = (ClientCertResponse) o; - - if (!certificatePath.equals(that.certificatePath)) return false; - if (certificatePassword != null ? !certificatePassword.equals(that.certificatePassword) : that.certificatePassword != null) - return false; - if (!keyStoreType.equals(that.keyStoreType)) return false; - return action != null ? action.equals(that.action) : that.action == null; - } - - @Override - public int hashCode() { - int result = certificatePath.hashCode(); - result = 31 * result + (certificatePassword != null ? certificatePassword.hashCode() : 0); - result = 31 * result + keyStoreType.hashCode(); - result = 31 * result + (action != null ? action.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "ClientCertResponse{" + - "certificatePath='" + certificatePath + '\'' + - ", certificatePassword='" + certificatePassword + '\'' + - ", keyStoreType='" + keyStoreType + '\'' + - ", action=" + action + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ContentWorld.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ContentWorld.java deleted file mode 100644 index 8c1fd25ae0..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ContentWorld.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Map; - -public class ContentWorld { - @NonNull - private String name; - - public static final ContentWorld PAGE = new ContentWorld("page"); - public static final ContentWorld DEFAULT_CLIENT = new ContentWorld("defaultClient"); - - private ContentWorld(@NonNull String name) { - this.name = name; - } - - public static ContentWorld world(@NonNull String name) { - return new ContentWorld(name); - } - - @Nullable - public static ContentWorld fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String name = (String) map.get("name"); - assert name != null; - return new ContentWorld(name); - } - - @NonNull - public String getName() { - return name; - } - - public void setName(@NonNull String name) { - this.name = name; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ContentWorld that = (ContentWorld) o; - - return name.equals(that.name); - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public String toString() { - return "ContentWorld{" + - "name='" + name + '\'' + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/CreateWindowAction.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/CreateWindowAction.java deleted file mode 100644 index d12b225f1e..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/CreateWindowAction.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import java.util.Map; - -public class CreateWindowAction extends NavigationAction { - int windowId; - boolean isDialog; - - public CreateWindowAction(URLRequest request, boolean isForMainFrame, boolean hasGesture, boolean isRedirect, int windowId, boolean isDialog) { - super(request, isForMainFrame, hasGesture, isRedirect); - this.windowId = windowId; - this.isDialog = isDialog; - } - - public Map toMap() { - Map createWindowActionMap = super.toMap(); - createWindowActionMap.put("windowId", windowId); - createWindowActionMap.put("isDialog", isDialog); - createWindowActionMap.put("windowFeatures", null); - return createWindowActionMap; - } - - public int getWindowId() { - return windowId; - } - - public void setWindowId(int windowId) { - this.windowId = windowId; - } - - public boolean isDialog() { - return isDialog; - } - - public void setDialog(boolean dialog) { - isDialog = dialog; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - - CreateWindowAction that = (CreateWindowAction) o; - - if (windowId != that.windowId) return false; - return isDialog == that.isDialog; - } - - @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + windowId; - result = 31 * result + (isDialog ? 1 : 0); - return result; - } - - @Override - public String toString() { - return "CreateWindowAction{" + - "windowId=" + windowId + - ", isDialog=" + isDialog + - ", request=" + request + - ", isForMainFrame=" + isForMainFrame + - ", hasGesture=" + hasGesture + - ", isRedirect=" + isRedirect + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/CustomSchemeResponse.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/CustomSchemeResponse.java deleted file mode 100644 index 50bac1022e..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/CustomSchemeResponse.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Arrays; -import java.util.Map; - -public class CustomSchemeResponse { - @NonNull - private byte[] data; - @NonNull - private String contentType; - @NonNull - private String contentEncoding; - - public CustomSchemeResponse(@NonNull byte[] data, @NonNull String contentType, @NonNull String contentEncoding) { - this.data = data; - this.contentType = contentType; - this.contentEncoding = contentEncoding; - } - - @Nullable - public static CustomSchemeResponse fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - byte[] data = (byte[]) map.get("data"); - String contentType = (String) map.get("contentType"); - String contentEncoding = (String) map.get("contentEncoding"); - return new CustomSchemeResponse(data, contentType, contentEncoding); - } - - @NonNull - public byte[] getData() { - return data; - } - - public void setData(@NonNull byte[] data) { - this.data = data; - } - - @NonNull - public String getContentType() { - return contentType; - } - - public void setContentType(@NonNull String contentType) { - this.contentType = contentType; - } - - @NonNull - public String getContentEncoding() { - return contentEncoding; - } - - public void setContentEncoding(@NonNull String contentEncoding) { - this.contentEncoding = contentEncoding; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - CustomSchemeResponse that = (CustomSchemeResponse) o; - - if (!Arrays.equals(data, that.data)) return false; - if (!contentType.equals(that.contentType)) return false; - return contentEncoding.equals(that.contentEncoding); - } - - @Override - public int hashCode() { - int result = Arrays.hashCode(data); - result = 31 * result + contentType.hashCode(); - result = 31 * result + contentEncoding.hashCode(); - return result; - } - - @Override - public String toString() { - return "CustomSchemeResponse{" + - "data=" + Arrays.toString(data) + - ", contentType='" + contentType + '\'' + - ", contentEncoding='" + contentEncoding + '\'' + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/CustomTabsActionButton.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/CustomTabsActionButton.java deleted file mode 100644 index b408d32fe2..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/CustomTabsActionButton.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Arrays; -import java.util.Map; - -public class CustomTabsActionButton { - private int id; - - @NonNull - private byte[] icon; - - @NonNull - private String description; - - private boolean shouldTint; - - public CustomTabsActionButton(int id, @NonNull byte[] icon, @NonNull String description, boolean shouldTint) { - this.id = id; - this.icon = icon; - this.description = description; - this.shouldTint = shouldTint; - } - - @Nullable - public static CustomTabsActionButton fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - int id = (int) map.get("id"); - byte[] icon = (byte[]) map.get("icon"); - String description = (String) map.get("description"); - boolean shouldTint = (boolean) map.get("shouldTint"); - return new CustomTabsActionButton(id, icon, description, shouldTint); - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @NonNull - public byte[] getIcon() { - return icon; - } - - public void setIcon(@NonNull byte[] icon) { - this.icon = icon; - } - - @NonNull - public String getDescription() { - return description; - } - - public void setDescription(@NonNull String description) { - this.description = description; - } - - public boolean isShouldTint() { - return shouldTint; - } - - public void setShouldTint(boolean shouldTint) { - this.shouldTint = shouldTint; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - CustomTabsActionButton that = (CustomTabsActionButton) o; - - if (id != that.id) return false; - if (shouldTint != that.shouldTint) return false; - if (!Arrays.equals(icon, that.icon)) return false; - return description.equals(that.description); - } - - @Override - public int hashCode() { - int result = id; - result = 31 * result + Arrays.hashCode(icon); - result = 31 * result + description.hashCode(); - result = 31 * result + (shouldTint ? 1 : 0); - return result; - } - - @Override - public String toString() { - return "CustomTabsActionButton{" + - "id=" + id + - ", icon=" + Arrays.toString(icon) + - ", description='" + description + '\'' + - ", shouldTint=" + shouldTint + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/CustomTabsMenuItem.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/CustomTabsMenuItem.java deleted file mode 100644 index 34cf997008..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/CustomTabsMenuItem.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Map; - -public class CustomTabsMenuItem { - private int id; - - @NonNull - private String label; - - public CustomTabsMenuItem(int id, @NonNull String label) { - this.id = id; - this.label = label; - } - - @Nullable - public static CustomTabsMenuItem fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - int id = (int) map.get("id"); - String label = (String) map.get("label"); - return new CustomTabsMenuItem(id, label); - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @NonNull - public String getLabel() { - return label; - } - - public void setLabel(@NonNull String label) { - this.label = label; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - CustomTabsMenuItem that = (CustomTabsMenuItem) o; - - if (id != that.id) return false; - return label.equals(that.label); - } - - @Override - public int hashCode() { - int result = id; - result = 31 * result + label.hashCode(); - return result; - } - - @Override - public String toString() { - return "CustomTabsMenuItem{" + - "id=" + id + - ", label='" + label + '\'' + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/CustomTabsSecondaryToolbar.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/CustomTabsSecondaryToolbar.java deleted file mode 100644 index 7db298ece6..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/CustomTabsSecondaryToolbar.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class CustomTabsSecondaryToolbar { - @NonNull - private AndroidResource layout; - @NonNull - private List clickableIDs = new ArrayList<>(); - - public CustomTabsSecondaryToolbar(@NonNull AndroidResource layout, @NonNull List clickableIDs) { - this.layout = layout; - this.clickableIDs = clickableIDs; - } - - @Nullable - public static CustomTabsSecondaryToolbar fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - AndroidResource layout = AndroidResource.fromMap((Map) map.get("layout")); - List clickableIDs = new ArrayList<>(); - List> clickableIDList = (List>) map.get("clickableIDs"); - if (clickableIDList != null) { - for (Map clickableIDMap : clickableIDList) { - AndroidResource clickableID = AndroidResource.fromMap((Map) clickableIDMap.get("id")); - if (clickableID != null) { - clickableIDs.add(clickableID); - } - } - } - return new CustomTabsSecondaryToolbar(layout, clickableIDs); - } - - @NonNull - public AndroidResource getLayout() { - return layout; - } - - public void setLayout(@NonNull AndroidResource layout) { - this.layout = layout; - } - - @NonNull - public List getClickableIDs() { - return clickableIDs; - } - - public void setClickableIDs(@NonNull List clickableIDs) { - this.clickableIDs = clickableIDs; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - CustomTabsSecondaryToolbar that = (CustomTabsSecondaryToolbar) o; - - if (!layout.equals(that.layout)) return false; - return clickableIDs.equals(that.clickableIDs); - } - - @Override - public int hashCode() { - int result = layout.hashCode(); - result = 31 * result + clickableIDs.hashCode(); - return result; - } - - @Override - public String toString() { - return "CustomTabsSecondaryToolbar{" + - "layout=" + layout + - ", clickableIDs=" + clickableIDs + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/Disposable.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/Disposable.java deleted file mode 100644 index 0cd54c0d77..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/Disposable.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -public interface Disposable { - void dispose(); -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/DownloadStartRequest.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/DownloadStartRequest.java deleted file mode 100644 index 3dd8d3b17a..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/DownloadStartRequest.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.HashMap; -import java.util.Map; - -public class DownloadStartRequest { - - @NonNull - private String url; - @NonNull - private String userAgent; - @NonNull - private String contentDisposition; - @NonNull - private String mimeType; - private long contentLength; - @Nullable - private String suggestedFilename; - @Nullable - private String textEncodingName; - - public DownloadStartRequest(@NonNull String url, @NonNull String userAgent, @NonNull String contentDisposition, @NonNull String mimeType, long contentLength, @Nullable String suggestedFilename, @Nullable String textEncodingName) { - this.url = url; - this.userAgent = userAgent; - this.contentDisposition = contentDisposition; - this.mimeType = mimeType; - this.contentLength = contentLength; - this.suggestedFilename = suggestedFilename; - this.textEncodingName = textEncodingName; - } - - public Map toMap() { - Map obj = new HashMap<>(); - obj.put("url", url); - obj.put("userAgent", userAgent); - obj.put("contentDisposition", contentDisposition); - obj.put("mimeType", mimeType); - obj.put("contentLength", contentLength); - obj.put("suggestedFilename", suggestedFilename); - obj.put("textEncodingName", textEncodingName); - return obj; - } - - @NonNull - public String getUrl() { - return url; - } - - public void setUrl(@NonNull String url) { - this.url = url; - } - - @NonNull - public String getUserAgent() { - return userAgent; - } - - public void setUserAgent(@NonNull String userAgent) { - this.userAgent = userAgent; - } - - @NonNull - public String getContentDisposition() { - return contentDisposition; - } - - public void setContentDisposition(@NonNull String contentDisposition) { - this.contentDisposition = contentDisposition; - } - - @NonNull - public String getMimeType() { - return mimeType; - } - - public void setMimeType(@NonNull String mimeType) { - this.mimeType = mimeType; - } - - public long getContentLength() { - return contentLength; - } - - public void setContentLength(long contentLength) { - this.contentLength = contentLength; - } - - @Nullable - public String getSuggestedFilename() { - return suggestedFilename; - } - - public void setSuggestedFilename(@Nullable String suggestedFilename) { - this.suggestedFilename = suggestedFilename; - } - - @Nullable - public String getTextEncodingName() { - return textEncodingName; - } - - public void setTextEncodingName(@Nullable String textEncodingName) { - this.textEncodingName = textEncodingName; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - DownloadStartRequest that = (DownloadStartRequest) o; - - if (contentLength != that.contentLength) return false; - if (!url.equals(that.url)) return false; - if (!userAgent.equals(that.userAgent)) return false; - if (!contentDisposition.equals(that.contentDisposition)) return false; - if (!mimeType.equals(that.mimeType)) return false; - if (suggestedFilename != null ? !suggestedFilename.equals(that.suggestedFilename) : that.suggestedFilename != null) - return false; - return textEncodingName != null ? textEncodingName.equals(that.textEncodingName) : that.textEncodingName == null; - } - - @Override - public int hashCode() { - int result = url.hashCode(); - result = 31 * result + userAgent.hashCode(); - result = 31 * result + contentDisposition.hashCode(); - result = 31 * result + mimeType.hashCode(); - result = 31 * result + (int) (contentLength ^ (contentLength >>> 32)); - result = 31 * result + (suggestedFilename != null ? suggestedFilename.hashCode() : 0); - result = 31 * result + (textEncodingName != null ? textEncodingName.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "DownloadStartRequest{" + - "url='" + url + '\'' + - ", userAgent='" + userAgent + '\'' + - ", contentDisposition='" + contentDisposition + '\'' + - ", mimeType='" + mimeType + '\'' + - ", contentLength=" + contentLength + - ", suggestedFilename='" + suggestedFilename + '\'' + - ", textEncodingName='" + textEncodingName + '\'' + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/FindSession.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/FindSession.java deleted file mode 100644 index a4df7d73bc..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/FindSession.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import java.util.HashMap; -import java.util.Map; - -public class FindSession { - private int resultCount; - private int highlightedResultIndex; - private int searchResultDisplayStyle = 2; // matches NONE of iOS - - public FindSession(int resultCount, int highlightedResultIndex) { - this.resultCount = resultCount; - this.highlightedResultIndex = highlightedResultIndex; - } - - public Map toMap() { - Map obj = new HashMap<>(); - obj.put("resultCount", resultCount); - obj.put("highlightedResultIndex", highlightedResultIndex); - obj.put("searchResultDisplayStyle", searchResultDisplayStyle); - return obj; - } - - public int getResultCount() { - return resultCount; - } - - public void setResultCount(int resultCount) { - this.resultCount = resultCount; - } - - public int getHighlightedResultIndex() { - return highlightedResultIndex; - } - - public void setHighlightedResultIndex(int highlightedResultIndex) { - this.highlightedResultIndex = highlightedResultIndex; - } - - public int getSearchResultDisplayStyle() { - return searchResultDisplayStyle; - } - - public void setSearchResultDisplayStyle(int searchResultDisplayStyle) { - this.searchResultDisplayStyle = searchResultDisplayStyle; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - FindSession that = (FindSession) o; - - if (resultCount != that.resultCount) return false; - if (highlightedResultIndex != that.highlightedResultIndex) return false; - return searchResultDisplayStyle == that.searchResultDisplayStyle; - } - - @Override - public int hashCode() { - int result = resultCount; - result = 31 * result + highlightedResultIndex; - result = 31 * result + searchResultDisplayStyle; - return result; - } - - @Override - public String toString() { - return "FindSession{" + - "resultCount=" + resultCount + - ", highlightedResultIndex=" + highlightedResultIndex + - ", searchResultDisplayStyle=" + searchResultDisplayStyle + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/GeolocationPermissionShowPromptResponse.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/GeolocationPermissionShowPromptResponse.java deleted file mode 100644 index 14340e9a16..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/GeolocationPermissionShowPromptResponse.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Map; - -public class GeolocationPermissionShowPromptResponse { - @NonNull - private String origin; - boolean allow; - boolean retain; - - public GeolocationPermissionShowPromptResponse(@NonNull String origin, boolean allow, boolean retain) { - this.origin = origin; - this.allow = allow; - this.retain = retain; - } - - @Nullable - public static GeolocationPermissionShowPromptResponse fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String origin = (String) map.get("origin"); - boolean allow = (boolean) map.get("allow"); - boolean retain = (boolean) map.get("retain"); - return new GeolocationPermissionShowPromptResponse(origin, allow, retain); - } - - @NonNull - public String getOrigin() { - return origin; - } - - public void setOrigin(@NonNull String origin) { - this.origin = origin; - } - - public boolean isAllow() { - return allow; - } - - public void setAllow(boolean allow) { - this.allow = allow; - } - - public boolean isRetain() { - return retain; - } - - public void setRetain(boolean retain) { - this.retain = retain; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - GeolocationPermissionShowPromptResponse that = (GeolocationPermissionShowPromptResponse) o; - - if (allow != that.allow) return false; - if (retain != that.retain) return false; - return origin.equals(that.origin); - } - - @Override - public int hashCode() { - int result = origin.hashCode(); - result = 31 * result + (allow ? 1 : 0); - result = 31 * result + (retain ? 1 : 0); - return result; - } - - @Override - public String toString() { - return "GeolocationPermissionShowPromptResponse{" + - "origin='" + origin + '\'' + - ", allow=" + allow + - ", retain=" + retain + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/HitTestResult.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/HitTestResult.java deleted file mode 100644 index 87615fa532..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/HitTestResult.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.webkit.WebView; - -import androidx.annotation.Nullable; - -import java.util.HashMap; -import java.util.Map; - -public class HitTestResult { - private int type; - @Nullable - private String extra; - - public HitTestResult(int type, @Nullable String extra) { - this.type = type; - this.extra = extra; - } - - @Nullable - static public HitTestResult fromWebViewHitTestResult(@Nullable WebView.HitTestResult hitTestResult) { - if (hitTestResult == null) { - return null; - } - - return new HitTestResult(hitTestResult.getType(), hitTestResult.getExtra()); - } - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } - - @Nullable - public String getExtra() { - return extra; - } - - public void setExtra(@Nullable String extra) { - this.extra = extra; - } - - @Nullable - public Map toMap() { - Map hitTestResultMap = new HashMap<>(); - hitTestResultMap.put("type", type); - hitTestResultMap.put("extra", extra); - return hitTestResultMap; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - HitTestResult that = (HitTestResult) o; - - if (type != that.type) return false; - return extra != null ? extra.equals(that.extra) : that.extra == null; - } - - @Override - public int hashCode() { - int result = type; - result = 31 * result + (extra != null ? extra.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "HitTestResultMap{" + - "type=" + type + - ", extra='" + extra + '\'' + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/HttpAuthResponse.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/HttpAuthResponse.java deleted file mode 100644 index 123a1b025f..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/HttpAuthResponse.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Map; - -public class HttpAuthResponse { - @NonNull - private String username; - @NonNull - private String password; - boolean permanentPersistence; - @Nullable - private Integer action; - - public HttpAuthResponse(@NonNull String username, @NonNull String password, boolean permanentPersistence, @Nullable Integer action) { - this.username = username; - this.password = password; - this.permanentPersistence = permanentPersistence; - this.action = action; - } - - @Nullable - public static HttpAuthResponse fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String username = (String) map.get("username"); - String password = (String) map.get("password"); - boolean permanentPersistence = (boolean) map.get("permanentPersistence"); - Integer action = (Integer) map.get("action"); - return new HttpAuthResponse(username, password, permanentPersistence, action); - } - - @NonNull - public String getUsername() { - return username; - } - - public void setUsername(@NonNull String username) { - this.username = username; - } - - @NonNull - public String getPassword() { - return password; - } - - public void setPassword(@NonNull String password) { - this.password = password; - } - - public boolean isPermanentPersistence() { - return permanentPersistence; - } - - public void setPermanentPersistence(boolean permanentPersistence) { - this.permanentPersistence = permanentPersistence; - } - - @Nullable - public Integer getAction() { - return action; - } - - public void setAction(@Nullable Integer action) { - this.action = action; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - HttpAuthResponse that = (HttpAuthResponse) o; - - if (permanentPersistence != that.permanentPersistence) return false; - if (!username.equals(that.username)) return false; - if (!password.equals(that.password)) return false; - return action != null ? action.equals(that.action) : that.action == null; - } - - @Override - public int hashCode() { - int result = username.hashCode(); - result = 31 * result + password.hashCode(); - result = 31 * result + (permanentPersistence ? 1 : 0); - result = 31 * result + (action != null ? action.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "HttpAuthResponse{" + - "username='" + username + '\'' + - ", password='" + password + '\'' + - ", permanentPersistence=" + permanentPersistence + - ", action=" + action + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/HttpAuthenticationChallenge.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/HttpAuthenticationChallenge.java deleted file mode 100644 index 66edfa4ac7..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/HttpAuthenticationChallenge.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.Nullable; - -import java.util.Map; - -public class HttpAuthenticationChallenge extends URLAuthenticationChallenge { - private int previousFailureCount; - @Nullable - URLCredential proposedCredential; - - public HttpAuthenticationChallenge(URLProtectionSpace protectionSpace, int previousFailureCount, @Nullable URLCredential proposedCredential) { - super(protectionSpace); - this.previousFailureCount = previousFailureCount; - this.proposedCredential = proposedCredential; - } - - public Map toMap() { - Map challengeMap = super.toMap(); - challengeMap.put("previousFailureCount", previousFailureCount); - challengeMap.put("proposedCredential", (proposedCredential != null) ? proposedCredential.toMap() : null); - challengeMap.put("failureResponse", null); - challengeMap.put("error", null); - return challengeMap; - } - - public int getPreviousFailureCount() { - return previousFailureCount; - } - - public void setPreviousFailureCount(int previousFailureCount) { - this.previousFailureCount = previousFailureCount; - } - - @Nullable - public URLCredential getProposedCredential() { - return proposedCredential; - } - - public void setProposedCredential(@Nullable URLCredential proposedCredential) { - this.proposedCredential = proposedCredential; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - - HttpAuthenticationChallenge that = (HttpAuthenticationChallenge) o; - - if (previousFailureCount != that.previousFailureCount) return false; - return proposedCredential != null ? proposedCredential.equals(that.proposedCredential) : that.proposedCredential == null; - } - - @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + previousFailureCount; - result = 31 * result + (proposedCredential != null ? proposedCredential.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "HttpAuthenticationChallenge{" + - "previousFailureCount=" + previousFailureCount + - ", proposedCredential=" + proposedCredential + - "} " + super.toString(); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ICallbackResult.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ICallbackResult.java deleted file mode 100644 index 02515fca11..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ICallbackResult.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import io.flutter.plugin.common.MethodChannel; - -public interface ICallbackResult extends MethodChannel.Result { - boolean nonNullSuccess(@NonNull T result); - boolean nullSuccess(); - void defaultBehaviour(@Nullable T result); - @Nullable T decodeResult(@Nullable Object obj); -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/IChannelDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/IChannelDelegate.java deleted file mode 100644 index 4d1ca8f82b..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/IChannelDelegate.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.Nullable; - -import io.flutter.plugin.common.MethodChannel; - -public interface IChannelDelegate extends MethodChannel.MethodCallHandler, Disposable { - @Nullable - MethodChannel getChannel(); -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/InAppBrowserMenuItem.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/InAppBrowserMenuItem.java deleted file mode 100644 index 85bba6e325..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/InAppBrowserMenuItem.java +++ /dev/null @@ -1,146 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.Util; - -import java.util.Map; -import java.util.Objects; - -public class InAppBrowserMenuItem { - private int id; - - @NonNull - private String title; - - @Nullable - private Integer order; - - @Nullable - private Object icon; - - @Nullable - private String iconColor; - - private boolean showAsAction; - - public InAppBrowserMenuItem(int id, @NonNull String title, @Nullable Integer order, @Nullable Object icon, - @Nullable String iconColor, boolean showAsAction) { - this.id = id; - this.title = title; - this.order = order; - this.icon = icon; - this.iconColor = iconColor; - this.showAsAction = showAsAction; - } - - @Nullable - public static InAppBrowserMenuItem fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - int id = (int) map.get("id"); - String title = (String) map.get("title"); - Integer order = (Integer) map.get("order"); - Object icon = map.get("icon"); - if (icon instanceof Map) { - icon = AndroidResource.fromMap((Map) map.get("icon")); - } else if (!(icon instanceof byte[])) { - icon = null; - } - String iconColor = (String) map.get("iconColor"); - boolean showAsAction = Util.getOrDefault( map, "showAsAction", false); - return new InAppBrowserMenuItem(id, title, order, icon, iconColor, showAsAction); - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @NonNull - public String getTitle() { - return title; - } - - public void setTitle(@NonNull String title) { - this.title = title; - } - - @Nullable - public Integer getOrder() { - return order; - } - - public void setOrder(@Nullable Integer order) { - this.order = order; - } - - @Nullable - public Object getIcon() { - return icon; - } - - public void setIcon(@Nullable Object icon) { - this.icon = icon; - } - - @Nullable - public String getIconColor() { - return iconColor; - } - - public void setIconColor(@Nullable String iconColor) { - this.iconColor = iconColor; - } - - public boolean isShowAsAction() { - return showAsAction; - } - - public void setShowAsAction(boolean showAsAction) { - this.showAsAction = showAsAction; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - InAppBrowserMenuItem that = (InAppBrowserMenuItem) o; - - if (id != that.id) return false; - if (showAsAction != that.showAsAction) return false; - if (!title.equals(that.title)) return false; - if (!Objects.equals(order, that.order)) return false; - if (!Objects.equals(icon, that.icon)) return false; - return Objects.equals(iconColor, that.iconColor); - } - - @Override - public int hashCode() { - int result = id; - result = 31 * result + title.hashCode(); - result = 31 * result + (order != null ? order.hashCode() : 0); - result = 31 * result + (icon != null ? icon.hashCode() : 0); - result = 31 * result + (iconColor != null ? iconColor.hashCode() : 0); - result = 31 * result + (showAsAction ? 1 : 0); - return result; - } - - @Override - public String toString() { - return "InAppBrowserMenuItem{" + - "id=" + id + - ", title='" + title + '\'' + - ", order=" + order + - ", icon=" + icon + - ", iconColor='" + iconColor + '\'' + - ", showAsAction=" + showAsAction + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/InAppWebViewRect.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/InAppWebViewRect.java deleted file mode 100644 index b297899ff9..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/InAppWebViewRect.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.graphics.Rect; - -import androidx.annotation.Nullable; - -import java.util.HashMap; -import java.util.Map; - -public class InAppWebViewRect { - private double height; - private double width; - private double x; - private double y; - - public InAppWebViewRect(double height, double width, double x, double y) { - this.height = height; - this.width = width; - this.x = x; - this.y = y; - } - - @Nullable - public static InAppWebViewRect fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - double height = (double) map.get("height"); - double width = (double) map.get("width"); - double x = (double) map.get("x"); - double y = (double) map.get("y"); - return new InAppWebViewRect(height, width, x, y); - } - - public Map toMap() { - Map map = new HashMap<>(); - map.put("height", height); - map.put("width", width); - map.put("x", x); - map.put("y", y); - return map; - } - - public Rect toRect() { - return new Rect((int) x, (int) y, (int) (x + width), (int) (y + height)); - } - - public double getHeight() { - return height; - } - - public void setHeight(double height) { - this.height = height; - } - - public double getWidth() { - return width; - } - - public void setWidth(double width) { - this.width = width; - } - - public double getX() { - return x; - } - - public void setX(double x) { - this.x = x; - } - - public double getY() { - return y; - } - - public void setY(double y) { - this.y = y; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - InAppWebViewRect that = (InAppWebViewRect) o; - return Double.compare(height, that.height) == 0 && Double.compare(width, that.width) == 0 && Double.compare(x, that.x) == 0 && Double.compare(y, that.y) == 0; - } - - @Override - public int hashCode() { - int result = Double.hashCode(height); - result = 31 * result + Double.hashCode(width); - result = 31 * result + Double.hashCode(x); - result = 31 * result + Double.hashCode(y); - return result; - } - - @Override - public String toString() { - return "InAppWebViewRect{" + - "height=" + height + - ", width=" + width + - ", x=" + x + - ", y=" + y + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JavaScriptHandlerFunctionData.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JavaScriptHandlerFunctionData.java deleted file mode 100644 index 8cf6aa294d..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JavaScriptHandlerFunctionData.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.HashMap; -import java.util.Map; - -public class JavaScriptHandlerFunctionData { - @NonNull - private String origin; - @NonNull - private String requestUrl; - private boolean isMainFrame; - @NonNull - private String args; - - public JavaScriptHandlerFunctionData(@NonNull String origin, @NonNull String requestUrl, boolean isMainFrame, @NonNull String args) { - this.origin = origin; - this.requestUrl = requestUrl; - this.isMainFrame = isMainFrame; - this.args = args; - } - - @Nullable - public static JavaScriptHandlerFunctionData fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String origin = (String) map.get("origin"); - String requestUrl = (String) map.get("requestUrl"); - boolean isMainFrame = (boolean) map.get("isMainFrame"); - String args = (String) map.get("args"); - return new JavaScriptHandlerFunctionData(origin, requestUrl, isMainFrame, args); - } - - public Map toMap() { - Map map = new HashMap<>(); - map.put("origin", origin); - map.put("requestUrl", requestUrl); - map.put("isMainFrame", isMainFrame); - map.put("args", args); - return map; - } - - @NonNull - public String getRequestUrl() { - return requestUrl; - } - - public void setRequestUrl(@NonNull String requestUrl) { - this.requestUrl = requestUrl; - } - - @NonNull - public String getOrigin() { - return origin; - } - - public void setOrigin(@NonNull String origin) { - this.origin = origin; - } - - public boolean isMainFrame() { - return isMainFrame; - } - - public void setMainFrame(boolean mainFrame) { - isMainFrame = mainFrame; - } - - @NonNull - public String getArgs() { - return args; - } - - public void setArgs(@NonNull String args) { - this.args = args; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - JavaScriptHandlerFunctionData that = (JavaScriptHandlerFunctionData) o; - return isMainFrame == that.isMainFrame && origin.equals(that.origin) && requestUrl.equals(that.requestUrl) && args.equals(that.args); - } - - @Override - public int hashCode() { - int result = origin.hashCode(); - result = 31 * result + requestUrl.hashCode(); - result = 31 * result + Boolean.hashCode(isMainFrame); - result = 31 * result + args.hashCode(); - return result; - } - - @Override - public String toString() { - return "JavaScriptHandlerFunctionData{" + - "origin='" + origin + '\'' + - ", requestUrl='" + requestUrl + '\'' + - ", isMainFrame=" + isMainFrame + - ", args='" + args + '\'' + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JsAlertResponse.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JsAlertResponse.java deleted file mode 100644 index 6f3f0925af..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JsAlertResponse.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.Nullable; - -import java.util.Map; - -public class JsAlertResponse { - private String message; - private String confirmButtonTitle; - private boolean handledByClient; - @Nullable - private Integer action; - - public JsAlertResponse(String message, String confirmButtonTitle, boolean handledByClient, @Nullable Integer action) { - this.message = message; - this.confirmButtonTitle = confirmButtonTitle; - this.handledByClient = handledByClient; - this.action = action; - } - - @Nullable - public static JsAlertResponse fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String message = (String) map.get("message"); - String confirmButtonTitle = (String) map.get("confirmButtonTitle"); - boolean handledByClient = (boolean) map.get("handledByClient"); - Integer action = (Integer) map.get("action"); - return new JsAlertResponse(message, confirmButtonTitle, handledByClient, action); - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public String getConfirmButtonTitle() { - return confirmButtonTitle; - } - - public void setConfirmButtonTitle(String confirmButtonTitle) { - this.confirmButtonTitle = confirmButtonTitle; - } - - public boolean isHandledByClient() { - return handledByClient; - } - - public void setHandledByClient(boolean handledByClient) { - this.handledByClient = handledByClient; - } - - @Nullable - public Integer getAction() { - return action; - } - - public void setAction(@Nullable Integer action) { - this.action = action; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - JsAlertResponse that = (JsAlertResponse) o; - - if (handledByClient != that.handledByClient) return false; - if (message != null ? !message.equals(that.message) : that.message != null) return false; - if (confirmButtonTitle != null ? !confirmButtonTitle.equals(that.confirmButtonTitle) : that.confirmButtonTitle != null) - return false; - return action != null ? action.equals(that.action) : that.action == null; - } - - @Override - public int hashCode() { - int result = message != null ? message.hashCode() : 0; - result = 31 * result + (confirmButtonTitle != null ? confirmButtonTitle.hashCode() : 0); - result = 31 * result + (handledByClient ? 1 : 0); - result = 31 * result + (action != null ? action.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "JsAlertResponse{" + - "message='" + message + '\'' + - ", confirmButtonTitle='" + confirmButtonTitle + '\'' + - ", handledByClient=" + handledByClient + - ", action=" + action + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JsBeforeUnloadResponse.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JsBeforeUnloadResponse.java deleted file mode 100644 index ead00e00ea..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JsBeforeUnloadResponse.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.Nullable; - -import java.util.Map; - -public class JsBeforeUnloadResponse { - private String message; - private String confirmButtonTitle; - private String cancelButtonTitle; - private boolean handledByClient; - @Nullable - private Integer action; - - public JsBeforeUnloadResponse(String message, String confirmButtonTitle, String cancelButtonTitle, boolean handledByClient, @Nullable Integer action) { - this.message = message; - this.confirmButtonTitle = confirmButtonTitle; - this.cancelButtonTitle = cancelButtonTitle; - this.handledByClient = handledByClient; - this.action = action; - } - - @Nullable - public static JsBeforeUnloadResponse fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String message = (String) map.get("message"); - String confirmButtonTitle = (String) map.get("confirmButtonTitle"); - String cancelButtonTitle = (String) map.get("cancelButtonTitle"); - boolean handledByClient = (boolean) map.get("handledByClient"); - Integer action = (Integer) map.get("action"); - return new JsBeforeUnloadResponse(message, confirmButtonTitle, cancelButtonTitle, handledByClient, action); - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public String getConfirmButtonTitle() { - return confirmButtonTitle; - } - - public void setConfirmButtonTitle(String confirmButtonTitle) { - this.confirmButtonTitle = confirmButtonTitle; - } - - public String getCancelButtonTitle() { - return cancelButtonTitle; - } - - public void setCancelButtonTitle(String cancelButtonTitle) { - this.cancelButtonTitle = cancelButtonTitle; - } - - public boolean isHandledByClient() { - return handledByClient; - } - - public void setHandledByClient(boolean handledByClient) { - this.handledByClient = handledByClient; - } - - @Nullable - public Integer getAction() { - return action; - } - - public void setAction(@Nullable Integer action) { - this.action = action; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - JsBeforeUnloadResponse that = (JsBeforeUnloadResponse) o; - - if (handledByClient != that.handledByClient) return false; - if (message != null ? !message.equals(that.message) : that.message != null) return false; - if (confirmButtonTitle != null ? !confirmButtonTitle.equals(that.confirmButtonTitle) : that.confirmButtonTitle != null) - return false; - if (cancelButtonTitle != null ? !cancelButtonTitle.equals(that.cancelButtonTitle) : that.cancelButtonTitle != null) - return false; - return action != null ? action.equals(that.action) : that.action == null; - } - - @Override - public int hashCode() { - int result = message != null ? message.hashCode() : 0; - result = 31 * result + (confirmButtonTitle != null ? confirmButtonTitle.hashCode() : 0); - result = 31 * result + (cancelButtonTitle != null ? cancelButtonTitle.hashCode() : 0); - result = 31 * result + (handledByClient ? 1 : 0); - result = 31 * result + (action != null ? action.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "JsConfirmResponse{" + - "message='" + message + '\'' + - ", confirmButtonTitle='" + confirmButtonTitle + '\'' + - ", cancelButtonTitle='" + cancelButtonTitle + '\'' + - ", handledByClient=" + handledByClient + - ", action=" + action + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JsConfirmResponse.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JsConfirmResponse.java deleted file mode 100644 index af65e41aef..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JsConfirmResponse.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.Nullable; - -import java.util.Map; - -public class JsConfirmResponse { - private String message; - private String confirmButtonTitle; - private String cancelButtonTitle; - private boolean handledByClient; - @Nullable - private Integer action; - - public JsConfirmResponse(String message, String confirmButtonTitle, String cancelButtonTitle, boolean handledByClient, @Nullable Integer action) { - this.message = message; - this.confirmButtonTitle = confirmButtonTitle; - this.cancelButtonTitle = cancelButtonTitle; - this.handledByClient = handledByClient; - this.action = action; - } - - @Nullable - public static JsConfirmResponse fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String message = (String) map.get("message"); - String confirmButtonTitle = (String) map.get("confirmButtonTitle"); - String cancelButtonTitle = (String) map.get("cancelButtonTitle"); - boolean handledByClient = (boolean) map.get("handledByClient"); - Integer action = (Integer) map.get("action"); - return new JsConfirmResponse(message, confirmButtonTitle, cancelButtonTitle, handledByClient, action); - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public String getConfirmButtonTitle() { - return confirmButtonTitle; - } - - public void setConfirmButtonTitle(String confirmButtonTitle) { - this.confirmButtonTitle = confirmButtonTitle; - } - - public String getCancelButtonTitle() { - return cancelButtonTitle; - } - - public void setCancelButtonTitle(String cancelButtonTitle) { - this.cancelButtonTitle = cancelButtonTitle; - } - - public boolean isHandledByClient() { - return handledByClient; - } - - public void setHandledByClient(boolean handledByClient) { - this.handledByClient = handledByClient; - } - - @Nullable - public Integer getAction() { - return action; - } - - public void setAction(@Nullable Integer action) { - this.action = action; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - JsConfirmResponse that = (JsConfirmResponse) o; - - if (handledByClient != that.handledByClient) return false; - if (message != null ? !message.equals(that.message) : that.message != null) return false; - if (confirmButtonTitle != null ? !confirmButtonTitle.equals(that.confirmButtonTitle) : that.confirmButtonTitle != null) - return false; - if (cancelButtonTitle != null ? !cancelButtonTitle.equals(that.cancelButtonTitle) : that.cancelButtonTitle != null) - return false; - return action != null ? action.equals(that.action) : that.action == null; - } - - @Override - public int hashCode() { - int result = message != null ? message.hashCode() : 0; - result = 31 * result + (confirmButtonTitle != null ? confirmButtonTitle.hashCode() : 0); - result = 31 * result + (cancelButtonTitle != null ? cancelButtonTitle.hashCode() : 0); - result = 31 * result + (handledByClient ? 1 : 0); - result = 31 * result + (action != null ? action.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "JsConfirmResponse{" + - "message='" + message + '\'' + - ", confirmButtonTitle='" + confirmButtonTitle + '\'' + - ", cancelButtonTitle='" + cancelButtonTitle + '\'' + - ", handledByClient=" + handledByClient + - ", action=" + action + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JsPromptResponse.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JsPromptResponse.java deleted file mode 100644 index fb63aef734..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JsPromptResponse.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.Nullable; - -import java.util.Map; - -public class JsPromptResponse { - private String message; - private String defaultValue; - private String confirmButtonTitle; - private String cancelButtonTitle; - private boolean handledByClient; - @Nullable - private String value; - @Nullable - private Integer action; - - public JsPromptResponse(String message, String defaultValue, String confirmButtonTitle, - String cancelButtonTitle, boolean handledByClient, @Nullable String value, @Nullable Integer action) { - this.message = message; - this.defaultValue = defaultValue; - this.confirmButtonTitle = confirmButtonTitle; - this.cancelButtonTitle = cancelButtonTitle; - this.handledByClient = handledByClient; - this.value = value; - this.action = action; - } - - @Nullable - public static JsPromptResponse fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String message = (String) map.get("message"); - String defaultValue = (String) map.get("defaultValue"); - String confirmButtonTitle = (String) map.get("confirmButtonTitle"); - String cancelButtonTitle = (String) map.get("cancelButtonTitle"); - boolean handledByClient = (boolean) map.get("handledByClient"); - String value = (String) map.get("value"); - Integer action = (Integer) map.get("action"); - return new JsPromptResponse(message, defaultValue, confirmButtonTitle, cancelButtonTitle, handledByClient, value, action); - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public String getDefaultValue() { - return defaultValue; - } - - public void setDefaultValue(String defaultValue) { - this.defaultValue = defaultValue; - } - - public String getConfirmButtonTitle() { - return confirmButtonTitle; - } - - public void setConfirmButtonTitle(String confirmButtonTitle) { - this.confirmButtonTitle = confirmButtonTitle; - } - - public String getCancelButtonTitle() { - return cancelButtonTitle; - } - - public void setCancelButtonTitle(String cancelButtonTitle) { - this.cancelButtonTitle = cancelButtonTitle; - } - - public boolean isHandledByClient() { - return handledByClient; - } - - public void setHandledByClient(boolean handledByClient) { - this.handledByClient = handledByClient; - } - - @Nullable - public String getValue() { - return value; - } - - public void setValue(@Nullable String value) { - this.value = value; - } - - @Nullable - public Integer getAction() { - return action; - } - - public void setAction(@Nullable Integer action) { - this.action = action; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - JsPromptResponse that = (JsPromptResponse) o; - - if (handledByClient != that.handledByClient) return false; - if (message != null ? !message.equals(that.message) : that.message != null) return false; - if (defaultValue != null ? !defaultValue.equals(that.defaultValue) : that.defaultValue != null) - return false; - if (confirmButtonTitle != null ? !confirmButtonTitle.equals(that.confirmButtonTitle) : that.confirmButtonTitle != null) - return false; - if (cancelButtonTitle != null ? !cancelButtonTitle.equals(that.cancelButtonTitle) : that.cancelButtonTitle != null) - return false; - if (value != null ? !value.equals(that.value) : that.value != null) return false; - return action != null ? action.equals(that.action) : that.action == null; - } - - @Override - public int hashCode() { - int result = message != null ? message.hashCode() : 0; - result = 31 * result + (defaultValue != null ? defaultValue.hashCode() : 0); - result = 31 * result + (confirmButtonTitle != null ? confirmButtonTitle.hashCode() : 0); - result = 31 * result + (cancelButtonTitle != null ? cancelButtonTitle.hashCode() : 0); - result = 31 * result + (handledByClient ? 1 : 0); - result = 31 * result + (value != null ? value.hashCode() : 0); - result = 31 * result + (action != null ? action.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "JsPromptResponse{" + - "message='" + message + '\'' + - ", defaultValue='" + defaultValue + '\'' + - ", confirmButtonTitle='" + confirmButtonTitle + '\'' + - ", cancelButtonTitle='" + cancelButtonTitle + '\'' + - ", handledByClient=" + handledByClient + - ", value='" + value + '\'' + - ", action=" + action + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/MarginsExt.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/MarginsExt.java deleted file mode 100644 index 161254d57f..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/MarginsExt.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.os.Build; -import android.print.PrintAttributes; - -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; - -import java.util.HashMap; -import java.util.Map; - -@RequiresApi(api = Build.VERSION_CODES.KITKAT) -public class MarginsExt { - private double top; - private double right; - private double bottom; - private double left; - - public MarginsExt() {} - - public MarginsExt(double top, double right, double bottom, double left) { - this.top = top; - this.right = right; - this.bottom = bottom; - this.left = left; - } - - @Nullable - public static MarginsExt fromMargins(@Nullable PrintAttributes.Margins margins) { - if (margins == null) { - return null; - } - MarginsExt marginsExt = new MarginsExt(); - marginsExt.top = milsToPixels(margins.getTopMils()); - marginsExt.right = milsToPixels(margins.getRightMils()); - marginsExt.bottom = milsToPixels(margins.getBottomMils()); - marginsExt.left = milsToPixels(margins.getLeftMils()); - return marginsExt; - } - - @Nullable - public static MarginsExt fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - return new MarginsExt( - (double) map.get("top"), - (double) map.get("right"), - (double) map.get("bottom"), - (double) map.get("left")); - } - - public PrintAttributes.Margins toMargins() { - return new PrintAttributes.Margins( - pixelsToMils(left), - pixelsToMils(top), - pixelsToMils(right), - pixelsToMils(bottom) - ); - } - - // from mils to pixels - private static double milsToPixels(int mils) { - return mils * 0.09600001209449; - } - - // from pixels to mils - private static int pixelsToMils(double pixels) { - return (int) Math.round(pixels * 10.416665354331); - } - - public Map toMap() { - Map obj = new HashMap<>(); - obj.put("top", top); - obj.put("right", right); - obj.put("bottom", bottom); - obj.put("left", left); - return obj; - } - - public double getTop() { - return top; - } - - public void setTop(double top) { - this.top = top; - } - - public double getRight() { - return right; - } - - public void setRight(double right) { - this.right = right; - } - - public double getBottom() { - return bottom; - } - - public void setBottom(double bottom) { - this.bottom = bottom; - } - - public double getLeft() { - return left; - } - - public void setLeft(double left) { - this.left = left; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - MarginsExt that = (MarginsExt) o; - - if (Double.compare(that.top, top) != 0) return false; - if (Double.compare(that.right, right) != 0) return false; - if (Double.compare(that.bottom, bottom) != 0) return false; - return Double.compare(that.left, left) == 0; - } - - @Override - public int hashCode() { - int result; - long temp; - temp = Double.doubleToLongBits(top); - result = (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(right); - result = 31 * result + (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(bottom); - result = 31 * result + (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(left); - result = 31 * result + (int) (temp ^ (temp >>> 32)); - return result; - } - - @Override - public String toString() { - return "MarginsExt{" + - "top=" + top + - ", right=" + right + - ", bottom=" + bottom + - ", left=" + left + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/MediaSizeExt.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/MediaSizeExt.java deleted file mode 100644 index cd2618f28f..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/MediaSizeExt.java +++ /dev/null @@ -1,134 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.os.Build; -import android.print.PrintAttributes; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; - -import java.util.HashMap; -import java.util.Map; - -@RequiresApi(api = Build.VERSION_CODES.KITKAT) -public class MediaSizeExt { - @NonNull - private String id; - @Nullable - private String label; - private int widthMils; - private int heightMils; - - public MediaSizeExt(@NonNull String id, @Nullable String label, int widthMils, int heightMils) { - this.id = id; - this.label = label; - this.widthMils = widthMils; - this.heightMils = heightMils; - } - - @Nullable - public static MediaSizeExt fromMediaSize(@Nullable PrintAttributes.MediaSize mediaSize) { - if (mediaSize == null) { - return null; - } - return new MediaSizeExt( - mediaSize.getId(), - null, - mediaSize.getHeightMils(), - mediaSize.getWidthMils() - ); - } - - @Nullable - public static MediaSizeExt fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String id = (String) map.get("id"); - String label = (String) map.get("label"); - int widthMils = (int) map.get("widthMils"); - int heightMils = (int) map.get("heightMils"); - return new MediaSizeExt(id, label, widthMils, heightMils); - } - - public PrintAttributes.MediaSize toMediaSize() { - return new PrintAttributes.MediaSize( - id, "Custom", widthMils, heightMils - ); - } - - public Map toMap() { - Map obj = new HashMap<>(); - obj.put("id", id); - obj.put("label", label); - obj.put("heightMils", heightMils); - obj.put("widthMils", widthMils); - return obj; - } - - @NonNull - public String getId() { - return id; - } - - public void setId(@NonNull String id) { - this.id = id; - } - - @Nullable - public String getLabel() { - return label; - } - - public void setLabel(@Nullable String label) { - this.label = label; - } - - public int getWidthMils() { - return widthMils; - } - - public void setWidthMils(int widthMils) { - this.widthMils = widthMils; - } - - public int getHeightMils() { - return heightMils; - } - - public void setHeightMils(int heightMils) { - this.heightMils = heightMils; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - MediaSizeExt that = (MediaSizeExt) o; - - if (widthMils != that.widthMils) return false; - if (heightMils != that.heightMils) return false; - if (!id.equals(that.id)) return false; - return label != null ? label.equals(that.label) : that.label == null; - } - - @Override - public int hashCode() { - int result = id.hashCode(); - result = 31 * result + (label != null ? label.hashCode() : 0); - result = 31 * result + widthMils; - result = 31 * result + heightMils; - return result; - } - - @Override - public String toString() { - return "MediaSizeExt{" + - "id='" + id + '\'' + - ", label='" + label + '\'' + - ", widthMils=" + widthMils + - ", heightMils=" + heightMils + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/NavigationAction.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/NavigationAction.java deleted file mode 100644 index faf5e59669..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/NavigationAction.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import java.util.HashMap; -import java.util.Map; - -public class NavigationAction { - URLRequest request; - boolean isForMainFrame; - boolean hasGesture; - boolean isRedirect; - - public NavigationAction(URLRequest request, boolean isForMainFrame, boolean hasGesture, boolean isRedirect) { - this.request = request; - this.isForMainFrame = isForMainFrame; - this.hasGesture = hasGesture; - this.isRedirect = isRedirect; - } - - public Map toMap() { - Map navigationActionMap = new HashMap<>(); - navigationActionMap.put("request", request.toMap()); - navigationActionMap.put("isForMainFrame", isForMainFrame); - navigationActionMap.put("hasGesture", hasGesture); - navigationActionMap.put("isRedirect", isRedirect); - navigationActionMap.put("navigationType", null); - navigationActionMap.put("sourceFrame", null); - navigationActionMap.put("targetFrame", null); - navigationActionMap.put("shouldPerformDownload", null); - return navigationActionMap; - } - - public URLRequest getRequest() { - return request; - } - - public void setRequest(URLRequest request) { - this.request = request; - } - - public boolean isForMainFrame() { - return isForMainFrame; - } - - public void setForMainFrame(boolean forMainFrame) { - isForMainFrame = forMainFrame; - } - - public boolean isHasGesture() { - return hasGesture; - } - - public void setHasGesture(boolean hasGesture) { - this.hasGesture = hasGesture; - } - - public boolean isRedirect() { - return isRedirect; - } - - public void setRedirect(boolean redirect) { - isRedirect = redirect; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - NavigationAction that = (NavigationAction) o; - - if (isForMainFrame != that.isForMainFrame) return false; - if (hasGesture != that.hasGesture) return false; - if (isRedirect != that.isRedirect) return false; - return request.equals(that.request); - } - - @Override - public int hashCode() { - int result = request.hashCode(); - result = 31 * result + (isForMainFrame ? 1 : 0); - result = 31 * result + (hasGesture ? 1 : 0); - result = 31 * result + (isRedirect ? 1 : 0); - return result; - } - - @Override - public String toString() { - return "NavigationAction{" + - "request=" + request + - ", isForMainFrame=" + isForMainFrame + - ", hasGesture=" + hasGesture + - ", isRedirect=" + isRedirect + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/NavigationActionPolicy.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/NavigationActionPolicy.java deleted file mode 100644 index c6e0fbbae9..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/NavigationActionPolicy.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -public enum NavigationActionPolicy { - CANCEL(0), - ALLOW(1); - - private final int value; - - private NavigationActionPolicy(int value) { - this.value = value; - } - - public boolean equalsValue(int otherValue) { - return value == otherValue; - } - - public static NavigationActionPolicy fromValue(int value) { - for(NavigationActionPolicy type : NavigationActionPolicy.values()) { - if(value == type.value) - return type; - } - throw new IllegalArgumentException("No enum constant: " + value); - } - - public int rawValue() { - return this.value; - } - - @Override - public String toString() { - return String.valueOf(this.value); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PermissionResponse.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PermissionResponse.java deleted file mode 100644 index f3848dd734..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PermissionResponse.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.List; -import java.util.Map; - -public class PermissionResponse { - @NonNull - private List resources; - @Nullable - private Integer action; - - public PermissionResponse(@NonNull List resources, @Nullable Integer action) { - this.resources = resources; - this.action = action; - } - - @Nullable - public static PermissionResponse fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - List resources = (List) map.get("resources"); - Integer action = (Integer) map.get("action"); - return new PermissionResponse(resources, action); - } - - @NonNull - public List getResources() { - return resources; - } - - public void setResources(@NonNull List resources) { - this.resources = resources; - } - - @Nullable - public Integer getAction() { - return action; - } - - public void setAction(@Nullable Integer action) { - this.action = action; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - PermissionResponse that = (PermissionResponse) o; - - if (!resources.equals(that.resources)) return false; - return action != null ? action.equals(that.action) : that.action == null; - } - - @Override - public int hashCode() { - int result = resources.hashCode(); - result = 31 * result + (action != null ? action.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "PermissionResponse{" + - "resources=" + resources + - ", action=" + action + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PluginScript.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PluginScript.java deleted file mode 100644 index a5a95e4ea5..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PluginScript.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Set; - -public class PluginScript extends UserScript { - private boolean requiredInAllContentWorlds; - - public PluginScript(@Nullable String groupName, @NonNull String source, @NonNull UserScriptInjectionTime injectionTime, - @Nullable ContentWorld contentWorld, boolean requiredInAllContentWorlds, @Nullable Set allowedOriginRules, boolean forMainFrameOnly) { - super(groupName, source, injectionTime, contentWorld, allowedOriginRules, forMainFrameOnly); - this.requiredInAllContentWorlds = requiredInAllContentWorlds; - } - - public boolean isRequiredInAllContentWorlds() { - return requiredInAllContentWorlds; - } - - public void setRequiredInAllContentWorlds(boolean requiredInAllContentWorlds) { - this.requiredInAllContentWorlds = requiredInAllContentWorlds; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - - PluginScript that = (PluginScript) o; - - return requiredInAllContentWorlds == that.requiredInAllContentWorlds; - } - - @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + (requiredInAllContentWorlds ? 1 : 0); - return result; - } - - @Override - public String toString() { - return "PluginScript{" + - "requiredInContentWorld=" + requiredInAllContentWorlds + - "} " + super.toString(); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PreferredContentModeOptionType.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PreferredContentModeOptionType.java deleted file mode 100755 index bb5bfa0ab4..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PreferredContentModeOptionType.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -public enum PreferredContentModeOptionType { - RECOMMENDED (0), - MOBILE (1), - DESKTOP (2); - - private final int value; - - private PreferredContentModeOptionType(int value) { - this.value = value; - } - - public boolean equalsValue(int otherValue) { - return value == otherValue; - } - - public static PreferredContentModeOptionType fromValue(int value) { - for( PreferredContentModeOptionType type : PreferredContentModeOptionType.values()) { - if(value == type.toValue()) - return type; - } - throw new IllegalArgumentException("No enum constant: " + value); - } - - public int toValue() { - return this.value; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PrintAttributesExt.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PrintAttributesExt.java deleted file mode 100644 index 77b65528f3..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PrintAttributesExt.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.os.Build; -import android.print.PrintAttributes; - -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; - -import java.util.HashMap; -import java.util.Map; - -@RequiresApi(api = Build.VERSION_CODES.KITKAT) -public class PrintAttributesExt { - private int colorMode; - @Nullable - private Integer duplex; - @Nullable - private Integer orientation; - @Nullable - private MediaSizeExt mediaSize; - @Nullable - private ResolutionExt resolution; - @Nullable - private MarginsExt margins; - - @Nullable - public static PrintAttributesExt fromPrintAttributes(@Nullable PrintAttributes attributes) { - if (attributes == null) { - return null; - } - PrintAttributesExt attributesExt = new PrintAttributesExt(); - attributesExt.colorMode = attributes.getColorMode(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - attributesExt.duplex = attributes.getDuplexMode(); - } - PrintAttributes.MediaSize mediaSize = attributes.getMediaSize(); - if (mediaSize != null) { - attributesExt.mediaSize = MediaSizeExt.fromMediaSize(mediaSize); - attributesExt.orientation = mediaSize.isPortrait() ? 0 : 1; - } - attributesExt.resolution = ResolutionExt.fromResolution(attributes.getResolution()); - attributesExt.margins = MarginsExt.fromMargins(attributes.getMinMargins()); - return attributesExt; - } - - public Map toMap() { - Map obj = new HashMap<>(); - obj.put("colorMode", colorMode); - obj.put("duplex", duplex); - obj.put("orientation", orientation); - obj.put("mediaSize", mediaSize != null ? mediaSize.toMap() : null); - obj.put("resolution", resolution != null ? resolution.toMap() : null); - obj.put("margins", margins != null ? margins.toMap() : null); - return obj; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PrintJobInfoExt.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PrintJobInfoExt.java deleted file mode 100644 index e58d851a1e..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PrintJobInfoExt.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.os.Build; -import android.print.PrintJobInfo; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; - -import java.util.HashMap; -import java.util.Map; - -@RequiresApi(api = Build.VERSION_CODES.KITKAT) -public class PrintJobInfoExt { - private int state; - private int copies; - @Nullable - private Integer numberOfPages; - private long creationTime; - @NonNull - private String label; - @Nullable - private String printerId; - @Nullable - private PrintAttributesExt attributes; - - @Nullable - public static PrintJobInfoExt fromPrintJobInfo(@Nullable PrintJobInfo info) { - if (info == null) { - return null; - } - PrintJobInfoExt printJobInfoExt = new PrintJobInfoExt(); - printJobInfoExt.state = info.getState(); - printJobInfoExt.copies = info.getCopies(); - printJobInfoExt.numberOfPages = info.getPages() != null ? info.getPages().length : null; - printJobInfoExt.creationTime = info.getCreationTime(); - printJobInfoExt.label = info.getLabel(); - printJobInfoExt.printerId = info.getPrinterId() != null ? info.getPrinterId().getLocalId() : null; - printJobInfoExt.attributes = PrintAttributesExt.fromPrintAttributes(info.getAttributes()); - return printJobInfoExt; - } - - public Map toMap() { - Map obj = new HashMap<>(); - obj.put("state", state); - obj.put("copies", copies); - obj.put("numberOfPages", numberOfPages); - obj.put("creationTime", creationTime); - obj.put("label", label); - Map printer = new HashMap<>(); - printer.put("id", printerId); - obj.put("printer", printer); - obj.put("attributes", attributes != null ? attributes.toMap() : null); - return obj; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ProxyRuleExt.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ProxyRuleExt.java deleted file mode 100644 index 52081a3874..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ProxyRuleExt.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.ProxyConfig; - -import java.util.HashMap; -import java.util.Map; - -public class ProxyRuleExt { - @Nullable - @ProxyConfig.ProxyScheme - private String schemeFilter; - @NonNull - private String url; - - public ProxyRuleExt(@Nullable @ProxyConfig.ProxyScheme String schemeFilter, @NonNull String url) { - this.schemeFilter = schemeFilter; - this.url = url; - } - - @Nullable - public static ProxyRuleExt fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String url = (String) map.get("url"); - String schemeFilter = (String) map.get("schemeFilter"); - return new ProxyRuleExt(schemeFilter, url); - } - - public Map toMap() { - Map proxyRuleMap = new HashMap<>(); - proxyRuleMap.put("url", url); - proxyRuleMap.put("schemeFilter", schemeFilter); - return proxyRuleMap; - } - - @Nullable - public String getSchemeFilter() { - return schemeFilter; - } - - public void setSchemeFilter(@Nullable String schemeFilter) { - this.schemeFilter = schemeFilter; - } - - @NonNull - public String getUrl() { - return url; - } - - public void setUrl(@NonNull String url) { - this.url = url; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ProxyRuleExt that = (ProxyRuleExt) o; - - if (schemeFilter != null ? !schemeFilter.equals(that.schemeFilter) : that.schemeFilter != null) - return false; - return url.equals(that.url); - } - - @Override - public int hashCode() { - int result = schemeFilter != null ? schemeFilter.hashCode() : 0; - result = 31 * result + url.hashCode(); - return result; - } - - @Override - public String toString() { - return "ProxyRuleExt{" + - "schemeFilter='" + schemeFilter + '\'' + - ", url='" + url + '\'' + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ResolutionExt.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ResolutionExt.java deleted file mode 100644 index daca1117e5..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ResolutionExt.java +++ /dev/null @@ -1,134 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.os.Build; -import android.print.PrintAttributes; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; - -import java.util.HashMap; -import java.util.Map; - -@RequiresApi(api = Build.VERSION_CODES.KITKAT) -public class ResolutionExt { - @NonNull - private String id; - @NonNull - private String label; - private int verticalDpi; - private int horizontalDpi; - - public ResolutionExt(@NonNull String id, @NonNull String label, int verticalDpi, int horizontalDpi) { - this.id = id; - this.label = label; - this.verticalDpi = verticalDpi; - this.horizontalDpi = horizontalDpi; - } - - @Nullable - public static ResolutionExt fromResolution(@Nullable PrintAttributes.Resolution resolution) { - if (resolution == null) { - return null; - } - return new ResolutionExt( - resolution.getId(), - resolution.getLabel(), - resolution.getVerticalDpi(), - resolution.getHorizontalDpi() - ); - } - - @Nullable - public static ResolutionExt fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String id = (String) map.get("id"); - String label = (String) map.get("label"); - int verticalDpi = (int) map.get("verticalDpi"); - int horizontalDpi = (int) map.get("horizontalDpi"); - return new ResolutionExt(id, label, verticalDpi, horizontalDpi); - } - - public PrintAttributes.Resolution toResolution() { - return new PrintAttributes.Resolution( - id, label, horizontalDpi, verticalDpi - ); - } - - public Map toMap() { - Map obj = new HashMap<>(); - obj.put("id", id); - obj.put("label", label); - obj.put("verticalDpi", verticalDpi); - obj.put("horizontalDpi", horizontalDpi); - return obj; - } - - @NonNull - public String getId() { - return id; - } - - public void setId(@NonNull String id) { - this.id = id; - } - - @NonNull - public String getLabel() { - return label; - } - - public void setLabel(@NonNull String label) { - this.label = label; - } - - public int getVerticalDpi() { - return verticalDpi; - } - - public void setVerticalDpi(int verticalDpi) { - this.verticalDpi = verticalDpi; - } - - public int getHorizontalDpi() { - return horizontalDpi; - } - - public void setHorizontalDpi(int horizontalDpi) { - this.horizontalDpi = horizontalDpi; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ResolutionExt that = (ResolutionExt) o; - - if (verticalDpi != that.verticalDpi) return false; - if (horizontalDpi != that.horizontalDpi) return false; - if (!id.equals(that.id)) return false; - return label.equals(that.label); - } - - @Override - public int hashCode() { - int result = id.hashCode(); - result = 31 * result + label.hashCode(); - result = 31 * result + verticalDpi; - result = 31 * result + horizontalDpi; - return result; - } - - @Override - public String toString() { - return "ResolutionExt{" + - "id='" + id + '\'' + - ", label='" + label + '\'' + - ", verticalDpi=" + verticalDpi + - ", horizontalDpi=" + horizontalDpi + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/SafeBrowsingResponse.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/SafeBrowsingResponse.java deleted file mode 100644 index 765fe25860..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/SafeBrowsingResponse.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.Nullable; - -import java.util.Map; - -public class SafeBrowsingResponse { - private boolean report; - @Nullable - private Integer action; - - public SafeBrowsingResponse(boolean report, @Nullable Integer action) { - this.report = report; - this.action = action; - } - - @Nullable - public static SafeBrowsingResponse fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - boolean report = (boolean) map.get("report"); - Integer action = (Integer) map.get("action"); - return new SafeBrowsingResponse(report, action); - } - - public boolean isReport() { - return report; - } - - public void setReport(boolean report) { - this.report = report; - } - - @Nullable - public Integer getAction() { - return action; - } - - public void setAction(@Nullable Integer action) { - this.action = action; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - SafeBrowsingResponse that = (SafeBrowsingResponse) o; - - if (report != that.report) return false; - return action != null ? action.equals(that.action) : that.action == null; - } - - @Override - public int hashCode() { - int result = (report ? 1 : 0); - result = 31 * result + (action != null ? action.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "SafeBrowsingResponse{" + - "report=" + report + - ", action=" + action + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ServerTrustAuthResponse.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ServerTrustAuthResponse.java deleted file mode 100644 index eebf7bd9c2..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ServerTrustAuthResponse.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.Nullable; - -import java.util.Map; - -public class ServerTrustAuthResponse { - @Nullable - private Integer action; - - public ServerTrustAuthResponse(@Nullable Integer action) { - this.action = action; - } - - @Nullable - public static ServerTrustAuthResponse fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - Integer action = (Integer) map.get("action"); - return new ServerTrustAuthResponse(action); - } - - @Nullable - public Integer getAction() { - return action; - } - - public void setAction(@Nullable Integer action) { - this.action = action; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ServerTrustAuthResponse that = (ServerTrustAuthResponse) o; - - return action != null ? action.equals(that.action) : that.action == null; - } - - @Override - public int hashCode() { - return action != null ? action.hashCode() : 0; - } - - @Override - public String toString() { - return "ServerTrustAuthResponse{" + - "action=" + action + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ServerTrustChallenge.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ServerTrustChallenge.java deleted file mode 100644 index 17616453bc..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ServerTrustChallenge.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -public class ServerTrustChallenge extends URLAuthenticationChallenge { - public ServerTrustChallenge(URLProtectionSpace protectionSpace) { - super(protectionSpace); - } - - @Override - public String toString() { - return "ServerTrustChallenge{} " + super.toString(); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ShowFileChooserRequest.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ShowFileChooserRequest.java deleted file mode 100644 index eb26459b8a..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ShowFileChooserRequest.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.annotation.TargetApi; -import android.os.Build; -import android.webkit.WebChromeClient; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -public class ShowFileChooserRequest { - private int mode; - @NonNull - private List acceptTypes; - private boolean isCaptureEnabled; - @Nullable - private String title; - @Nullable - private String filenameHint; - - public ShowFileChooserRequest(int mode, @NonNull List acceptTypes, boolean isCaptureEnabled, @Nullable String title, @Nullable String filenameHint) { - this.mode = mode; - this.acceptTypes = acceptTypes; - this.isCaptureEnabled = isCaptureEnabled; - this.title = title; - this.filenameHint = filenameHint; - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public static ShowFileChooserRequest fromFileChooserParams(WebChromeClient.FileChooserParams fileChooserParams) { - int mode = fileChooserParams.getMode(); - List acceptTypes = Arrays.asList(fileChooserParams.getAcceptTypes()); - boolean isCaptureEnabled = fileChooserParams.isCaptureEnabled(); - String title = fileChooserParams.getTitle() != null ? fileChooserParams.getTitle().toString() : null; - String filenameHint = fileChooserParams.getFilenameHint(); - return new ShowFileChooserRequest(mode, acceptTypes, isCaptureEnabled, title, filenameHint); - } - - @Nullable - public static ShowFileChooserRequest fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - int mode = (int) map.get("mode"); - List acceptTypes = (List) map.get("acceptTypes"); - boolean isCaptureEnabled = (boolean) map.get("isCaptureEnabled"); - String title = (String) map.get("title"); - String filenameHint = (String) map.get("filenameHint"); - return new ShowFileChooserRequest(mode, acceptTypes, isCaptureEnabled, title, filenameHint); - } - - public Map toMap() { - Map showFileChooserRequestMap = new HashMap<>(); - showFileChooserRequestMap.put("mode", mode); - showFileChooserRequestMap.put("acceptTypes", acceptTypes); - showFileChooserRequestMap.put("isCaptureEnabled", isCaptureEnabled); - showFileChooserRequestMap.put("title", title); - showFileChooserRequestMap.put("filenameHint", filenameHint); - return showFileChooserRequestMap; - } - - - public int getMode() { - return mode; - } - - public void setMode(int mode) { - this.mode = mode; - } - - public @NonNull List getAcceptTypes() { - return acceptTypes; - } - - public void setAcceptTypes(@NonNull List acceptTypes) { - this.acceptTypes = acceptTypes; - } - - public boolean isCaptureEnabled() { - return isCaptureEnabled; - } - - public void setCaptureEnabled(boolean captureEnabled) { - isCaptureEnabled = captureEnabled; - } - - @Nullable - public String getTitle() { - return title; - } - - public void setTitle(@Nullable String title) { - this.title = title; - } - - @Nullable - public String getFilenameHint() { - return filenameHint; - } - - public void setFilenameHint(@Nullable String filenameHint) { - this.filenameHint = filenameHint; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ShowFileChooserRequest that = (ShowFileChooserRequest) o; - return mode == that.mode && isCaptureEnabled == that.isCaptureEnabled && acceptTypes.equals(that.acceptTypes) && Objects.equals(title, that.title) && Objects.equals(filenameHint, that.filenameHint); - } - - @Override - public int hashCode() { - int result = mode; - result = 31 * result + acceptTypes.hashCode(); - result = 31 * result + Boolean.hashCode(isCaptureEnabled); - result = 31 * result + Objects.hashCode(title); - result = 31 * result + Objects.hashCode(filenameHint); - return result; - } - - @NonNull - @Override - public String toString() { - return "ShowFileChooserRequest{" + - "mode=" + mode + - ", acceptTypes=" + acceptTypes + - ", isCaptureEnabled=" + isCaptureEnabled + - ", title='" + title + '\'' + - ", filenameHint='" + filenameHint + '\'' + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ShowFileChooserResponse.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ShowFileChooserResponse.java deleted file mode 100644 index d7cc839ce8..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/ShowFileChooserResponse.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.List; -import java.util.Map; -import java.util.Objects; - -public class ShowFileChooserResponse { - private boolean handledByClient; - @Nullable - private List filePaths; - - public ShowFileChooserResponse(boolean handledByClient, @Nullable List filePaths) { - this.handledByClient = handledByClient; - this.filePaths = filePaths; - } - - @Nullable - public static ShowFileChooserResponse fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - boolean handledByClient = (boolean) map.get("handledByClient"); - List filePaths = (List) map.get("filePaths"); - return new ShowFileChooserResponse(handledByClient, filePaths); - } - - public boolean isHandledByClient() { - return handledByClient; - } - - public void setHandledByClient(boolean handledByClient) { - this.handledByClient = handledByClient; - } - - @Nullable - public List getFilePaths() { - return filePaths; - } - - public void setFilePaths(@Nullable List filePaths) { - this.filePaths = filePaths; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ShowFileChooserResponse that = (ShowFileChooserResponse) o; - return handledByClient == that.handledByClient && Objects.equals(filePaths, that.filePaths); - } - - @Override - public int hashCode() { - int result = Boolean.hashCode(handledByClient); - result = 31 * result + Objects.hashCode(filePaths); - return result; - } - - @NonNull - @Override - public String toString() { - return "ShowFileChooserResponse{" + - "handledByClient=" + handledByClient + - ", filePaths=" + filePaths + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/Size2D.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/Size2D.java deleted file mode 100644 index da512690e9..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/Size2D.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.Nullable; - -import java.util.HashMap; -import java.util.Map; - -public class Size2D { - private double width; - private double height; - - public Size2D(double width, double height) { - this.width = width; - this.height = height; - } - - @Nullable - public static Size2D fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - Double width = (Double) map.get("width"); - Double height = (Double) map.get("height"); - assert width != null; - assert height != null; - return new Size2D(width, height); - } - - public Map toMap() { - Map sizeMap = new HashMap<>(); - sizeMap.put("width", width); - sizeMap.put("height", height); - return sizeMap; - } - - public double getWidth() { - return width; - } - - public void setWidth(double width) { - this.width = width; - } - - public double getHeight() { - return height; - } - - public void setHeight(double height) { - this.height = height; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Size2D size = (Size2D) o; - - if (Double.compare(size.width, width) != 0) return false; - return Double.compare(size.height, height) == 0; - } - - @Override - public int hashCode() { - int result; - long temp; - temp = Double.doubleToLongBits(width); - result = (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(height); - result = 31 * result + (int) (temp ^ (temp >>> 32)); - return result; - } - - @Override - public String toString() { - return "Size{" + - "width=" + width + - ", height=" + height + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/SslCertificateExt.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/SslCertificateExt.java deleted file mode 100644 index 3208745915..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/SslCertificateExt.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.net.http.SslCertificate; -import android.os.Build; - -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.Util; - -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; -import java.util.HashMap; -import java.util.Map; - -public class SslCertificateExt extends SslCertificate { - - private SslCertificateExt(X509Certificate certificate) { - super(certificate); - } - - @Nullable - static public Map toMap(@Nullable SslCertificate sslCertificate) { - if (sslCertificate == null) { - return null; - } - - DName issuedByName = sslCertificate.getIssuedBy(); - Map issuedBy = null; - if (issuedByName != null) { - issuedBy = new HashMap<>(); - issuedBy.put("CName", issuedByName.getCName()); - issuedBy.put("DName", issuedByName.getDName()); - issuedBy.put("OName", issuedByName.getOName()); - issuedBy.put("UName", issuedByName.getUName()); - } - - DName issuedToName = sslCertificate.getIssuedTo(); - Map issuedTo = null; - if (issuedToName != null) { - issuedTo = new HashMap<>(); - issuedTo.put("CName", issuedToName.getCName()); - issuedTo.put("DName", issuedToName.getDName()); - issuedTo.put("OName", issuedToName.getOName()); - issuedTo.put("UName", issuedToName.getUName()); - } - - byte[] x509CertificateData = null; - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - try { - X509Certificate certificate = sslCertificate.getX509Certificate(); - if (certificate != null) { - x509CertificateData = certificate.getEncoded(); - } - } catch (CertificateEncodingException e) { - e.printStackTrace(); - } - } else { - try { - x509CertificateData = Util.getX509CertFromSslCertHack(sslCertificate).getEncoded(); - } catch (CertificateEncodingException e) { - e.printStackTrace(); - } - } - - long validNotAfterDate = sslCertificate.getValidNotAfterDate().getTime(); - long validNotBeforeDate = sslCertificate.getValidNotBeforeDate().getTime(); - - Map sslCertificateMap = new HashMap<>(); - sslCertificateMap.put("issuedBy", issuedBy); - sslCertificateMap.put("issuedTo", issuedTo); - sslCertificateMap.put("validNotAfterDate", validNotAfterDate); - sslCertificateMap.put("validNotBeforeDate", validNotBeforeDate); - sslCertificateMap.put("x509Certificate", x509CertificateData); - return sslCertificateMap; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/SslErrorExt.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/SslErrorExt.java deleted file mode 100644 index f88313203e..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/SslErrorExt.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.net.http.SslCertificate; -import android.net.http.SslError; - -import androidx.annotation.Nullable; - -import java.util.HashMap; -import java.util.Map; - -public class SslErrorExt extends SslError { - - private SslErrorExt(int error, SslCertificate certificate, String url) { - super(error, certificate, url); - } - - @Nullable - static public Map toMap(SslError sslError) { - if (sslError == null) { - return null; - } - - int primaryError = sslError.getPrimaryError(); - - String message; - switch (primaryError) { - case SslError.SSL_DATE_INVALID: - message = "The date of the certificate is invalid"; - break; - case SslError.SSL_EXPIRED: - message = "The certificate has expired"; - break; - case SslError.SSL_IDMISMATCH: - message = "Hostname mismatch"; - break; - case SslError.SSL_INVALID: - message = "A generic error occurred"; - break; - case SslError.SSL_NOTYETVALID: - message = "The certificate is not yet valid"; - break; - case SslError.SSL_UNTRUSTED: - message = "The certificate authority is not trusted"; - break; - default: - message = null; - break; - } - - Map urlProtectionSpaceMap = new HashMap<>(); - urlProtectionSpaceMap.put("code", primaryError >= 0 ? primaryError : null); - urlProtectionSpaceMap.put("message", message); - return urlProtectionSpaceMap; - } - -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/SyncBaseCallbackResultImpl.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/SyncBaseCallbackResultImpl.java deleted file mode 100644 index 1fd2ee7e94..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/SyncBaseCallbackResultImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.CallSuper; -import androidx.annotation.Nullable; - -import java.util.concurrent.CountDownLatch; - -public class SyncBaseCallbackResultImpl extends BaseCallbackResultImpl { - final public CountDownLatch latch = new CountDownLatch(1); - @Nullable - public T result = null; - - @CallSuper - @Override - public void defaultBehaviour(@Nullable T result) { - latch.countDown(); - } - - @Override - public void success(@Nullable Object obj) { - T result = decodeResult(obj); - this.result = result; - boolean shouldRunDefaultBehaviour; - if (result == null) { - shouldRunDefaultBehaviour = nullSuccess(); - } else { - shouldRunDefaultBehaviour = nonNullSuccess(result); - } - if (shouldRunDefaultBehaviour) { - defaultBehaviour(result); - } else { - latch.countDown(); - } - } - - @CallSuper - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - latch.countDown(); - } - - @CallSuper - @Override - public void notImplemented() { - defaultBehaviour(null); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/URLAuthenticationChallenge.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/URLAuthenticationChallenge.java deleted file mode 100644 index 7d015071b4..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/URLAuthenticationChallenge.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import java.util.HashMap; -import java.util.Map; - -public class URLAuthenticationChallenge { - private URLProtectionSpace protectionSpace; - - public URLAuthenticationChallenge(URLProtectionSpace protectionSpace) { - this.protectionSpace = protectionSpace; - } - - public Map toMap() { - Map challengeMap = new HashMap<>(); - challengeMap.put("protectionSpace", protectionSpace.toMap()); - return challengeMap; - } - - public URLProtectionSpace getProtectionSpace() { - return protectionSpace; - } - - public void setProtectionSpace(URLProtectionSpace protectionSpace) { - this.protectionSpace = protectionSpace; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - URLAuthenticationChallenge challenge = (URLAuthenticationChallenge) o; - - return protectionSpace.equals(challenge.protectionSpace); - } - - @Override - public int hashCode() { - return protectionSpace.hashCode(); - } - - @Override - public String toString() { - return "URLAuthenticationChallenge{" + - "protectionSpace=" + protectionSpace + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/URLCredential.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/URLCredential.java deleted file mode 100644 index 0bf7251975..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/URLCredential.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.HashMap; -import java.util.Map; - -public class URLCredential { - @Nullable - private Long id; - @Nullable - private String username; - @Nullable - private String password; - @Nullable - private Long protectionSpaceId; - - public URLCredential(@Nullable String username, @Nullable String password) { - this.username = username; - this.password = password; - } - - public URLCredential (@Nullable Long id, @NonNull String username, @NonNull String password, @Nullable Long protectionSpaceId) { - this.id = id; - this.username = username; - this.password = password; - this.protectionSpaceId = protectionSpaceId; - } - - public Map toMap() { - Map urlCredentialMap = new HashMap<>(); - urlCredentialMap.put("username", username); - urlCredentialMap.put("password", password); - urlCredentialMap.put("certificates", null); - urlCredentialMap.put("persistence", null); - return urlCredentialMap; - } - - @Nullable - public Long getId() { - return id; - } - - public void setId(@Nullable Long id) { - this.id = id; - } - - @Nullable - public String getUsername() { - return username; - } - - public void setUsername(@Nullable String username) { - this.username = username; - } - - @Nullable - public String getPassword() { - return password; - } - - public void setPassword(@Nullable String password) { - this.password = password; - } - - @Nullable - public Long getProtectionSpaceId() { - return protectionSpaceId; - } - - public void setProtectionSpaceId(@Nullable Long protectionSpaceId) { - this.protectionSpaceId = protectionSpaceId; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - URLCredential that = (URLCredential) o; - - if (username != null ? !username.equals(that.username) : that.username != null) return false; - return password != null ? password.equals(that.password) : that.password == null; - } - - @Override - public int hashCode() { - int result = username != null ? username.hashCode() : 0; - result = 31 * result + (password != null ? password.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "URLCredential{" + - "username='" + username + '\'' + - ", password='" + password + '\'' + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/URLProtectionSpace.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/URLProtectionSpace.java deleted file mode 100644 index a27e97feea..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/URLProtectionSpace.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.net.http.SslCertificate; -import android.net.http.SslError; - -import androidx.annotation.Nullable; - -import java.util.HashMap; -import java.util.Map; - -public class URLProtectionSpace { - @Nullable - private Long id; - private String host; - private String protocol; - @Nullable - private String realm; - private int port; - @Nullable - private SslCertificate sslCertificate; - @Nullable - private SslError sslError; - - public URLProtectionSpace(String host, String protocol, @Nullable String realm, int port, @Nullable SslCertificate sslCertificate, @Nullable SslError sslError) { - this.host = host; - this.protocol = protocol; - this.realm = realm; - this.port = port; - this.sslCertificate = sslCertificate; - this.sslError = sslError; - } - - public URLProtectionSpace(@Nullable Long id, String host, String protocol, @Nullable String realm, int port) { - this.id = id; - this.host = host; - this.protocol = protocol; - this.realm = realm; - this.port = port; - } - - public Map toMap() { - Map urlProtectionSpaceMap = new HashMap<>(); - urlProtectionSpaceMap.put("host", host); - urlProtectionSpaceMap.put("protocol", protocol); - urlProtectionSpaceMap.put("realm", realm); - urlProtectionSpaceMap.put("port", port); - urlProtectionSpaceMap.put("sslCertificate", SslCertificateExt.toMap(sslCertificate)); - urlProtectionSpaceMap.put("sslError", SslErrorExt.toMap(sslError)); - urlProtectionSpaceMap.put("authenticationMethod", null); - urlProtectionSpaceMap.put("distinguishedNames", null); - urlProtectionSpaceMap.put("receivesCredentialSecurely", null); - urlProtectionSpaceMap.put("isProxy", null); - urlProtectionSpaceMap.put("proxyType", null); - return urlProtectionSpaceMap; - } - - @Nullable - public Long getId() { - return id; - } - - public void setId(@Nullable Long id) { - this.id = id; - } - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public String getProtocol() { - return protocol; - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - @Nullable - public String getRealm() { - return realm; - } - - public void setRealm(@Nullable String realm) { - this.realm = realm; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - @Nullable - public SslCertificate getSslCertificate() { - return sslCertificate; - } - - public void setSslCertificate(@Nullable SslCertificate sslCertificateExt) { - this.sslCertificate = sslCertificateExt; - } - - @Nullable - public SslError getSslError() { - return sslError; - } - - public void setSslError(@Nullable SslError sslError) { - this.sslError = sslError; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - URLProtectionSpace that = (URLProtectionSpace) o; - - if (port != that.port) return false; - if (!host.equals(that.host)) return false; - if (!protocol.equals(that.protocol)) return false; - if (realm != null ? !realm.equals(that.realm) : that.realm != null) return false; - if (sslCertificate != null ? !sslCertificate.equals(that.sslCertificate) : that.sslCertificate != null) - return false; - return sslError != null ? sslError.equals(that.sslError) : that.sslError == null; - } - - @Override - public int hashCode() { - int result = host.hashCode(); - result = 31 * result + protocol.hashCode(); - result = 31 * result + (realm != null ? realm.hashCode() : 0); - result = 31 * result + port; - result = 31 * result + (sslCertificate != null ? sslCertificate.hashCode() : 0); - result = 31 * result + (sslError != null ? sslError.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "URLProtectionSpace{" + - "host='" + host + '\'' + - ", protocol='" + protocol + '\'' + - ", realm='" + realm + '\'' + - ", port=" + port + - ", sslCertificate=" + sslCertificate + - ", sslError=" + sslError + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/URLRequest.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/URLRequest.java deleted file mode 100644 index d9d598d276..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/URLRequest.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.Nullable; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -public class URLRequest { - @Nullable - private String url; - @Nullable - private String method; - @Nullable - private byte[] body; - @Nullable - private Map headers; - - public URLRequest(@Nullable String url, @Nullable String method, @Nullable byte[] body, @Nullable Map headers) { - this.url = url; - this.method = method; - this.body = body; - this.headers = headers; - } - - @Nullable - public static URLRequest fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String url = (String) map.get("url"); - if (url == null) { - url = "about:blank"; - } - String method = (String) map.get("method"); - byte[] body = (byte[]) map.get("body"); - Map headers = (Map) map.get("headers"); - return new URLRequest(url, method, body, headers); - } - - public Map toMap() { - Map urlRequestMap = new HashMap<>(); - urlRequestMap.put("url", url); - urlRequestMap.put("method", method); - urlRequestMap.put("headers", headers); - urlRequestMap.put("body", body); - urlRequestMap.put("allowsCellularAccess", null); - urlRequestMap.put("allowsConstrainedNetworkAccess", null); - urlRequestMap.put("allowsExpensiveNetworkAccess", null); - urlRequestMap.put("cachePolicy", null); - urlRequestMap.put("httpShouldHandleCookies", null); - urlRequestMap.put("httpShouldUsePipelining", null); - urlRequestMap.put("networkServiceType", null); - urlRequestMap.put("timeoutInterval", null); - urlRequestMap.put("mainDocumentURL", null); - urlRequestMap.put("assumesHTTP3Capable", null); - urlRequestMap.put("attribution", null); - return urlRequestMap; - } - - @Nullable - public String getUrl() { - return url; - } - - public void setUrl(@Nullable String url) { - this.url = url; - } - - @Nullable - public String getMethod() { - return method; - } - - public void setMethod(@Nullable String method) { - this.method = method; - } - - @Nullable - public byte[] getBody() { - return body; - } - - public void setBody(@Nullable byte[] body) { - this.body = body; - } - - @Nullable - public Map getHeaders() { - return headers; - } - - public void setHeaders(@Nullable Map headers) { - this.headers = headers; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - URLRequest that = (URLRequest) o; - - if (url != null ? !url.equals(that.url) : that.url != null) return false; - if (method != null ? !method.equals(that.method) : that.method != null) return false; - if (!Arrays.equals(body, that.body)) return false; - return headers != null ? headers.equals(that.headers) : that.headers == null; - } - - @Override - public int hashCode() { - int result = url != null ? url.hashCode() : 0; - result = 31 * result + (method != null ? method.hashCode() : 0); - result = 31 * result + Arrays.hashCode(body); - result = 31 * result + (headers != null ? headers.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "URLRequest{" + - "url='" + url + '\'' + - ", method='" + method + '\'' + - ", body=" + Arrays.toString(body) + - ", headers=" + headers + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserContentController.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserContentController.java deleted file mode 100644 index 0e59a581dd..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserContentController.java +++ /dev/null @@ -1,538 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.annotation.SuppressLint; -import android.text.TextUtils; -import android.webkit.WebView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.ScriptHandler; -import androidx.webkit.WebViewCompat; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.Util; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.JavaScriptBridgeJS; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.PluginScriptsUtil; - -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -@SuppressLint("RestrictedApi") -public class UserContentController implements Disposable { - protected static final String LOG_TAG = "UserContentController"; - - @NonNull - private final Set contentWorlds = new HashSet() {{ - add(ContentWorld.PAGE); - }}; - - private final Map scriptHandlerMap = new HashMap<>(); - - @Nullable - private ScriptHandler contentWorldsCreatorScript; - - @NonNull - private final Map> userOnlyScripts = new HashMap>() {{ - put(UserScriptInjectionTime.AT_DOCUMENT_START, new LinkedHashSet()); - put(UserScriptInjectionTime.AT_DOCUMENT_END, new LinkedHashSet()); - }}; - @NonNull - private final Map> pluginScripts = new HashMap>() {{ - put(UserScriptInjectionTime.AT_DOCUMENT_START, new LinkedHashSet()); - put(UserScriptInjectionTime.AT_DOCUMENT_END, new LinkedHashSet()); - }}; - - @Nullable - public WebView webView; - - public UserContentController(@Nullable WebView webView) { - this.webView = webView; - } - - public String generateWrappedCodeForDocumentStart() { - return Util.replaceAll( - DOCUMENT_READY_WRAPPER_JS_SOURCE, - PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, - generateCodeForDocumentStart()); - } - - public String generateWrappedCodeForDocumentEnd() { - UserScriptInjectionTime injectionTime = UserScriptInjectionTime.AT_DOCUMENT_END; - String js = ""; - if (!WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { - // try to reload scripts if they were not loaded during the AT_DOCUMENT_START event - js += generateCodeForDocumentStart(); - } - js += generatePluginScriptsCodeAt(injectionTime); - js += generateUserOnlyScriptsCodeAt(injectionTime); - js = USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE().replace(PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, js); - return js; - } - - public String generateCodeForDocumentStart() { - UserScriptInjectionTime injectionTime = UserScriptInjectionTime.AT_DOCUMENT_START; - String js = ""; - js += generatePluginScriptsCodeAt(injectionTime); - js += generateContentWorldsCreatorCode(); - js += generateUserOnlyScriptsCodeAt(injectionTime); - js = USER_SCRIPTS_AT_DOCUMENT_START_WRAPPER_JS_SOURCE().replace(PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, js); - return js; - } - - public String generateContentWorldsCreatorCode() { - if (this.contentWorlds.size() == 1) { - return ""; - } - - StringBuilder source = new StringBuilder(); - LinkedHashSet pluginScriptsRequired = this.getPluginScriptsRequiredInAllContentWorlds(); - for (PluginScript script : pluginScriptsRequired) { - source.append(script.getSource()); - } - List contentWorldsNames = new ArrayList<>(); - for (ContentWorld contentWorld : this.contentWorlds) { - if (contentWorld.equals(ContentWorld.PAGE)) { - continue; - } - contentWorldsNames.add("'" + escapeContentWorldName(contentWorld.getName()) + "'"); - } - - return CONTENT_WORLDS_GENERATOR_JS_SOURCE() - .replace(PluginScriptsUtil.VAR_CONTENT_WORLD_NAME_ARRAY, TextUtils.join(", ", contentWorldsNames)) - .replace(PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED, escapeCode(source.toString())); - - } - - public String generatePluginScriptsCodeAt(UserScriptInjectionTime injectionTime) { - StringBuilder js = new StringBuilder(); - LinkedHashSet scripts = this.getPluginScriptsAt(injectionTime); - for (PluginScript script : scripts) { - String source = ";" + script.getSource(); - source = wrapSourceCodeInContentWorld(script.getContentWorld(), source); - source = wrapSourceCodeAddChecks(source, script); - js.append(source); - } - return js.toString(); - } - - public String generateUserOnlyScriptsCodeAt(UserScriptInjectionTime injectionTime) { - StringBuilder js = new StringBuilder(); - LinkedHashSet scripts = this.getUserOnlyScriptsAt(injectionTime); - for (UserScript script : scripts) { - String source = ";" + script.getSource(); - source = wrapSourceCodeInContentWorld(script.getContentWorld(), source); - source = wrapSourceCodeAddChecks(source, script); - js.append(source); - } - return js.toString(); - } - - public String generateCodeForScriptEvaluation(String source, @Nullable ContentWorld contentWorld) { - if (contentWorld != null && !contentWorld.equals(ContentWorld.PAGE)) { - StringBuilder sourceWrapped = new StringBuilder(); - if (!contentWorlds.contains(contentWorld)) { - contentWorlds.add(contentWorld); - - StringBuilder pluginScriptsSource = new StringBuilder(); - LinkedHashSet pluginScriptsRequired = this.getPluginScriptsRequiredInAllContentWorlds(); - for (PluginScript script : pluginScriptsRequired) { - pluginScriptsSource.append(script.getSource()); - } - String contentWorldCreatorCode = CONTENT_WORLDS_GENERATOR_JS_SOURCE() - .replace(PluginScriptsUtil.VAR_CONTENT_WORLD_NAME_ARRAY, "'" + escapeContentWorldName(contentWorld.getName()) + "'") - .replace(PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED, escapeCode(pluginScriptsSource.toString())); - sourceWrapped.append(contentWorldCreatorCode).append(";"); - } - return sourceWrapped.append(wrapSourceCodeInContentWorld(contentWorld, source)).toString(); - } - return source; - } - - public String wrapSourceCodeInContentWorld(@Nullable ContentWorld contentWorld, String source) { - String sourceWrapped = contentWorld == null || contentWorld.equals(ContentWorld.PAGE) ? source : - CONTENT_WORLD_WRAPPER_JS_SOURCE() - .replace(PluginScriptsUtil.VAR_CONTENT_WORLD_NAME, escapeContentWorldName(contentWorld.getName())) - .replace(PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED, escapeCode(source)); - - return sourceWrapped; - } - - public static String escapeCode(String code) { - String escapedCode = JSONObject.quote(code); - // escapedCode = escapedCode.substring(1, escapedCode.length() - 1); - return escapedCode; - } - - public static String escapeContentWorldName(String name) { - return name.replaceAll("'", "\\\\'"); - } - - public LinkedHashSet getUserOnlyScriptsAt(UserScriptInjectionTime injectionTime) { - return new LinkedHashSet<>(this.userOnlyScripts.get(injectionTime)); - } - - private void updateContentWorldsCreatorScript() { - String source = generateContentWorldsCreatorCode(); - if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { - if (contentWorldsCreatorScript != null) { - contentWorldsCreatorScript.remove(); - } - if (!source.isEmpty() && webView != null) { - contentWorldsCreatorScript = WebViewCompat.addDocumentStartJavaScript( - webView, - source, - new HashSet() {{ - add("*"); - }} - ); - } - } - } - - public boolean addUserOnlyScript(UserScript userOnlyScript) { - ContentWorld contentWorld = userOnlyScript.getContentWorld(); - if (contentWorld != null) { - contentWorlds.add(contentWorld); - } - this.updateContentWorldsCreatorScript(); - if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { - String source = userOnlyScript.getSource(); - if (userOnlyScript.getInjectionTime() == UserScriptInjectionTime.AT_DOCUMENT_END) { - source = "if (document.readyState === 'complete') { " + source + "} else { window.addEventListener('load', function() { " + source + " }); }"; - } - source = wrapSourceCodeAddChecks(source, userOnlyScript); - - ScriptHandler scriptHandler = WebViewCompat.addDocumentStartJavaScript( - webView, - wrapSourceCodeInContentWorld(userOnlyScript.getContentWorld(), source), - userOnlyScript.getAllowedOriginRules() - ); - this.scriptHandlerMap.put(userOnlyScript, scriptHandler); - } - return this.userOnlyScripts.get(userOnlyScript.getInjectionTime()).add(userOnlyScript); - } - - public void addUserOnlyScripts(List userOnlyScripts) { - for (UserScript userOnlyScript : userOnlyScripts) { - this.addUserOnlyScript(userOnlyScript); - } - } - - public boolean removeUserOnlyScript(UserScript userOnlyScript) { - if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { - ScriptHandler scriptHandler = this.scriptHandlerMap.get(userOnlyScript); - if (scriptHandler != null) { - scriptHandler.remove(); - this.scriptHandlerMap.remove(userOnlyScript); - } - this.updateContentWorldsCreatorScript(); - } - return this.userOnlyScripts.get(userOnlyScript.getInjectionTime()).remove(userOnlyScript); - } - - public boolean removeUserOnlyScriptAt(int index, UserScriptInjectionTime injectionTime) { - UserScript userOnlyScript = new ArrayList<>(this.userOnlyScripts.get(injectionTime)).get(index); - return this.removeUserOnlyScript(userOnlyScript); - } - - public void removeAllUserOnlyScripts() { - if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { - for (UserScript userOnlyScript : this.userOnlyScripts.get(UserScriptInjectionTime.AT_DOCUMENT_START)) { - ScriptHandler scriptHandler = this.scriptHandlerMap.get(userOnlyScript); - if (scriptHandler != null) { - scriptHandler.remove(); - this.scriptHandlerMap.remove(userOnlyScript); - } - } - for (UserScript userOnlyScript : this.userOnlyScripts.get(UserScriptInjectionTime.AT_DOCUMENT_END)) { - ScriptHandler scriptHandler = this.scriptHandlerMap.get(userOnlyScript); - if (scriptHandler != null) { - scriptHandler.remove(); - this.scriptHandlerMap.remove(userOnlyScript); - } - } - } - this.userOnlyScripts.get(UserScriptInjectionTime.AT_DOCUMENT_START).clear(); - this.userOnlyScripts.get(UserScriptInjectionTime.AT_DOCUMENT_END).clear(); - } - - public LinkedHashSet getPluginScriptsAt(UserScriptInjectionTime injectionTime) { - return new LinkedHashSet<>(this.pluginScripts.get(injectionTime)); - } - - public LinkedHashSet getPluginScriptsRequiredInAllContentWorlds() { - LinkedHashSet pluginScriptsRequired = new LinkedHashSet<>(); - LinkedHashSet scripts = this.getPluginScriptsAt(UserScriptInjectionTime.AT_DOCUMENT_START); - for (PluginScript script : scripts) { - if (script.isRequiredInAllContentWorlds()) { - pluginScriptsRequired.add(script); - } - } - return pluginScriptsRequired; - } - - public boolean addPluginScript(PluginScript pluginScript) { - ContentWorld contentWorld = pluginScript.getContentWorld(); - if (contentWorld != null) { - contentWorlds.add(contentWorld); - } - this.updateContentWorldsCreatorScript(); - if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { - String source = pluginScript.getSource(); - if (pluginScript.getInjectionTime() == UserScriptInjectionTime.AT_DOCUMENT_END) { - source = "if (document.readyState === 'complete') { " + source + "} else { window.addEventListener('load', function() { " + source + " }); }"; - } - source = wrapSourceCodeAddChecks(source, pluginScript); - - ScriptHandler scriptHandler = WebViewCompat.addDocumentStartJavaScript( - webView, - wrapSourceCodeInContentWorld(pluginScript.getContentWorld(), source), - pluginScript.getAllowedOriginRules() - ); - this.scriptHandlerMap.put(pluginScript, scriptHandler); - } - return this.pluginScripts.get(pluginScript.getInjectionTime()).add(pluginScript); - } - - public void addPluginScripts(List pluginScripts) { - for (PluginScript pluginScript : pluginScripts) { - this.addPluginScript(pluginScript); - } - } - - public boolean removePluginScript(PluginScript pluginScript) { - if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { - ScriptHandler scriptHandler = this.scriptHandlerMap.get(pluginScript); - if (scriptHandler != null) { - scriptHandler.remove(); - this.scriptHandlerMap.remove(pluginScript); - } - this.updateContentWorldsCreatorScript(); - } - return this.pluginScripts.get(pluginScript.getInjectionTime()).remove(pluginScript); - } - - public void removeAllPluginScripts() { - if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { - for (PluginScript pluginScript : this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_START)) { - ScriptHandler scriptHandler = this.scriptHandlerMap.get(pluginScript); - if (scriptHandler != null) { - scriptHandler.remove(); - this.scriptHandlerMap.remove(pluginScript); - } - } - for (PluginScript pluginScript : this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_END)) { - ScriptHandler scriptHandler = this.scriptHandlerMap.get(pluginScript); - if (scriptHandler != null) { - scriptHandler.remove(); - this.scriptHandlerMap.remove(pluginScript); - } - } - } - this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_START).clear(); - this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_END).clear(); - } - - public LinkedHashSet getUserOnlyScriptAsList() { - LinkedHashSet userOnlyScripts = new LinkedHashSet<>(); - Collection> collection = this.userOnlyScripts.values(); - for (LinkedHashSet list : collection) { - userOnlyScripts.addAll(list); - } - return userOnlyScripts; - } - - public LinkedHashSet getPluginScriptAsList() { - LinkedHashSet pluginScripts = new LinkedHashSet<>(); - Collection> collection = this.pluginScripts.values(); - for (LinkedHashSet list : collection) { - pluginScripts.addAll(list); - } - return pluginScripts; - } - - public void resetContentWorlds() { - this.contentWorlds.clear(); - this.contentWorlds.add(ContentWorld.PAGE); - - LinkedHashSet pluginScripts = this.getPluginScriptAsList(); - for (PluginScript pluginScript : pluginScripts) { - ContentWorld contentWorld = pluginScript.getContentWorld(); - this.contentWorlds.add(contentWorld); - } - - LinkedHashSet userOnlyScripts = this.getUserOnlyScriptAsList(); - for (UserScript userOnlyScript : userOnlyScripts) { - ContentWorld contentWorld = userOnlyScript.getContentWorld(); - this.contentWorlds.add(contentWorld); - } - } - - public boolean containsPluginScript(PluginScript pluginScript) { - return this.getPluginScriptAsList().contains(pluginScript); - } - - public boolean containsPluginScriptByGroupName(String groupName) { - LinkedHashSet pluginScripts = this.getPluginScriptAsList(); - for (PluginScript pluginScript : pluginScripts) { - if (Util.objEquals(groupName, pluginScript.getGroupName())) { - return true; - } - } - return false; - } - - public boolean containsUserOnlyScript(UserScript userOnlyScript) { - return this.getUserOnlyScriptAsList().contains(userOnlyScript); - } - - public boolean containsUserOnlyScriptByGroupName(String groupName) { - LinkedHashSet userOnlyScripts = this.getUserOnlyScriptAsList(); - for (UserScript userOnlyScript : userOnlyScripts) { - if (Util.objEquals(groupName, userOnlyScript.getGroupName())) { - return true; - } - } - - return false; - } - - public void removePluginScriptsByGroupName(String groupName) { - LinkedHashSet pluginScripts = this.getPluginScriptAsList(); - for (PluginScript pluginScript : pluginScripts) { - if (Util.objEquals(groupName, pluginScript.getGroupName())) { - this.removePluginScript(pluginScript); - } - } - } - - public void removeUserOnlyScriptsByGroupName(String groupName) { - LinkedHashSet userOnlyScripts = this.getUserOnlyScriptAsList(); - for (UserScript userOnlyScript : userOnlyScripts) { - if (Util.objEquals(groupName, userOnlyScript.getGroupName())) { - this.removeUserOnlyScript(userOnlyScript); - } - } - } - - @NonNull - public LinkedHashSet getContentWorlds() { - return new LinkedHashSet<>(this.contentWorlds); - } - - static private String wrapSourceCodeAddChecks(String source, UserScript userScript) { - StringBuilder ifStatement = new StringBuilder("if ("); - Set allowedOriginRules = userScript.getAllowedOriginRules(); - boolean forMainFrameOnly = userScript.isForMainFrameOnly(); - if (!WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT) && !allowedOriginRules.contains("*")) { - if (allowedOriginRules.isEmpty()) { - // return empty source string if allowedOriginRules is an empty list. - // an empty list means that this UserScript is not allowed for any origin. - return ""; - } - StringBuilder jsRegExpArray = new StringBuilder("["); - for (String allowedOriginRule : allowedOriginRules) { - if (jsRegExpArray.length() > 1) { - jsRegExpArray.append(", "); - } - jsRegExpArray.append("new RegExp(").append(UserContentController.escapeCode(allowedOriginRule)).append(")"); - } - if (jsRegExpArray.length() > 1) { - jsRegExpArray.append("]"); - ifStatement.append(jsRegExpArray).append(".some(function(rx) { return rx.test(window.location.origin); })"); - } - } - if (forMainFrameOnly) { - if (ifStatement.length() > 4) { - ifStatement.append(" && "); - } - ifStatement.append("window === window.top"); - } - return ifStatement.length() > 4 ? ifStatement.append(") {").append(source).append("}").toString() : source; - } - - private static String USER_SCRIPTS_AT_DOCUMENT_START_WRAPPER_JS_SOURCE() { - return "if (window._" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_userScriptsAtDocumentStartLoaded == null || !window._" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_userScriptsAtDocumentStartLoaded) {" + - " window._" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_userScriptsAtDocumentStartLoaded = true;" + - " " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE + - "}"; - } - - private static String USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE() { - return "if (window._" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_userScriptsAtDocumentEndLoaded == null || !window._" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_userScriptsAtDocumentEndLoaded) {" + - " window._" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_userScriptsAtDocumentEndLoaded = true;" + - " " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE + - "}"; - } - - private static String CONTENT_WORLDS_GENERATOR_JS_SOURCE() { - return "(function() {" + - " var interval = setInterval(function() {" + - " if (document.body == null) {return;}" + - " var contentWorldNames = [" + PluginScriptsUtil.VAR_CONTENT_WORLD_NAME_ARRAY + "];" + - " for (var contentWorldName of contentWorldNames) {" + - " var iframeId = '" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_' + contentWorldName;" + - " var iframe = document.getElementById(iframeId);" + - " if (iframe == null) {" + - " iframe = document.createElement('iframe');" + - " iframe.id = iframeId;" + - " iframe.style = 'display: none; z-index: 0; position: absolute; width: 0px; height: 0px';" + - " document.body.append(iframe);" + - " }" + - " if (iframe.contentWindow.document.getElementById('" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_plugin_scripts') == null) {" + - " var script = iframe.contentWindow.document.createElement('script');" + - " script.id = '" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_plugin_scripts';" + - " script.innerHTML = " + PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED + ";" + - " iframe.contentWindow.document.body.append(script);" + - " }" + - " }" + - " clearInterval(interval);" + - " });" + - "})();"; - } - - private static String CONTENT_WORLD_WRAPPER_JS_SOURCE() { - return "(function() {" + - " var interval = setInterval(function() {" + - " if (document.body == null) {return;}" + - " var iframeId = '" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_" + PluginScriptsUtil.VAR_CONTENT_WORLD_NAME + "';" + - " var iframe = document.getElementById(iframeId);" + - " if (iframe == null) {" + - " iframe = document.createElement('iframe');" + - " iframe.id = iframeId;" + - " iframe.style = 'display: none; z-index: 0; position: absolute; width: 0px; height: 0px';" + - " document.body.append(iframe);" + - " }" + - " if (iframe.contentWindow.document.querySelector('#" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_plugin_scripts') == null) {" + - " return;" + - " }" + - " var script = iframe.contentWindow.document.createElement('script');" + - " script.innerHTML = " + PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED + ";" + - " iframe.contentWindow.document.body.append(script);" + - " clearInterval(interval);" + - " });" + - "})();"; - } - - private static final String DOCUMENT_READY_WRAPPER_JS_SOURCE = "if (document.readyState === 'interactive' || document.readyState === 'complete') { " + - " " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE + - "}"; - - @Override - public void dispose() { - if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT) && contentWorldsCreatorScript != null) { - contentWorldsCreatorScript.remove(); - } - removeAllUserOnlyScripts(); - removeAllPluginScripts(); - webView = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserScript.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserScript.java deleted file mode 100644 index d440984b2e..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserScript.java +++ /dev/null @@ -1,138 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.WebViewFeature; - -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -public class UserScript { - @Nullable - private String groupName; - @NonNull - private String source; - @NonNull - private UserScriptInjectionTime injectionTime; - @NonNull - private ContentWorld contentWorld; - @NonNull - private Set allowedOriginRules = new HashSet<>(); - private boolean forMainFrameOnly = true; - - public UserScript(@Nullable String groupName, @NonNull String source, - @NonNull UserScriptInjectionTime injectionTime, @Nullable ContentWorld contentWorld, - @Nullable Set allowedOriginRules, boolean forMainFrameOnly) { - this.groupName = groupName; - this.source = source; - this.injectionTime = injectionTime; - this.contentWorld = contentWorld == null ? ContentWorld.PAGE : contentWorld; - this.allowedOriginRules = allowedOriginRules == null ? new HashSet() {{ - add("*"); - }} : allowedOriginRules; - this.forMainFrameOnly = forMainFrameOnly; - } - - @Nullable - public static UserScript fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String groupName = (String) map.get("groupName"); - String source = (String) map.get("source"); - UserScriptInjectionTime injectionTime = UserScriptInjectionTime.fromValue((int) map.get("injectionTime")); - ContentWorld contentWorld = ContentWorld.fromMap((Map) map.get("contentWorld")); - Set allowedOriginRules = new HashSet<>((List) map.get("allowedOriginRules")); - boolean forMainFrameOnly = (boolean) map.get("forMainFrameOnly"); - assert source != null; - return new UserScript(groupName, source, injectionTime, contentWorld, allowedOriginRules, forMainFrameOnly); - } - - @Nullable - public String getGroupName() { - return groupName; - } - - public void setGroupName(@Nullable String groupName) { - this.groupName = groupName; - } - - @NonNull - public String getSource() { - return source; - } - - public void setSource(@NonNull String source) { - this.source = source; - } - - @NonNull - public UserScriptInjectionTime getInjectionTime() { - return injectionTime; - } - - public void setInjectionTime(@NonNull UserScriptInjectionTime injectionTime) { - this.injectionTime = injectionTime; - } - - @NonNull - public ContentWorld getContentWorld() { - return contentWorld; - } - - public void setContentWorld(@Nullable ContentWorld contentWorld) { - this.contentWorld = contentWorld == null ? ContentWorld.PAGE : contentWorld; - } - - @NonNull - public Set getAllowedOriginRules() { - return allowedOriginRules; - } - - public void setAllowedOriginRules(@NonNull Set allowedOriginRules) { - this.allowedOriginRules = allowedOriginRules; - } - - public boolean isForMainFrameOnly() { - return forMainFrameOnly; - } - - public void setForMainFrameOnly(boolean forMainFrameOnly) { - this.forMainFrameOnly = forMainFrameOnly; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - UserScript that = (UserScript) o; - return forMainFrameOnly == that.forMainFrameOnly && Objects.equals(groupName, that.groupName) && source.equals(that.source) && injectionTime == that.injectionTime && contentWorld.equals(that.contentWorld) && allowedOriginRules.equals(that.allowedOriginRules); - } - - @Override - public int hashCode() { - int result = Objects.hashCode(groupName); - result = 31 * result + source.hashCode(); - result = 31 * result + injectionTime.hashCode(); - result = 31 * result + contentWorld.hashCode(); - result = 31 * result + allowedOriginRules.hashCode(); - result = 31 * result + Boolean.hashCode(forMainFrameOnly); - return result; - } - - @Override - public String toString() { - return "UserScript{" + - "groupName='" + groupName + '\'' + - ", source='" + source + '\'' + - ", injectionTime=" + injectionTime + - ", contentWorld=" + contentWorld + - ", allowedOriginRules=" + allowedOriginRules + - ", forMainFrameOnly=" + forMainFrameOnly + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserScriptInjectionTime.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserScriptInjectionTime.java deleted file mode 100644 index bfceeb854c..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserScriptInjectionTime.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -public enum UserScriptInjectionTime { - AT_DOCUMENT_START (0), - AT_DOCUMENT_END (1); - - private final int value; - - private UserScriptInjectionTime(int value) { - this.value = value; - } - - public boolean equalsValue(int otherValue) { - return value == otherValue; - } - - public static UserScriptInjectionTime fromValue(int value) { - for( UserScriptInjectionTime type : UserScriptInjectionTime.values()) { - if(value == type.toValue()) - return type; - } - throw new IllegalArgumentException("No enum constant: " + value); - } - - public int toValue() { - return this.value; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessage.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessage.java deleted file mode 100644 index 21ed0f03b0..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessage.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.Nullable; - -import java.util.List; - -public class WebMessage { - @Nullable - public String data; - @Nullable - public List ports; - - public WebMessage(@Nullable String data, @Nullable List ports) { - this.data = data; - this.ports = ports; - } - - public void dispose() { - if (ports != null) { - ports.clear(); - } - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessageCompatExt.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessageCompatExt.java deleted file mode 100644 index b635b3c434..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessageCompatExt.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.WebMessageCompat; -import androidx.webkit.WebViewFeature; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -public class WebMessageCompatExt { - @Nullable - private Object data; - private @WebMessageCompat.Type int type; - - @Nullable - private List ports; - - public WebMessageCompatExt(@Nullable Object data, int type, @Nullable List ports) { - this.data = data; - this.type = type; - this.ports = ports; - } - - public static WebMessageCompatExt fromMapWebMessageCompat(@NonNull WebMessageCompat message) { - Object data; - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER) && message.getType() == WebMessageCompat.TYPE_ARRAY_BUFFER) { - data = message.getArrayBuffer(); - } else { - data = message.getData(); - } - return new WebMessageCompatExt(data, message.getType(), null); - } - - @Nullable - public static WebMessageCompatExt fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - Object data = map.get("data"); - Integer type = (Integer) map.get("type"); - List> portMapList = (List>) map.get("ports"); - List ports = null; - if (portMapList != null && !portMapList.isEmpty()) { - ports = new ArrayList<>(); - for (Map portMap : portMapList) { - ports.add(WebMessagePortCompatExt.fromMap(portMap)); - } - } - return new WebMessageCompatExt(data, type, ports); - } - - public Map toMap() { - Map proxyRuleMap = new HashMap<>(); - proxyRuleMap.put("data", data); - proxyRuleMap.put("type", type); - return proxyRuleMap; - } - - @Nullable - public Object getData() { - return data; - } - - public void setData(@Nullable Object data) { - this.data = data; - } - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } - - @Nullable - public List getPorts() { - return ports; - } - - public void setPorts(@Nullable List ports) { - this.ports = ports; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - WebMessageCompatExt that = (WebMessageCompatExt) o; - - if (type != that.type) return false; - if (!Objects.equals(data, that.data)) return false; - return Objects.equals(ports, that.ports); - } - - @Override - public int hashCode() { - int result = data != null ? data.hashCode() : 0; - result = 31 * result + type; - result = 31 * result + (ports != null ? ports.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "WebMessageCompatExt{" + - "data=" + data + - ", type=" + type + - ", ports=" + ports + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessagePort.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessagePort.java deleted file mode 100644 index be9003810e..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessagePort.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.text.TextUtils; -import android.webkit.ValueCallback; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.Util; -import com.pichillilorenzo.flutter_inappwebview_android.webview.InAppWebViewInterface; -import com.pichillilorenzo.flutter_inappwebview_android.webview.web_message.WebMessageChannel; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.JavaScriptBridgeJS; - -import java.util.ArrayList; -import java.util.List; - -public class WebMessagePort { - public String name; - @Nullable - public WebMessageChannel webMessageChannel; - public boolean isClosed = false; - public boolean isTransferred = false; - public boolean isStarted = false; - - public WebMessagePort(String name, @NonNull WebMessageChannel webMessageChannel) { - this.name = name; - this.webMessageChannel = webMessageChannel; - } - - public void setWebMessageCallback(final ValueCallback callback) throws Exception { - if (isClosed || isTransferred) { - throw new Exception("Port is already closed or transferred"); - } - this.isStarted = true; - InAppWebViewInterface webView = webMessageChannel != null && webMessageChannel.webView != null ? webMessageChannel.webView : null; - if (webView != null) { - int index = name.equals("port1") ? 0 : 1; - webView.evaluateJavascript("(function() {" + - " var webMessageChannel = " + JavaScriptBridgeJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME() + "['" + webMessageChannel.id + "'];" + - " if (webMessageChannel != null) {" + - " webMessageChannel." + this.name + ".onmessage = function (event) {" + - " window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onWebMessagePortMessageReceived', {" + - " 'webMessageChannelId': '" + webMessageChannel.id + "'," + - " 'index': " + index + "," + - " 'message': event.data" + - " });" + - " }" + - " }" + - "})();", null, new ValueCallback() { - @Override - public void onReceiveValue(String value) { - if (callback != null) { - callback.onReceiveValue(null); - } - } - }); - } else { - if (callback != null) { - callback.onReceiveValue(null); - } - } - } - - public void postMessage(WebMessage message, final ValueCallback callback) throws Exception { - if (isClosed || isTransferred) { - throw new Exception("Port is already closed or transferred"); - } - InAppWebViewInterface webView = webMessageChannel != null && webMessageChannel.webView != null ? webMessageChannel.webView : null; - if (webView != null) { - String portsString = "null"; - List ports = message.ports; - if (ports != null) { - List portArrayString = new ArrayList<>(); - for (WebMessagePort port : ports) { - if (port == this) { - throw new Exception("Source port cannot be transferred"); - } - if (port.isStarted) { - throw new Exception("Port is already started"); - } - if (port.isClosed || port.isTransferred) { - throw new Exception("Port is already closed or transferred"); - } - port.isTransferred = true; - portArrayString.add(JavaScriptBridgeJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME() + "['" + webMessageChannel.id + "']." + port.name); - } - portsString = "[" + TextUtils.join(", ", portArrayString) + "]"; - } - String data = message.data != null ? Util.replaceAll(message.data, "\'", "\\'") : "null"; - String source = "(function() {" + - " var webMessageChannel = " + JavaScriptBridgeJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME() + "['" + webMessageChannel.id + "'];" + - " if (webMessageChannel != null) {" + - " webMessageChannel." + this.name + ".postMessage('" + data + "', " + portsString + ");" + - " }" + - "})();"; - webView.evaluateJavascript(source, null, new ValueCallback() { - @Override - public void onReceiveValue(String value) { - callback.onReceiveValue(null); - } - }); - } else { - callback.onReceiveValue(null); - } - message.dispose(); - } - - public void close(final ValueCallback callback) throws Exception { - if (isTransferred) { - throw new Exception("Port is already transferred"); - } - isClosed = true; - InAppWebViewInterface webView = webMessageChannel != null && webMessageChannel.webView != null ? webMessageChannel.webView : null; - if (webView != null) { - String source = "(function() {" + - " var webMessageChannel = " + JavaScriptBridgeJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME() + "['" + webMessageChannel.id + "'];" + - " if (webMessageChannel != null) {" + - " webMessageChannel." + this.name + ".close();" + - " }" + - "})();"; - webView.evaluateJavascript(source, null, new ValueCallback() { - @Override - public void onReceiveValue(String value) { - callback.onReceiveValue(null); - } - }); - } else { - callback.onReceiveValue(null); - } - } - - public void dispose() { - isClosed = true; - webMessageChannel = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessagePortCompatExt.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessagePortCompatExt.java deleted file mode 100644 index a03e4d65f0..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessagePortCompatExt.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.HashMap; -import java.util.Map; - -public class WebMessagePortCompatExt { - private int index; - @NonNull - private String webMessageChannelId; - - public WebMessagePortCompatExt(int index, @NonNull String webMessageChannelId) { - this.index = index; - this.webMessageChannelId = webMessageChannelId; - } - - @Nullable - public static WebMessagePortCompatExt fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - Integer index = (Integer) map.get("index"); - String webMessageChannelId = (String) map.get("webMessageChannelId"); - return new WebMessagePortCompatExt(index, webMessageChannelId); - } - - public Map toMap() { - Map proxyRuleMap = new HashMap<>(); - proxyRuleMap.put("index", index); - proxyRuleMap.put("webMessageChannelId", webMessageChannelId); - return proxyRuleMap; - } - - public int getIndex() { - return index; - } - - public void setIndex(int index) { - this.index = index; - } - - @NonNull - public String getWebMessageChannelId() { - return webMessageChannelId; - } - - public void setWebMessageChannelId(@NonNull String webMessageChannelId) { - this.webMessageChannelId = webMessageChannelId; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - WebMessagePortCompatExt that = (WebMessagePortCompatExt) o; - - if (index != that.index) return false; - return webMessageChannelId.equals(that.webMessageChannelId); - } - - @Override - public int hashCode() { - int result = index; - result = 31 * result + webMessageChannelId.hashCode(); - return result; - } - - @Override - public String toString() { - return "WebMessagePortCompatExt{" + - "index=" + index + - ", webMessageChannelId='" + webMessageChannelId + '\'' + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebResourceErrorExt.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebResourceErrorExt.java deleted file mode 100644 index bf23cc73ad..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebResourceErrorExt.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.os.Build; -import android.webkit.WebResourceError; - -import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; -import androidx.webkit.WebResourceErrorCompat; -import androidx.webkit.WebViewFeature; - -import java.util.HashMap; -import java.util.Map; - -public class WebResourceErrorExt { - private int type; - @NonNull - private String description; - - public WebResourceErrorExt(int type, @NonNull String description) { - this.type = type; - this.description = description; - } - - @RequiresApi(Build.VERSION_CODES.M) - static public WebResourceErrorExt fromWebResourceError(@NonNull WebResourceError error) { - return new WebResourceErrorExt(error.getErrorCode(), error.getDescription().toString()); - } - - @RequiresApi(Build.VERSION_CODES.M) - static public WebResourceErrorExt fromWebResourceError(@NonNull WebResourceErrorCompat error) { - int type = -1; - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_RESOURCE_ERROR_GET_CODE)) { - type = error.getErrorCode(); - } - String description = ""; - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_RESOURCE_ERROR_GET_DESCRIPTION)) { - description = error.getDescription().toString(); - } - return new WebResourceErrorExt(type, description); - } - - public Map toMap() { - Map webResourceErrorMap = new HashMap<>(); - webResourceErrorMap.put("type", getType()); - webResourceErrorMap.put("description", getDescription()); - return webResourceErrorMap; - } - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } - - @NonNull - public String getDescription() { - return description; - } - - public void setDescription(@NonNull String description) { - this.description = description; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - WebResourceErrorExt that = (WebResourceErrorExt) o; - - if (type != that.type) return false; - return description.equals(that.description); - } - - @Override - public int hashCode() { - int result = type; - result = 31 * result + description.hashCode(); - return result; - } - - @Override - public String toString() { - return "WebResourceErrorExt{" + - "type=" + type + - ", description='" + description + '\'' + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebResourceRequestExt.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebResourceRequestExt.java deleted file mode 100644 index b33d807295..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebResourceRequestExt.java +++ /dev/null @@ -1,146 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.os.Build; -import android.webkit.WebResourceRequest; - -import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; -import androidx.webkit.WebResourceRequestCompat; -import androidx.webkit.WebViewFeature; - -import java.util.HashMap; -import java.util.Map; - -public class WebResourceRequestExt { - @NonNull - private String url; - private Map headers; - private boolean isRedirect; - private boolean hasGesture; - private boolean isForMainFrame; - private String method; - - public WebResourceRequestExt(@NonNull String url, Map headers, boolean isRedirect, boolean hasGesture, boolean isForMainFrame, String method) { - this.url = url; - this.headers = headers; - this.isRedirect = isRedirect; - this.hasGesture = hasGesture; - this.isForMainFrame = isForMainFrame; - this.method = method; - } - - @RequiresApi(Build.VERSION_CODES.LOLLIPOP) - static public WebResourceRequestExt fromWebResourceRequest(@NonNull WebResourceRequest request) { - boolean isRedirect = false; - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT)) { - isRedirect = WebResourceRequestCompat.isRedirect(request); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - isRedirect = request.isRedirect(); - } - return new WebResourceRequestExt(request.getUrl().toString(), - request.getRequestHeaders(), - isRedirect, - request.hasGesture(), - request.isForMainFrame(), - request.getMethod() - ); - } - - public Map toMap() { - Map webResourceRequestMap = new HashMap<>(); - webResourceRequestMap.put("url", url); - webResourceRequestMap.put("headers", headers); - webResourceRequestMap.put("isRedirect", isRedirect); - webResourceRequestMap.put("hasGesture", hasGesture); - webResourceRequestMap.put("isForMainFrame", isForMainFrame); - webResourceRequestMap.put("method", method); - return webResourceRequestMap; - } - - @NonNull - public String getUrl() { - return url; - } - - public void setUrl(@NonNull String url) { - this.url = url; - } - - public Map getHeaders() { - return headers; - } - - public void setHeaders(Map headers) { - this.headers = headers; - } - - public boolean isRedirect() { - return isRedirect; - } - - public void setRedirect(boolean redirect) { - isRedirect = redirect; - } - - public boolean isHasGesture() { - return hasGesture; - } - - public void setHasGesture(boolean hasGesture) { - this.hasGesture = hasGesture; - } - - public boolean isForMainFrame() { - return isForMainFrame; - } - - public void setForMainFrame(boolean forMainFrame) { - isForMainFrame = forMainFrame; - } - - public String getMethod() { - return method; - } - - public void setMethod(String method) { - this.method = method; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - WebResourceRequestExt that = (WebResourceRequestExt) o; - - if (isRedirect != that.isRedirect) return false; - if (hasGesture != that.hasGesture) return false; - if (isForMainFrame != that.isForMainFrame) return false; - if (!url.equals(that.url)) return false; - if (headers != null ? !headers.equals(that.headers) : that.headers != null) return false; - return method != null ? method.equals(that.method) : that.method == null; - } - - @Override - public int hashCode() { - int result = url.hashCode(); - result = 31 * result + (headers != null ? headers.hashCode() : 0); - result = 31 * result + (isRedirect ? 1 : 0); - result = 31 * result + (hasGesture ? 1 : 0); - result = 31 * result + (isForMainFrame ? 1 : 0); - result = 31 * result + (method != null ? method.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "WebResourceRequestExt{" + - "url=" + url + - ", headers=" + headers + - ", isRedirect=" + isRedirect + - ", hasGesture=" + hasGesture + - ", isForMainFrame=" + isForMainFrame + - ", method='" + method + '\'' + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebResourceResponseExt.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebResourceResponseExt.java deleted file mode 100644 index 824ccc0f57..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebResourceResponseExt.java +++ /dev/null @@ -1,177 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.os.Build; -import android.webkit.WebResourceResponse; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.Util; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -public class WebResourceResponseExt { - @Nullable - private String contentType; - @Nullable - private String contentEncoding; - @Nullable - private Integer statusCode; - @Nullable - private String reasonPhrase; - @Nullable - private Map headers; - @Nullable - private byte[] data; - - public WebResourceResponseExt(@Nullable String contentType, @Nullable String contentEncoding, @Nullable Integer statusCode, - @Nullable String reasonPhrase, @Nullable Map headers, @Nullable byte[] data) { - this.contentType = contentType; - this.contentEncoding = contentEncoding; - this.statusCode = statusCode; - this.reasonPhrase = reasonPhrase; - this.headers = headers; - this.data = data; - } - - static public WebResourceResponseExt fromWebResourceResponse(@NonNull WebResourceResponse response) { - Integer statusCode = null; - String reasonPhrase = null; - Map headers = null; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - statusCode = response.getStatusCode(); - reasonPhrase = response.getReasonPhrase(); - headers = response.getResponseHeaders(); - } - return new WebResourceResponseExt(response.getMimeType(), - response.getEncoding(), - statusCode, - reasonPhrase, - headers, - Util.readAllBytes(response.getData()) - ); - } - - @Nullable - public static WebResourceResponseExt fromMap(@Nullable Map map) { - if (map == null) { - return null; - } - String contentType = (String) map.get("contentType"); - String contentEncoding = (String) map.get("contentEncoding"); - Integer statusCode = (Integer) map.get("statusCode"); - String reasonPhrase = (String) map.get("reasonPhrase"); - Map headers = (Map) map.get("headers"); - byte[] data = (byte[]) map.get("data"); - return new WebResourceResponseExt(contentType, contentEncoding, statusCode, reasonPhrase, headers, data); - } - - public Map toMap() { - Map webResourceResponseMap = new HashMap<>(); - webResourceResponseMap.put("contentType", contentType); - webResourceResponseMap.put("contentEncoding", contentEncoding); - webResourceResponseMap.put("statusCode", statusCode); - webResourceResponseMap.put("reasonPhrase", reasonPhrase); - webResourceResponseMap.put("headers", headers); - webResourceResponseMap.put("data", data); - return webResourceResponseMap; - } - - @Nullable - public String getContentType() { - return contentType; - } - - public void setContentType(@Nullable String contentType) { - this.contentType = contentType; - } - - @Nullable - public String getContentEncoding() { - return contentEncoding; - } - - public void setContentEncoding(@Nullable String contentEncoding) { - this.contentEncoding = contentEncoding; - } - - @Nullable - public Integer getStatusCode() { - return statusCode; - } - - public void setStatusCode(@Nullable Integer statusCode) { - this.statusCode = statusCode; - } - - @Nullable - public String getReasonPhrase() { - return reasonPhrase; - } - - public void setReasonPhrase(@Nullable String reasonPhrase) { - this.reasonPhrase = reasonPhrase; - } - - @Nullable - public Map getHeaders() { - return headers; - } - - public void setHeaders(@Nullable Map headers) { - this.headers = headers; - } - - @Nullable - public byte[] getData() { - return data; - } - - public void setData(@Nullable byte[] data) { - this.data = data; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - WebResourceResponseExt that = (WebResourceResponseExt) o; - - if (contentType != null ? !contentType.equals(that.contentType) : that.contentType != null) - return false; - if (contentEncoding != null ? !contentEncoding.equals(that.contentEncoding) : that.contentEncoding != null) - return false; - if (statusCode != null ? !statusCode.equals(that.statusCode) : that.statusCode != null) - return false; - if (reasonPhrase != null ? !reasonPhrase.equals(that.reasonPhrase) : that.reasonPhrase != null) - return false; - if (headers != null ? !headers.equals(that.headers) : that.headers != null) return false; - return Arrays.equals(data, that.data); - } - - @Override - public int hashCode() { - int result = contentType != null ? contentType.hashCode() : 0; - result = 31 * result + (contentEncoding != null ? contentEncoding.hashCode() : 0); - result = 31 * result + (statusCode != null ? statusCode.hashCode() : 0); - result = 31 * result + (reasonPhrase != null ? reasonPhrase.hashCode() : 0); - result = 31 * result + (headers != null ? headers.hashCode() : 0); - result = 31 * result + Arrays.hashCode(data); - return result; - } - - @Override - public String toString() { - return "WebResourceResponseExt{" + - "contentType='" + contentType + '\'' + - ", contentEncoding='" + contentEncoding + '\'' + - ", statusCode=" + statusCode + - ", reasonPhrase='" + reasonPhrase + '\'' + - ", headers=" + headers + - ", data=" + Arrays.toString(data) + - '}'; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebViewAssetLoaderExt.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebViewAssetLoaderExt.java deleted file mode 100644 index 0a0c747eb3..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebViewAssetLoaderExt.java +++ /dev/null @@ -1,209 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.types; - -import android.content.Context; -import android.os.Build; -import android.util.Log; -import android.webkit.WebResourceResponse; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.WebViewAssetLoader; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.Util; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.flutter.plugin.common.MethodChannel; - -public class WebViewAssetLoaderExt implements Disposable { - @Nullable - public WebViewAssetLoader loader; - @NonNull - public List customPathHandlers; - - public WebViewAssetLoaderExt(@Nullable WebViewAssetLoader loader, @NonNull List customPathHandlers) { - this.loader = loader; - this.customPathHandlers = customPathHandlers; - } - - @Nullable - public static WebViewAssetLoaderExt fromMap(@Nullable Map map, @NonNull InAppWebViewFlutterPlugin plugin, @NonNull Context context) { - if (map == null) { - return null; - } - WebViewAssetLoader.Builder builder = new WebViewAssetLoader.Builder(); - String domain = (String) map.get("domain"); - Boolean httpAllowed = (Boolean) map.get("httpAllowed"); - List> pathHandlers = (List>) map.get("pathHandlers"); - List customPathHandlers = new ArrayList<>(); - if (domain != null && !domain.isEmpty()) { - builder.setDomain(domain); - } - if (httpAllowed != null) { - builder.setHttpAllowed(httpAllowed); - } - if (pathHandlers != null) { - for (Map pathHandler : pathHandlers) { - String type = (String) pathHandler.get("type"); - String path = (String) pathHandler.get("path"); - if (type == null || path == null) { - continue; - } - switch (type) { - case "AssetsPathHandler": - WebViewAssetLoader.AssetsPathHandler assetsPathHandler = - new WebViewAssetLoader.AssetsPathHandler(context); - builder.addPathHandler(path, assetsPathHandler); - break; - case "InternalStoragePathHandler": - String directory = (String) pathHandler.get("directory"); - if (directory == null) { - continue; - } - File dir = new File(directory); - WebViewAssetLoader.InternalStoragePathHandler internalStoragePathHandler = - new WebViewAssetLoader.InternalStoragePathHandler(context, dir); - builder.addPathHandler(path, internalStoragePathHandler); - break; - case "ResourcesPathHandler": - WebViewAssetLoader.ResourcesPathHandler resourcesPathHandler = new WebViewAssetLoader.ResourcesPathHandler(context); - builder.addPathHandler(path, resourcesPathHandler); - break; - default: - String id = (String) pathHandler.get("id"); - if (id == null) { - continue; - } - PathHandlerExt customPathHandler = new PathHandlerExt(id, plugin); - builder.addPathHandler(path, customPathHandler); - customPathHandlers.add(customPathHandler); - break; - } - } - } - return new WebViewAssetLoaderExt(builder.build(), customPathHandlers); - } - - @Override - public void dispose() { - for (PathHandlerExt pathHandler : customPathHandlers) { - pathHandler.dispose(); - } - customPathHandlers.clear(); - } - - public static class PathHandlerExt implements WebViewAssetLoader.PathHandler, Disposable { - - protected static final String LOG_TAG = "PathHandlerExt"; - public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_custompathhandler_"; - - @NonNull - public String id; - @Nullable - public PathHandlerExtChannelDelegate channelDelegate; - - public PathHandlerExt(@NonNull String id, @NonNull InAppWebViewFlutterPlugin plugin) { - this.id = id; - final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id); - this.channelDelegate = new PathHandlerExtChannelDelegate(this, channel); - } - - @Nullable - @Override - public WebResourceResponse handle(@NonNull String path) { - if (channelDelegate != null) { - WebResourceResponseExt response = null; - - try { - response = channelDelegate.handle(path); - } catch (InterruptedException e) { - Log.e(LOG_TAG, "", e); - return null; - } - - if (response != null) { - String contentType = response.getContentType(); - String contentEncoding = response.getContentEncoding(); - byte[] data = response.getData(); - Map responseHeaders = response.getHeaders(); - Integer statusCode = response.getStatusCode(); - String reasonPhrase = response.getReasonPhrase(); - - ByteArrayInputStream inputStream = (data != null) ? new ByteArrayInputStream(data) : null; - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && statusCode != null && reasonPhrase != null) { - return new WebResourceResponse(contentType, contentEncoding, statusCode, reasonPhrase, responseHeaders, inputStream); - } else { - return new WebResourceResponse(contentType, contentEncoding, inputStream); - } - } - } - return null; - } - - @Override - public void dispose() { - if (channelDelegate != null) { - channelDelegate.dispose(); - channelDelegate = null; - } - } - } - - public static class PathHandlerExtChannelDelegate extends ChannelDelegateImpl { - - @Nullable - private PathHandlerExt pathHandler; - - public PathHandlerExtChannelDelegate(@NonNull PathHandlerExt pathHandler, @NonNull MethodChannel channel) { - super(channel); - this.pathHandler = pathHandler; - } - - public static class HandleCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public WebResourceResponseExt decodeResult(@Nullable Object obj) { - return WebResourceResponseExt.fromMap((Map) obj); - } - } - - public void handle(String path, @NonNull HandleCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("path", path); - channel.invokeMethod("handle", obj, callback); - } - - public static class SyncHandleCallback extends SyncBaseCallbackResultImpl { - @Nullable - @Override - public WebResourceResponseExt decodeResult(@Nullable Object obj) { - return (new HandleCallback()).decodeResult(obj); - } - } - - @Nullable - public WebResourceResponseExt handle(String path) throws InterruptedException { - MethodChannel channel = getChannel(); - if (channel == null) return null; - final SyncHandleCallback callback = new SyncHandleCallback(); - Map obj = new HashMap<>(); - obj.put("path", path); - return Util.invokeMethodAndWaitResult(channel, "handle", obj, callback); - } - - @Override - public void dispose() { - super.dispose(); - pathHandler = null; - } - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/ContextMenuSettings.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/ContextMenuSettings.java deleted file mode 100644 index fb0f194654..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/ContextMenuSettings.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview; - -import androidx.annotation.NonNull; - -import com.pichillilorenzo.flutter_inappwebview_android.ISettings; - -import java.util.HashMap; -import java.util.Map; - -public class ContextMenuSettings implements ISettings { - public static final String LOG_TAG = "ContextMenuOptions"; - - public Boolean hideDefaultSystemContextMenuItems = false; - - @NonNull - @Override - public ContextMenuSettings parse(@NonNull Map options) { - for (Map.Entry pair : options.entrySet()) { - String key = pair.getKey(); - Object value = pair.getValue(); - if (value == null) { - continue; - } - - switch (key) { - case "hideDefaultSystemContextMenuItems": - hideDefaultSystemContextMenuItems = (Boolean) value; - break; - } - } - - return this; - } - - @NonNull - public Map toMap() { - Map options = new HashMap<>(); - options.put("hideDefaultSystemContextMenuItems", hideDefaultSystemContextMenuItems); - return options; - } - - @NonNull - @Override - public Map getRealSettings(@NonNull Object obj) { - Map realOptions = toMap(); - return realOptions; - } - -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/FlutterWebViewFactory.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/FlutterWebViewFactory.java deleted file mode 100755 index 6acd91e470..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/FlutterWebViewFactory.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview; - -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.headless_in_app_webview.HeadlessInAppWebView; -import com.pichillilorenzo.flutter_inappwebview_android.headless_in_app_webview.HeadlessInAppWebViewManager; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.FlutterWebView; - -import java.util.HashMap; - -import io.flutter.plugin.common.StandardMessageCodec; -import io.flutter.plugin.platform.PlatformView; -import io.flutter.plugin.platform.PlatformViewFactory; - -public class FlutterWebViewFactory extends PlatformViewFactory { - public static final String VIEW_TYPE_ID = "com.pichillilorenzo/flutter_inappwebview"; - private final InAppWebViewFlutterPlugin plugin; - - public FlutterWebViewFactory(final InAppWebViewFlutterPlugin plugin) { - super(StandardMessageCodec.INSTANCE); - this.plugin = plugin; - } - - @Override - public PlatformView create(Context context, int id, Object args) { - HashMap params = (HashMap) args; - FlutterWebView flutterWebView = null; - Object viewId = id; - - String keepAliveId = (String) params.get("keepAliveId"); - String headlessWebViewId = (String) params.get("headlessWebViewId"); - - HeadlessInAppWebViewManager headlessInAppWebViewManager = plugin.headlessInAppWebViewManager; - if (headlessWebViewId != null && headlessInAppWebViewManager != null) { - HeadlessInAppWebView headlessInAppWebView = headlessInAppWebViewManager.webViews.get(headlessWebViewId); - if (headlessInAppWebView != null) { - flutterWebView = headlessInAppWebView.disposeAndGetFlutterWebView(); - if (flutterWebView != null) { - flutterWebView.keepAliveId = keepAliveId; - } - } - } - - InAppWebViewManager inAppWebViewManager = plugin.inAppWebViewManager; - if (keepAliveId != null && flutterWebView == null && inAppWebViewManager != null) { - flutterWebView = inAppWebViewManager.keepAliveWebViews.get(keepAliveId); - if (flutterWebView != null) { - // be sure to remove the view from the previous parent. - View view = flutterWebView.getView(); - if (view != null) { - ViewGroup parent = (ViewGroup) view.getParent(); - if (parent != null) { - parent.removeView(view); - } - } - } - } - - boolean shouldMakeInitialLoad = flutterWebView == null; - if (flutterWebView == null) { - if (keepAliveId != null) { - viewId = keepAliveId; - } - flutterWebView = new FlutterWebView(plugin, context, viewId, params); - } - - if (keepAliveId != null && inAppWebViewManager != null) { - inAppWebViewManager.keepAliveWebViews.put(keepAliveId, flutterWebView); - } - - if (shouldMakeInitialLoad) { - flutterWebView.makeInitialLoad(params); - } - - return flutterWebView; - } -} - diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewInterface.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewInterface.java deleted file mode 100644 index 4c533c0c2a..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewInterface.java +++ /dev/null @@ -1,125 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview; - -import android.content.Context; -import android.net.Uri; -import android.net.http.SslCertificate; -import android.os.Looper; -import android.webkit.ValueCallback; -import android.webkit.WebMessage; -import android.webkit.WebView; - -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.in_app_browser.InAppBrowserDelegate; -import com.pichillilorenzo.flutter_inappwebview_android.print_job.PrintJobSettings; -import com.pichillilorenzo.flutter_inappwebview_android.types.ContentWorld; -import com.pichillilorenzo.flutter_inappwebview_android.types.HitTestResult; -import com.pichillilorenzo.flutter_inappwebview_android.types.URLRequest; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserContentController; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.InAppWebViewSettings; -import com.pichillilorenzo.flutter_inappwebview_android.webview.web_message.WebMessageChannel; -import com.pichillilorenzo.flutter_inappwebview_android.webview.web_message.WebMessageListener; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import io.flutter.plugin.common.MethodChannel; - -public interface InAppWebViewInterface { - Context getContext(); - String getUrl(); - String getTitle(); - int getProgress(); - void loadUrl(URLRequest urlRequest); - void postUrl(String url, byte[] postData); - void loadDataWithBaseURL(String baseUrl, String data, - String mimeType, String encoding, String historyUrl); - void loadFile(String assetFilePath) throws IOException; - void evaluateJavascript(String source, ContentWorld contentWorld, ValueCallback resultCallback); - void injectJavascriptFileFromUrl(String urlFile, Map scriptHtmlTagAttributes); - void injectCSSCode(String source); - void injectCSSFileFromUrl(String urlFile, Map cssLinkHtmlTagAttributes); - void reload(); - void goBack(); - boolean canGoBack(); - void goForward(); - boolean canGoForward(); - void goBackOrForward(int steps); - boolean canGoBackOrForward(int steps); - void stopLoading(); - boolean isLoading(); - void takeScreenshot(Map screenshotConfiguration, MethodChannel.Result result); - void setSettings(InAppWebViewSettings newSettings, HashMap newSettingsMap); - InAppWebViewSettings getCustomSettings(); - Map getCustomSettingsMap(); - HashMap getCopyBackForwardList(); - void clearAllCache(); - void clearSslPreferences(); - void findAllAsync(String find); - void findNext(boolean forward); - void clearMatches(); - void scrollTo(Integer x, Integer y, Boolean animated); - void scrollBy(Integer x, Integer y, Boolean animated); - void onPause(); - void onResume(); - void pauseTimers(); - void resumeTimers(); - @Nullable - String printCurrentPage(@Nullable PrintJobSettings settings); - int getContentHeight(); - void getContentHeight(ValueCallback callback); - void getContentWidth(ValueCallback callback); - void zoomBy(float zoomFactor); - String getOriginalUrl(); - void getSelectedText(ValueCallback callback); - WebView.HitTestResult getHitTestResult(); - void getHitTestResult(ValueCallback callback); - boolean pageDown(boolean bottom); - boolean pageUp(boolean top); - void saveWebArchive(String basename, boolean autoname, ValueCallback callback); - boolean zoomIn(); - boolean zoomOut(); - void clearFocus(); - Map requestFocusNodeHref(); - Map requestImageRef(); - int getScrollX(); - int getScrollY(); - SslCertificate getCertificate(); - void clearHistory(); - void callAsyncJavaScript(String functionBody, Map arguments, ContentWorld contentWorld, ValueCallback resultCallback); - void isSecureContext(final ValueCallback resultCallback); - WebMessageChannel createCompatWebMessageChannel(); - WebMessageChannel createWebMessageChannel(ValueCallback callback); - void postWebMessage(WebMessage message, Uri targetOrigin); - void postWebMessage(com.pichillilorenzo.flutter_inappwebview_android.types.WebMessage message, Uri targetOrigin, ValueCallback callback) throws Exception; - void addWebMessageListener(WebMessageListener webMessageListener) throws Exception; - boolean canScrollVertically(); - boolean canScrollHorizontally(); - float getZoomScale(); - void getZoomScale(ValueCallback callback); - Map getContextMenu(); - void setContextMenu(Map contextMenu); - InAppWebViewFlutterPlugin getPlugin(); - void setPlugin(InAppWebViewFlutterPlugin plugin); - InAppBrowserDelegate getInAppBrowserDelegate(); - void setInAppBrowserDelegate(InAppBrowserDelegate inAppBrowserDelegate); - UserContentController getUserContentController(); - void setUserContentController(UserContentController userContentController); - Map getWebMessageChannels(); - void setWebMessageChannels(Map webMessageChannels); - void disposeWebMessageChannels(); - void disposeWebMessageListeners(); - Looper getWebViewLooper(); - boolean isInFullscreen(); - void setInFullscreen(boolean inFullscreen); - @Nullable - WebViewChannelDelegate getChannelDelegate(); - void setChannelDelegate(@Nullable WebViewChannelDelegate eventWebViewChannelDelegate); - void showInputMethod(); - void hideInputMethod(); - @Nullable - byte[] saveState(); - boolean restoreState(byte[] state); -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java deleted file mode 100755 index 6b909df396..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview; - -import android.content.Context; -import android.content.pm.PackageInfo; -import android.os.Build; -import android.os.Message; -import android.view.View; -import android.view.ViewGroup; -import android.webkit.ValueCallback; -import android.webkit.WebSettings; -import android.webkit.WebView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.WebViewCompat; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.JavaScriptBridgeJS; -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.FlutterWebView; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class InAppWebViewManager extends ChannelDelegateImpl { - protected static final String LOG_TAG = "InAppWebViewManager"; - public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_manager"; - - @Nullable - public InAppWebViewFlutterPlugin plugin; - - public final Map keepAliveWebViews = new HashMap<>(); - - public final Map windowWebViewMessages = new HashMap<>(); - public int windowAutoincrementId = 0; - - public InAppWebViewManager(final InAppWebViewFlutterPlugin plugin) { - super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME)); - this.plugin = plugin; - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) { - switch (call.method) { - case "getDefaultUserAgent": - if (plugin != null) { - result.success(WebSettings.getDefaultUserAgent(plugin.applicationContext)); - } else { - result.success(null); - } - break; - case "clearClientCertPreferences": - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - WebView.clearClientCertPreferences(new Runnable() { - @Override - public void run() { - result.success(true); - } - }); - } else { - result.success(false); - } - break; - case "getSafeBrowsingPrivacyPolicyUrl": - if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL)) { - result.success(WebViewCompat.getSafeBrowsingPrivacyPolicyUrl().toString()); - } else - result.success(null); - break; - case "setSafeBrowsingAllowlist": - if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_ALLOWLIST)) { - Set hosts = new HashSet<>((List) call.argument("hosts")); - WebViewCompat.setSafeBrowsingAllowlist(hosts, new ValueCallback() { - @Override - public void onReceiveValue(Boolean value) { - result.success(value); - } - }); - } - else if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_WHITELIST)) { - List hosts = (List) call.argument("hosts"); - WebViewCompat.setSafeBrowsingWhitelist(hosts, new ValueCallback() { - @Override - public void onReceiveValue(Boolean value) { - result.success(value); - } - }); - } else - result.success(false); - break; - case "getCurrentWebViewPackage": - { - Context context = null; - if (plugin != null) { - context = plugin.activity; - if (context == null) { - context = plugin.applicationContext; - } - } - PackageInfo packageInfo = context != null ? WebViewCompat.getCurrentWebViewPackage(context) : null; - result.success(packageInfo != null ? convertWebViewPackageToMap(packageInfo) : null); - } - break; - case "setWebContentsDebuggingEnabled": - { - boolean debuggingEnabled = (boolean) call.argument("debuggingEnabled"); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - WebView.setWebContentsDebuggingEnabled(debuggingEnabled); - } - } - result.success(true); - break; - case "getVariationsHeader": - if (WebViewFeature.isFeatureSupported(WebViewFeature.GET_VARIATIONS_HEADER)) { - result.success(WebViewCompat.getVariationsHeader()); - } - else { - result.success(null); - } - break; - case "isMultiProcessEnabled": - if (WebViewFeature.isFeatureSupported(WebViewFeature.MULTI_PROCESS)) { - result.success(WebViewCompat.isMultiProcessEnabled()); - } - else { - result.success(false); - } - break; - case "disableWebView": - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - WebView.disableWebView(); - } - result.success(true); - break; - case "disposeKeepAlive": - final String keepAliveId = (String) call.argument("keepAliveId"); - if (keepAliveId != null) { - disposeKeepAlive(keepAliveId); - } - result.success(true); - break; - case "clearAllCache": - { - Context context = null; - if (plugin != null) { - context = plugin.activity; - if (context == null) { - context = plugin.applicationContext; - } - if (context != null) { - boolean includeDiskFiles = (boolean) call.argument("includeDiskFiles"); - clearAllCache(context, includeDiskFiles); - } - } - } - result.success(true); - break; - case "enableSlowWholeDocumentDraw": - { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - WebView.enableSlowWholeDocumentDraw(); - } - } - result.success(true); - break; - case "setJavaScriptBridgeName": - JavaScriptBridgeJS.set_JAVASCRIPT_BRIDGE_NAME((String) call.argument("bridgeName")); - result.success(true); - break; - case "getJavaScriptBridgeName": - { - result.success(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()); - } - break; - default: - result.notImplemented(); - } - } - - @NonNull - public Map convertWebViewPackageToMap(@NonNull PackageInfo webViewPackageInfo) { - HashMap webViewPackageInfoMap = new HashMap<>(); - - webViewPackageInfoMap.put("versionName", webViewPackageInfo.versionName); - webViewPackageInfoMap.put("packageName", webViewPackageInfo.packageName); - - return webViewPackageInfoMap; - } - - public void disposeKeepAlive(@NonNull String keepAliveId) { - FlutterWebView flutterWebView = keepAliveWebViews.get(keepAliveId); - if (flutterWebView != null) { - flutterWebView.keepAliveId = null; - // be sure to remove the view from the previous parent. - View view = flutterWebView.getView(); - if (view != null) { - ViewGroup parent = (ViewGroup) view.getParent(); - if (parent != null) { - parent.removeView(view); - } - } - flutterWebView.dispose(); - } - if (keepAliveWebViews.containsKey(keepAliveId)) { - keepAliveWebViews.put(keepAliveId, null); - } - } - - public void clearAllCache(@NonNull Context context, boolean includeDiskFiles) { - WebView tempWebView = new WebView(context); - tempWebView.clearCache(includeDiskFiles); - tempWebView.destroy(); - } - - @Override - public void dispose() { - super.dispose(); - Collection flutterWebViews = keepAliveWebViews.values(); - for (FlutterWebView flutterWebView : flutterWebViews) { - if (flutterWebView != null) { - String keepAliveId = flutterWebView.keepAliveId; - if (keepAliveId != null) { - disposeKeepAlive(keepAliveId); - } - } - } - keepAliveWebViews.clear(); - windowWebViewMessages.clear(); - plugin = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/JavaScriptBridgeInterface.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/JavaScriptBridgeInterface.java deleted file mode 100755 index d24f89d628..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/JavaScriptBridgeInterface.java +++ /dev/null @@ -1,238 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview; - -import android.os.Build; -import android.os.Handler; -import android.util.Log; -import android.webkit.JavascriptInterface; -import android.webkit.ValueCallback; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.JavaScriptBridgeJS; -import com.pichillilorenzo.flutter_inappwebview_android.print_job.PrintJobController; -import com.pichillilorenzo.flutter_inappwebview_android.print_job.PrintJobSettings; -import com.pichillilorenzo.flutter_inappwebview_android.types.JavaScriptHandlerFunctionData; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.InAppWebView; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.regex.Pattern; - -public class JavaScriptBridgeInterface { - private static final String LOG_TAG = "JSBridgeInterface"; - private InAppWebView inAppWebView; - @NonNull - private final String expectedBridgeSecret; - - public JavaScriptBridgeInterface(InAppWebView inAppWebView, @NonNull String expectedBridgeSecret) { - this.inAppWebView = inAppWebView; - this.expectedBridgeSecret = expectedBridgeSecret; - } - - @JavascriptInterface - public void _hideContextMenu() { - if (inAppWebView == null) { - return; - } - - final Handler handler = new Handler(inAppWebView.getWebViewLooper()); - handler.post(new Runnable() { - @Override - public void run() { - if (inAppWebView != null && inAppWebView.floatingContextMenu != null) { - inAppWebView.hideContextMenu(); - } - } - }); - } - - @JavascriptInterface - public void _callHandler(final String jsonStringifiedData) { - if (inAppWebView == null) { - return; - } - - JSONObject data; - try { - data = new JSONObject(jsonStringifiedData); - } catch (Exception e) { - e.printStackTrace(); - Log.e(LOG_TAG, "Cannot convert jsonStringifiedData parameter of _callHandler method to a valid JSONObject"); - return; - } - - if (!data.has("handlerName") || data.isNull("handlerName")) { - Log.d(LOG_TAG, "handlerName is null or undefined"); - return; - } - - final String handlerName = data.optString("handlerName"); - final String bridgeSecret = data.optString("_bridgeSecret"); - final Integer _callHandlerID = data.optInt("_callHandlerID"); - final String origin = data.optString("origin"); - final String requestUrl = data.optString("requestUrl"); - final Boolean isMainFrame = data.optBoolean("isMainFrame"); - final String args = data.optString("args"); - - if (!expectedBridgeSecret.equals(bridgeSecret)) { - Log.e(LOG_TAG, "Bridge access attempt with wrong secret token, possibly from malicious code from origin: " + origin); - return; - } - - boolean isOriginAllowed = false; - if (inAppWebView.customSettings.javaScriptHandlersOriginAllowList != null) { - for (Pattern allowedOrigin : inAppWebView.customSettings.javaScriptHandlersOriginAllowList) { - if (allowedOrigin.matcher(origin).matches()) { - isOriginAllowed = true; - break; - } - } - } else { - // origin is by default allowed if the allow list is null - isOriginAllowed = true; - } - if (!isOriginAllowed) { - Log.e(LOG_TAG, "Bridge access attempt from an origin not allowed: " + origin); - return; - } - - if (inAppWebView.customSettings.javaScriptHandlersForMainFrameOnly && !isMainFrame) { - Log.e(LOG_TAG, "Bridge access attempt from a sub-frame origin: " + origin); - return; - } - - // java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread. - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/98 - final Handler handler = new Handler(inAppWebView.getWebViewLooper()); - handler.post(new Runnable() { - @Override - public void run() { - if (inAppWebView == null) { - // The webview has already been disposed, ignore. - return; - } - - boolean isInternalHandler = true; - switch (handlerName) { - case "onPrintRequest": - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - PrintJobSettings settings = new PrintJobSettings(); - settings.handledByClient = true; - final String printJobId = inAppWebView.printCurrentPage(settings); - if (inAppWebView != null && inAppWebView.channelDelegate != null) { - inAppWebView.channelDelegate.onPrintRequest(inAppWebView.getUrl(), printJobId, new WebViewChannelDelegate.PrintRequestCallback() { - @Override - public boolean nonNullSuccess(@NonNull Boolean handledByClient) { - return !handledByClient; - } - - @Override - public void defaultBehaviour(@Nullable Boolean handledByClient) { - if (inAppWebView != null && inAppWebView.plugin != null && inAppWebView.plugin.printJobManager != null) { - PrintJobController printJobController = inAppWebView.plugin.printJobManager.jobs.get(printJobId); - if (printJobController != null) { - printJobController.disposeNoCancel(); - } - } - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }); - } - } - break; - case "callAsyncJavaScript": - try { - JSONArray arguments = new JSONArray(args); - JSONObject jsonObject = arguments.getJSONObject(0); - String resultUuid = jsonObject.getString("resultUuid"); - ValueCallback callAsyncJavaScriptCallback = inAppWebView.callAsyncJavaScriptCallbacks.get(resultUuid); - if (callAsyncJavaScriptCallback != null) { - callAsyncJavaScriptCallback.onReceiveValue(jsonObject.toString()); - inAppWebView.callAsyncJavaScriptCallbacks.remove(resultUuid); - } - } catch (JSONException e) { - Log.e(LOG_TAG, "", e); - } - break; - case "evaluateJavaScriptWithContentWorld": - try { - JSONArray arguments = new JSONArray(args); - JSONObject jsonObject = arguments.getJSONObject(0); - String resultUuid = jsonObject.getString("resultUuid"); - ValueCallback evaluateJavaScriptCallback = inAppWebView.evaluateJavaScriptContentWorldCallbacks.get(resultUuid); - if (evaluateJavaScriptCallback != null) { - evaluateJavaScriptCallback.onReceiveValue(jsonObject.has("value") ? jsonObject.get("value").toString() : "null"); - inAppWebView.evaluateJavaScriptContentWorldCallbacks.remove(resultUuid); - } - } catch (JSONException e) { - Log.e(LOG_TAG, "", e); - } - break; - default: - isInternalHandler = false; - break; - } - - if (isInternalHandler) { - if (inAppWebView != null) { - String sourceCode = "if (window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "[" + _callHandlerID + "] != null) { " + - "window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "[" + _callHandlerID + "].resolve(); " + - "delete window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "[" + _callHandlerID + "]; " + - "}"; - inAppWebView.evaluateJavascript(sourceCode, (ValueCallback) null); - } - return; - } - - - if (inAppWebView.channelDelegate != null) { - JavaScriptHandlerFunctionData data = new JavaScriptHandlerFunctionData(origin, requestUrl, isMainFrame, args); - // invoke flutter javascript handler and send back flutter data as a JSON Object to javascript - inAppWebView.channelDelegate.onCallJsHandler(handlerName, data, new WebViewChannelDelegate.CallJsHandlerCallback() { - @Override - public void defaultBehaviour(@Nullable Object json) { - if (inAppWebView == null) { - // The webview has already been disposed, ignore. - return; - } - String sourceCode = "if (window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "[" + _callHandlerID + "] != null) { " + - "window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "[" + _callHandlerID + "].resolve(" + json + "); " + - "delete window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "[" + _callHandlerID + "]; " + - "}"; - inAppWebView.evaluateJavascript(sourceCode, (ValueCallback) null); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - String message = errorCode + ((errorMessage != null) ? ", " + errorMessage : ""); - Log.e(LOG_TAG, message); - - if (inAppWebView == null) { - // The webview has already been disposed, ignore. - return; - } - - String sourceCode = "if (window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "[" + _callHandlerID + "] != null) { " + - "window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "[" + _callHandlerID + "].reject(new Error(" + JSONObject.quote(message) + ")); " + - "delete window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "[" + _callHandlerID + "]; " + - "}"; - inAppWebView.evaluateJavascript(sourceCode, (ValueCallback) null); - } - }); - } - } - }); - } - - public void dispose() { - inAppWebView = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/PlatformWebView.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/PlatformWebView.java deleted file mode 100644 index 93ae83fa5a..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/PlatformWebView.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview; - -import java.util.HashMap; - -import io.flutter.plugin.platform.PlatformView; - -public interface PlatformWebView extends PlatformView { - void makeInitialLoad(HashMap params); -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegate.java deleted file mode 100644 index 8bcf63ce60..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegate.java +++ /dev/null @@ -1,1387 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview; - -import android.net.Uri; -import android.os.Build; -import android.webkit.ValueCallback; -import android.webkit.WebView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.WebMessageCompat; -import androidx.webkit.WebMessagePortCompat; -import androidx.webkit.WebViewCompat; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.Util; -import com.pichillilorenzo.flutter_inappwebview_android.find_interaction.FindInteractionChannelDelegate; -import com.pichillilorenzo.flutter_inappwebview_android.in_app_browser.InAppBrowserActivity; -import com.pichillilorenzo.flutter_inappwebview_android.in_app_browser.InAppBrowserSettings; -import com.pichillilorenzo.flutter_inappwebview_android.print_job.PrintJobSettings; -import com.pichillilorenzo.flutter_inappwebview_android.types.BaseCallbackResultImpl; -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; -import com.pichillilorenzo.flutter_inappwebview_android.types.ClientCertChallenge; -import com.pichillilorenzo.flutter_inappwebview_android.types.ClientCertResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.ContentWorld; -import com.pichillilorenzo.flutter_inappwebview_android.types.CreateWindowAction; -import com.pichillilorenzo.flutter_inappwebview_android.types.CustomSchemeResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.DownloadStartRequest; -import com.pichillilorenzo.flutter_inappwebview_android.types.GeolocationPermissionShowPromptResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.HitTestResult; -import com.pichillilorenzo.flutter_inappwebview_android.types.HttpAuthResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.HttpAuthenticationChallenge; -import com.pichillilorenzo.flutter_inappwebview_android.types.InAppWebViewRect; -import com.pichillilorenzo.flutter_inappwebview_android.types.JavaScriptHandlerFunctionData; -import com.pichillilorenzo.flutter_inappwebview_android.types.JsAlertResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.JsBeforeUnloadResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.JsConfirmResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.JsPromptResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.NavigationAction; -import com.pichillilorenzo.flutter_inappwebview_android.types.NavigationActionPolicy; -import com.pichillilorenzo.flutter_inappwebview_android.types.PermissionResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.SafeBrowsingResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.ServerTrustAuthResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.ServerTrustChallenge; -import com.pichillilorenzo.flutter_inappwebview_android.types.ShowFileChooserRequest; -import com.pichillilorenzo.flutter_inappwebview_android.types.ShowFileChooserResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.SslCertificateExt; -import com.pichillilorenzo.flutter_inappwebview_android.types.SyncBaseCallbackResultImpl; -import com.pichillilorenzo.flutter_inappwebview_android.types.URLRequest; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserScript; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebMessageCompatExt; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebMessagePortCompatExt; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebResourceErrorExt; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebResourceRequestExt; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebResourceResponseExt; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.InAppWebView; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.InAppWebViewSettings; -import com.pichillilorenzo.flutter_inappwebview_android.webview.web_message.WebMessageChannel; -import com.pichillilorenzo.flutter_inappwebview_android.webview.web_message.WebMessageListener; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class WebViewChannelDelegate extends ChannelDelegateImpl { - static final String LOG_TAG = "WebViewChannelDelegate"; - - @Nullable - private InAppWebView webView; - - public WebViewChannelDelegate(@NonNull InAppWebView webView, @NonNull MethodChannel channel) { - super(channel); - this.webView = webView; - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) { - WebViewChannelDelegateMethods method = null; - try { - method = WebViewChannelDelegateMethods.valueOf(call.method); - } catch (IllegalArgumentException e) { - result.notImplemented(); - return; - } - switch (method) { - case getUrl: - result.success((webView != null) ? webView.getUrl() : null); - break; - case getTitle: - result.success((webView != null) ? webView.getTitle() : null); - break; - case getProgress: - result.success((webView != null) ? webView.getProgress() : null); - break; - case loadUrl: - if (webView != null) { - Map urlRequest = (Map) call.argument("urlRequest"); - webView.loadUrl(URLRequest.fromMap(urlRequest)); - } - result.success(true); - break; - case postUrl: - if (webView != null) { - String url = (String) call.argument("url"); - byte[] postData = (byte[]) call.argument("postData"); - webView.postUrl(url, postData); - } - result.success(true); - break; - case loadData: - if (webView != null) { - String data = (String) call.argument("data"); - String mimeType = (String) call.argument("mimeType"); - String encoding = (String) call.argument("encoding"); - String baseUrl = (String) call.argument("baseUrl"); - String historyUrl = (String) call.argument("historyUrl"); - webView.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl); - } - result.success(true); - break; - case loadFile: - if (webView != null) { - String assetFilePath = (String) call.argument("assetFilePath"); - try { - webView.loadFile(assetFilePath); - } catch (IOException e) { - e.printStackTrace(); - result.error(LOG_TAG, e.getMessage(), null); - return; - } - } - result.success(true); - break; - case evaluateJavascript: - if (webView != null) { - String source = (String) call.argument("source"); - Map contentWorldMap = (Map) call.argument("contentWorld"); - ContentWorld contentWorld = ContentWorld.fromMap(contentWorldMap); - webView.evaluateJavascript(source, contentWorld, new ValueCallback() { - @Override - public void onReceiveValue(String value) { - result.success(value); - } - }); - } else { - result.success(null); - } - break; - case injectJavascriptFileFromUrl: - if (webView != null) { - String urlFile = (String) call.argument("urlFile"); - Map scriptHtmlTagAttributes = (Map) call.argument("scriptHtmlTagAttributes"); - webView.injectJavascriptFileFromUrl(urlFile, scriptHtmlTagAttributes); - } - result.success(true); - break; - case injectCSSCode: - if (webView != null) { - String source = (String) call.argument("source"); - webView.injectCSSCode(source); - } - result.success(true); - break; - case injectCSSFileFromUrl: - if (webView != null) { - String urlFile = (String) call.argument("urlFile"); - Map cssLinkHtmlTagAttributes = (Map) call.argument("cssLinkHtmlTagAttributes"); - webView.injectCSSFileFromUrl(urlFile, cssLinkHtmlTagAttributes); - } - result.success(true); - break; - case reload: - if (webView != null) - webView.reload(); - result.success(true); - break; - case goBack: - if (webView != null) - webView.goBack(); - result.success(true); - break; - case canGoBack: - result.success((webView != null) && webView.canGoBack()); - break; - case goForward: - if (webView != null) - webView.goForward(); - result.success(true); - break; - case canGoForward: - result.success((webView != null) && webView.canGoForward()); - break; - case goBackOrForward: - if (webView != null) - webView.goBackOrForward((Integer) call.argument("steps")); - result.success(true); - break; - case canGoBackOrForward: - result.success((webView != null) && webView.canGoBackOrForward((Integer) call.argument("steps"))); - break; - case stopLoading: - if (webView != null) - webView.stopLoading(); - result.success(true); - break; - case isLoading: - result.success((webView != null) && webView.isLoading()); - break; - case takeScreenshot: - if (webView != null) { - Map screenshotConfiguration = (Map) call.argument("screenshotConfiguration"); - webView.takeScreenshot(screenshotConfiguration, result); - } else - result.success(null); - break; - case setSettings: - if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) { - InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate(); - InAppBrowserSettings inAppBrowserSettings = new InAppBrowserSettings(); - HashMap inAppBrowserSettingsMap = (HashMap) call.argument("settings"); - inAppBrowserSettings.parse(inAppBrowserSettingsMap); - inAppBrowserActivity.setSettings(inAppBrowserSettings, inAppBrowserSettingsMap); - } else if (webView != null) { - InAppWebViewSettings inAppWebViewSettings = new InAppWebViewSettings(); - HashMap inAppWebViewSettingsMap = (HashMap) call.argument("settings"); - inAppWebViewSettings.parse(inAppWebViewSettingsMap); - webView.setSettings(inAppWebViewSettings, inAppWebViewSettingsMap); - } - result.success(true); - break; - case getSettings: - if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) { - InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate(); - result.success(inAppBrowserActivity.getCustomSettingsMap()); - } else { - result.success((webView != null) ? webView.getCustomSettingsMap() : null); - } - break; - case close: - if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) { - InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate(); - inAppBrowserActivity.close(result); - } else { - result.notImplemented(); - } - break; - case show: - if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) { - InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate(); - inAppBrowserActivity.show(); - result.success(true); - } else { - result.notImplemented(); - } - break; - case hide: - if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) { - InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate(); - inAppBrowserActivity.hide(); - result.success(true); - } else { - result.notImplemented(); - } - break; - case isHidden: - if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) { - InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate(); - result.success(inAppBrowserActivity.isHidden); - } else { - result.notImplemented(); - } - break; - case getCopyBackForwardList: - result.success((webView != null) ? webView.getCopyBackForwardList() : null); - break; - case startSafeBrowsing: - if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) { - WebViewCompat.startSafeBrowsing(webView.getContext(), new ValueCallback() { - @Override - public void onReceiveValue(Boolean success) { - result.success(success); - } - }); - } else { - result.success(false); - } - break; - case clearCache: - if (webView != null) - webView.clearAllCache(); - result.success(true); - break; - case clearSslPreferences: - if (webView != null) - webView.clearSslPreferences(); - result.success(true); - break; - case findAll: - if (webView != null) { - String find = (String) call.argument("find"); - webView.findAllAsync(find); - } - result.success(true); - break; - case findNext: - if (webView != null) { - Boolean forward = (Boolean) call.argument("forward"); - webView.findNext(forward); - } - result.success(true); - break; - case clearMatches: - if (webView != null) { - webView.clearMatches(); - } - result.success(true); - break; - case scrollTo: - if (webView != null) { - Integer x = (Integer) call.argument("x"); - Integer y = (Integer) call.argument("y"); - Boolean animated = (Boolean) call.argument("animated"); - webView.scrollTo(x, y, animated); - } - result.success(true); - break; - case scrollBy: - if (webView != null) { - Integer x = (Integer) call.argument("x"); - Integer y = (Integer) call.argument("y"); - Boolean animated = (Boolean) call.argument("animated"); - webView.scrollBy(x, y, animated); - } - result.success(true); - break; - case pause: - if (webView != null) { - webView.onPause(); - } - result.success(true); - break; - case resume: - if (webView != null) { - webView.onResume(); - } - result.success(true); - break; - case pauseTimers: - if (webView != null) { - webView.pauseTimers(); - } - result.success(true); - break; - case resumeTimers: - if (webView != null) { - webView.resumeTimers(); - } - result.success(true); - break; - case printCurrentPage: - if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - PrintJobSettings settings = new PrintJobSettings(); - Map settingsMap = (Map) call.argument("settings"); - if (settingsMap != null) { - settings.parse(settingsMap); - } - result.success(webView.printCurrentPage(settings)); - } else { - result.success(null); - } - break; - case getContentHeight: - if (webView instanceof InAppWebView) { - result.success(webView.getContentHeight()); - } else { - result.success(null); - } - break; - case getContentWidth: - if (webView instanceof InAppWebView) { - webView.getContentWidth(new ValueCallback() { - @Override - public void onReceiveValue(@Nullable Integer contentWidth) { - result.success(contentWidth); - } - }); - } else { - result.success(null); - } - break; - case zoomBy: - if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - double zoomFactor = (double) call.argument("zoomFactor"); - webView.zoomBy((float) zoomFactor); - } - result.success(true); - break; - case getOriginalUrl: - result.success((webView != null) ? webView.getOriginalUrl() : null); - break; - case getZoomScale: - if (webView instanceof InAppWebView) { - result.success(webView.getZoomScale()); - } else { - result.success(null); - } - break; - case getSelectedText: - if ((webView instanceof InAppWebView && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)) { - webView.getSelectedText(new ValueCallback() { - @Override - public void onReceiveValue(String value) { - result.success(value); - } - }); - } else { - result.success(null); - } - break; - case getHitTestResult: - if (webView instanceof InAppWebView) { - result.success(HitTestResult.fromWebViewHitTestResult(webView.getHitTestResult()).toMap()); - } else { - result.success(null); - } - break; - case pageDown: - if (webView != null) { - boolean bottom = (boolean) call.argument("bottom"); - result.success(webView.pageDown(bottom)); - } else { - result.success(false); - } - break; - case pageUp: - if (webView != null) { - boolean top = (boolean) call.argument("top"); - result.success(webView.pageUp(top)); - } else { - result.success(false); - } - break; - case saveWebArchive: - if (webView != null) { - String filePath = (String) call.argument("filePath"); - boolean autoname = (boolean) call.argument("autoname"); - webView.saveWebArchive(filePath, autoname, new ValueCallback() { - @Override - public void onReceiveValue(String value) { - result.success(value); - } - }); - } else { - result.success(null); - } - break; - case zoomIn: - if (webView != null) { - result.success(webView.zoomIn()); - } else { - result.success(false); - } - break; - case zoomOut: - if (webView != null) { - result.success(webView.zoomOut()); - } else { - result.success(false); - } - break; - case clearFocus: - if (webView != null) { - webView.clearFocus(); - } - result.success(true); - break; - case requestFocus: - if (webView != null) { - boolean resultValue = false; - Integer direction = (Integer) call.argument("direction"); - InAppWebViewRect previouslyFocusedRect = InAppWebViewRect.fromMap((Map) call.argument("previouslyFocusedRect")); - if (direction != null && previouslyFocusedRect != null) { - resultValue = webView.requestFocus(direction, previouslyFocusedRect.toRect()); - } else if (direction != null) { - resultValue = webView.requestFocus(direction); - } else { - resultValue = webView.requestFocus(); - } - result.success(resultValue); - } else { - result.success(false); - } - break; - case setContextMenu: - if (webView != null) { - Map contextMenu = (Map) call.argument("contextMenu"); - webView.setContextMenu(contextMenu); - } - result.success(true); - break; - case requestFocusNodeHref: - if (webView != null) { - result.success(webView.requestFocusNodeHref()); - } else { - result.success(null); - } - break; - case requestImageRef: - if (webView != null) { - result.success(webView.requestImageRef()); - } else { - result.success(null); - } - break; - case getScrollX: - if (webView != null) { - result.success(webView.getScrollX()); - } else { - result.success(null); - } - break; - case getScrollY: - if (webView != null) { - result.success(webView.getScrollY()); - } else { - result.success(null); - } - break; - case getCertificate: - if (webView != null) { - result.success(SslCertificateExt.toMap(webView.getCertificate())); - } else { - result.success(null); - } - break; - case clearHistory: - if (webView != null) { - webView.clearHistory(); - } - result.success(true); - break; - case addUserScript: - if (webView != null && webView.getUserContentController() != null) { - Map userScriptMap = (Map) call.argument("userScript"); - UserScript userScript = UserScript.fromMap(userScriptMap); - result.success(webView.getUserContentController().addUserOnlyScript(userScript)); - } else { - result.success(false); - } - break; - case removeUserScript: - if (webView != null && webView.getUserContentController() != null) { - Integer index = (Integer) call.argument("index"); - Map userScriptMap = (Map) call.argument("userScript"); - UserScript userScript = UserScript.fromMap(userScriptMap); - result.success(webView.getUserContentController().removeUserOnlyScriptAt(index, userScript.getInjectionTime())); - } else { - result.success(false); - } - break; - case removeUserScriptsByGroupName: - if (webView != null && webView.getUserContentController() != null) { - String groupName = (String) call.argument("groupName"); - webView.getUserContentController().removeUserOnlyScriptsByGroupName(groupName); - } - result.success(true); - break; - case removeAllUserScripts: - if (webView != null && webView.getUserContentController() != null) { - webView.getUserContentController().removeAllUserOnlyScripts(); - } - result.success(true); - break; - case callAsyncJavaScript: - if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - String functionBody = (String) call.argument("functionBody"); - Map functionArguments = (Map) call.argument("arguments"); - Map contentWorldMap = (Map) call.argument("contentWorld"); - ContentWorld contentWorld = ContentWorld.fromMap(contentWorldMap); - webView.callAsyncJavaScript(functionBody, functionArguments, contentWorld, new ValueCallback() { - @Override - public void onReceiveValue(String value) { - result.success(value); - } - }); - } else { - result.success(null); - } - break; - case isSecureContext: - if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - webView.isSecureContext(new ValueCallback() { - @Override - public void onReceiveValue(Boolean value) { - result.success(value); - } - }); - } else { - result.success(false); - } - break; - case createWebMessageChannel: - if (webView != null) { - if (webView instanceof InAppWebView && WebViewFeature.isFeatureSupported(WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL)) { - result.success(webView.createCompatWebMessageChannel().toMap()); - } else { - result.success(null); - } - } else { - result.success(null); - } - break; - case postWebMessage: - if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.POST_WEB_MESSAGE)) { - WebMessageCompatExt message = WebMessageCompatExt.fromMap((Map) call.argument("message")); - String targetOrigin = (String) call.argument("targetOrigin"); - List compatPorts = new ArrayList<>(); - List portsExt = message.getPorts(); - if (portsExt != null) { - for (WebMessagePortCompatExt portExt : portsExt) { - WebMessageChannel webMessageChannel = webView.getWebMessageChannels().get(portExt.getWebMessageChannelId()); - if (webMessageChannel != null) { - if (webView instanceof InAppWebView) { - compatPorts.add(webMessageChannel.compatPorts.get(portExt.getIndex())); - } - } - } - } - Object data = message.getData(); - if (webView instanceof InAppWebView) { - try { - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER) && data != null && - message.getType() == WebMessageCompat.TYPE_ARRAY_BUFFER) { - WebViewCompat.postWebMessage((WebView) webView, - new WebMessageCompat((byte[]) data, compatPorts.toArray(new WebMessagePortCompat[0])), - Uri.parse(targetOrigin)); - } else { - WebViewCompat.postWebMessage((WebView) webView, - new WebMessageCompat(data != null ? data.toString() : null, compatPorts.toArray(new WebMessagePortCompat[0])), - Uri.parse(targetOrigin)); - } - result.success(true); - } catch (Exception e) { - result.error(LOG_TAG, e.getMessage(), null); - } - } - } else { - result.success(true); - } - break; - case addWebMessageListener: - if (webView != null) { - Map webMessageListenerMap = (Map) call.argument("webMessageListener"); - WebMessageListener webMessageListener = WebMessageListener.fromMap(webView, webView.getPlugin().messenger, webMessageListenerMap); - if (webView instanceof InAppWebView && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) { - try { - webView.addWebMessageListener(webMessageListener); - result.success(true); - } catch (Exception e) { - result.error(LOG_TAG, e.getMessage(), null); - } - } else { - result.success(true); - } - } else { - result.success(true); - } - break; - case canScrollVertically: - if (webView != null) { - result.success(webView.canScrollVertically()); - } else { - result.success(false); - } - break; - case canScrollHorizontally: - if (webView != null) { - result.success(webView.canScrollHorizontally()); - } else { - result.success(false); - } - break; - case isInFullscreen: - if (webView != null) { - result.success(webView.isInFullscreen()); - } else { - result.success(false); - } - break; - case clearFormData: - if (webView != null) { - webView.clearFormData(); - } - result.success(true); - case hideInputMethod: - if (webView != null) { - webView.hideInputMethod(); - result.success(true); - } else { - result.success(false); - } - break; - case showInputMethod: - if (webView != null) { - webView.showInputMethod(); - result.success(true); - } else { - result.success(false); - } - break; - case saveState: - if (webView != null) { - result.success(webView.saveState()); - } else { - result.success(null); - } - break; - case restoreState: - if (webView != null) { - byte[] state = (byte[]) call.argument("state"); - result.success(webView.restoreState(state)); - } else { - result.success(false); - } - break; - } - } - - /** - * @deprecated Use {@link FindInteractionChannelDelegate#onFindResultReceived} instead. - */ - @Deprecated - public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("activeMatchOrdinal", activeMatchOrdinal); - obj.put("numberOfMatches", numberOfMatches); - obj.put("isDoneCounting", isDoneCounting); - channel.invokeMethod("onFindResultReceived", obj); - } - - public void onLongPressHitTestResult(HitTestResult hitTestResult) { - MethodChannel channel = getChannel(); - if (channel == null) return; - channel.invokeMethod("onLongPressHitTestResult", hitTestResult.toMap()); - } - - public void onScrollChanged(int x, int y) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("x", x); - obj.put("y", y); - channel.invokeMethod("onScrollChanged", obj); - } - - public void onDownloadStarting(DownloadStartRequest downloadStartRequest) { - MethodChannel channel = getChannel(); - if (channel == null) return; - channel.invokeMethod("onDownloadStarting", downloadStartRequest.toMap()); - } - - public void onCreateContextMenu(HitTestResult hitTestResult) { - MethodChannel channel = getChannel(); - if (channel == null) return; - channel.invokeMethod("onCreateContextMenu", hitTestResult.toMap()); - } - - public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("x", scrollX); - obj.put("y", scrollY); - obj.put("clampedX", clampedX); - obj.put("clampedY", clampedY); - channel.invokeMethod("onOverScrolled", obj); - } - - public void onContextMenuActionItemClicked(int itemId, String itemTitle) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("id", itemId); - obj.put("androidId", itemId); - obj.put("iosId", null); - obj.put("title", itemTitle); - channel.invokeMethod("onContextMenuActionItemClicked", obj); - } - - public void onHideContextMenu() { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onHideContextMenu", obj); - } - - public void onEnterFullscreen() { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onEnterFullscreen", obj); - } - - public void onExitFullscreen() { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onExitFullscreen", obj); - } - - public static class JsAlertCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public JsAlertResponse decodeResult(@Nullable Object obj) { - return JsAlertResponse.fromMap((Map) obj); - } - } - - public void onJsAlert(String url, String message, Boolean isMainFrame, @NonNull JsAlertCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("url", url); - obj.put("message", message); - obj.put("isMainFrame", isMainFrame); - channel.invokeMethod("onJsAlert", obj, callback); - } - - public static class JsConfirmCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public JsConfirmResponse decodeResult(@Nullable Object obj) { - return JsConfirmResponse.fromMap((Map) obj); - } - } - - public void onJsConfirm(String url, String message, Boolean isMainFrame, @NonNull JsConfirmCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("url", url); - obj.put("message", message); - obj.put("isMainFrame", isMainFrame); - channel.invokeMethod("onJsConfirm", obj, callback); - } - - public static class JsPromptCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public JsPromptResponse decodeResult(@Nullable Object obj) { - return JsPromptResponse.fromMap((Map) obj); - } - } - - public void onJsPrompt(String url, String message, String defaultValue, Boolean isMainFrame, @NonNull JsPromptCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("url", url); - obj.put("message", message); - obj.put("defaultValue", defaultValue); - obj.put("isMainFrame", isMainFrame); - channel.invokeMethod("onJsPrompt", obj, callback); - } - - public static class JsBeforeUnloadCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public JsBeforeUnloadResponse decodeResult(@Nullable Object obj) { - return JsBeforeUnloadResponse.fromMap((Map) obj); - } - } - - public void onJsBeforeUnload(String url, String message, @NonNull JsBeforeUnloadCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("url", url); - obj.put("message", message); - channel.invokeMethod("onJsBeforeUnload", obj, callback); - } - - public static class CreateWindowCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public Boolean decodeResult(@Nullable Object obj) { - return (obj instanceof Boolean) && (boolean) obj; - } - } - - public void onCreateWindow(CreateWindowAction createWindowAction, @NonNull CreateWindowCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - channel.invokeMethod("onCreateWindow", createWindowAction.toMap(), callback); - } - - public void onCloseWindow() { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onCloseWindow", obj); - } - - public static class GeolocationPermissionsShowPromptCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public GeolocationPermissionShowPromptResponse decodeResult(@Nullable Object obj) { - return GeolocationPermissionShowPromptResponse.fromMap((Map) obj); - } - } - - public void onGeolocationPermissionsShowPrompt(String origin, @NonNull GeolocationPermissionsShowPromptCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("origin", origin); - channel.invokeMethod("onGeolocationPermissionsShowPrompt", obj, callback); - } - - public void onGeolocationPermissionsHidePrompt() { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onGeolocationPermissionsHidePrompt", obj); - } - - public void onConsoleMessage(String message, int messageLevel) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("message", message); - obj.put("messageLevel", messageLevel); - channel.invokeMethod("onConsoleMessage", obj); - } - - public void onProgressChanged(int progress) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("progress", progress); - channel.invokeMethod("onProgressChanged", obj); - } - - public void onTitleChanged(String title) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("title", title); - channel.invokeMethod("onTitleChanged", obj); - } - - public void onReceivedIcon(byte[] icon) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("icon", icon); - channel.invokeMethod("onReceivedIcon", obj); - } - - public void onReceivedTouchIconUrl(String url, boolean precomposed) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("url", url); - obj.put("precomposed", precomposed); - channel.invokeMethod("onReceivedTouchIconUrl", obj); - } - - public static class PermissionRequestCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public PermissionResponse decodeResult(@Nullable Object obj) { - return PermissionResponse.fromMap((Map) obj); - } - } - - public void onPermissionRequest(String origin, List resources, Object frame, @NonNull PermissionRequestCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("origin", origin); - obj.put("resources", resources); - obj.put("frame", frame); - channel.invokeMethod("onPermissionRequest", obj, callback); - } - - public void onPermissionRequestCanceled(String origin, List resources) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("origin", origin); - obj.put("resources", resources); - channel.invokeMethod("onPermissionRequestCanceled", obj); - } - - public static class ShouldOverrideUrlLoadingCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public NavigationActionPolicy decodeResult(@Nullable Object obj) { - Integer action = obj instanceof Integer ? (Integer) obj : NavigationActionPolicy.CANCEL.rawValue(); - return NavigationActionPolicy.fromValue(action); - } - } - - public void shouldOverrideUrlLoading(NavigationAction navigationAction, @NonNull ShouldOverrideUrlLoadingCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - channel.invokeMethod("shouldOverrideUrlLoading", navigationAction.toMap(), callback); - } - - public void onLoadStart(String url) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("url", url); - channel.invokeMethod("onLoadStart", obj); - } - - public void onLoadStop(String url) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("url", url); - channel.invokeMethod("onLoadStop", obj); - } - - public void onUpdateVisitedHistory(String url, boolean isReload) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("url", url); - obj.put("isReload", isReload); - channel.invokeMethod("onUpdateVisitedHistory", obj); - } - - public void onReceivedError(WebResourceRequestExt request, WebResourceErrorExt error) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("request", request.toMap()); - obj.put("error", error.toMap()); - channel.invokeMethod("onReceivedError", obj); - } - - public void onReceivedHttpError(WebResourceRequestExt request, WebResourceResponseExt errorResponse) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("request", request.toMap()); - obj.put("errorResponse", errorResponse.toMap()); - channel.invokeMethod("onReceivedHttpError", obj); - } - - public static class ReceivedHttpAuthRequestCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public HttpAuthResponse decodeResult(@Nullable Object obj) { - return HttpAuthResponse.fromMap((Map) obj); - } - } - - public void onReceivedHttpAuthRequest(HttpAuthenticationChallenge challenge, @NonNull ReceivedHttpAuthRequestCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - channel.invokeMethod("onReceivedHttpAuthRequest", challenge.toMap(), callback); - } - - public static class ReceivedServerTrustAuthRequestCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public ServerTrustAuthResponse decodeResult(@Nullable Object obj) { - return ServerTrustAuthResponse.fromMap((Map) obj); - } - } - - public void onReceivedServerTrustAuthRequest(ServerTrustChallenge challenge, @NonNull ReceivedServerTrustAuthRequestCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - channel.invokeMethod("onReceivedServerTrustAuthRequest", challenge.toMap(), callback); - } - - public static class ReceivedClientCertRequestCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public ClientCertResponse decodeResult(@Nullable Object obj) { - return ClientCertResponse.fromMap((Map) obj); - } - } - - public void onReceivedClientCertRequest(ClientCertChallenge challenge, @NonNull ReceivedClientCertRequestCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - channel.invokeMethod("onReceivedClientCertRequest", challenge.toMap(), callback); - } - - public void onZoomScaleChanged(float oldScale, float newScale) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("oldScale", oldScale); - obj.put("newScale", newScale); - channel.invokeMethod("onZoomScaleChanged", obj); - } - - public static class SafeBrowsingHitCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public SafeBrowsingResponse decodeResult(@Nullable Object obj) { - return SafeBrowsingResponse.fromMap((Map) obj); - } - } - - public void onSafeBrowsingHit(String url, int threatType, @NonNull SafeBrowsingHitCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("url", url); - obj.put("threatType", threatType); - channel.invokeMethod("onSafeBrowsingHit", obj, callback); - } - - public static class FormResubmissionCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public Integer decodeResult(@Nullable Object obj) { - return obj instanceof Integer ? (Integer) obj : null; - } - } - - public void onFormResubmission(String url, @NonNull FormResubmissionCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("url", url); - channel.invokeMethod("onFormResubmission", obj, callback); - } - - public void onPageCommitVisible(String url) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("url", url); - channel.invokeMethod("onPageCommitVisible", obj); - } - - public void onRenderProcessGone(boolean didCrash, int rendererPriorityAtExit) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("didCrash", didCrash); - obj.put("rendererPriorityAtExit", rendererPriorityAtExit); - channel.invokeMethod("onRenderProcessGone", obj); - } - - public void onReceivedLoginRequest(String realm, String account, String args) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("realm", realm); - obj.put("account", account); - obj.put("args", args); - channel.invokeMethod("onReceivedLoginRequest", obj); - } - - public static class LoadResourceWithCustomSchemeCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public CustomSchemeResponse decodeResult(@Nullable Object obj) { - return CustomSchemeResponse.fromMap((Map) obj); - } - } - - public void onLoadResourceWithCustomScheme(WebResourceRequestExt request, @NonNull LoadResourceWithCustomSchemeCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("request", request.toMap()); - channel.invokeMethod("onLoadResourceWithCustomScheme", obj, callback); - } - - public static class SyncLoadResourceWithCustomSchemeCallback extends SyncBaseCallbackResultImpl { - @Nullable - @Override - public CustomSchemeResponse decodeResult(@Nullable Object obj) { - return (new LoadResourceWithCustomSchemeCallback()).decodeResult(obj); - } - } - - @Nullable - public CustomSchemeResponse onLoadResourceWithCustomScheme(WebResourceRequestExt request) throws InterruptedException { - MethodChannel channel = getChannel(); - if (channel == null) return null; - final Map obj = new HashMap<>(); - obj.put("request", request.toMap()); - final SyncLoadResourceWithCustomSchemeCallback callback = new SyncLoadResourceWithCustomSchemeCallback(); - return Util.invokeMethodAndWaitResult(channel, "onLoadResourceWithCustomScheme", obj, callback); - } - - public static class ShouldInterceptRequestCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public WebResourceResponseExt decodeResult(@Nullable Object obj) { - return WebResourceResponseExt.fromMap((Map) obj); - } - } - - public void shouldInterceptRequest(WebResourceRequestExt request, @NonNull ShouldInterceptRequestCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - channel.invokeMethod("shouldInterceptRequest", request.toMap(), callback); - } - - public static class SyncShouldInterceptRequestCallback extends SyncBaseCallbackResultImpl { - @Nullable - @Override - public WebResourceResponseExt decodeResult(@Nullable Object obj) { - return (new ShouldInterceptRequestCallback()).decodeResult(obj); - } - } - - @Nullable - public WebResourceResponseExt shouldInterceptRequest(WebResourceRequestExt request) throws InterruptedException { - MethodChannel channel = getChannel(); - if (channel == null) return null; - final SyncShouldInterceptRequestCallback callback = new SyncShouldInterceptRequestCallback(); - return Util.invokeMethodAndWaitResult(channel, "shouldInterceptRequest", request.toMap(), callback); - } - - public static class RenderProcessUnresponsiveCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public Integer decodeResult(@Nullable Object obj) { - return obj instanceof Integer ? (Integer) obj : null; - } - } - - public void onRenderProcessUnresponsive(String url, @NonNull RenderProcessUnresponsiveCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("url", url); - channel.invokeMethod("onRenderProcessUnresponsive", obj, callback); - } - - public static class RenderProcessResponsiveCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public Integer decodeResult(@Nullable Object obj) { - return obj instanceof Integer ? (Integer) obj : null; - } - } - - public void onRenderProcessResponsive(String url, @NonNull RenderProcessResponsiveCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("url", url); - channel.invokeMethod("onRenderProcessResponsive", obj, callback); - } - - public static class CallJsHandlerCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public Object decodeResult(@Nullable Object obj) { - return obj; - } - } - - public void onCallJsHandler(String handlerName, JavaScriptHandlerFunctionData data, @NonNull CallJsHandlerCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("handlerName", handlerName); - obj.put("data", data.toMap()); - channel.invokeMethod("onCallJsHandler", obj, callback); - } - - public static class PrintRequestCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public Boolean decodeResult(@Nullable Object obj) { - return (obj instanceof Boolean) && (boolean) obj; - } - } - - public void onPrintRequest(String url, String printJobId, @NonNull PrintRequestCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("url", url); - obj.put("printJobId", printJobId); - channel.invokeMethod("onPrintRequest", obj, callback); - } - - public void onRequestFocus() { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onRequestFocus", obj); - } - - public static class ShowFileChooserCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public ShowFileChooserResponse decodeResult(@Nullable Object obj) { - return ShowFileChooserResponse.fromMap((Map) obj); - } - } - - public void onShowFileChooser(ShowFileChooserRequest request, @NonNull ShowFileChooserCallback callback) { - MethodChannel channel = getChannel(); - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - channel.invokeMethod("onShowFileChooser", request.toMap(), callback); - } - - @Override - public void dispose() { - super.dispose(); - webView = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegateMethods.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegateMethods.java deleted file mode 100644 index 45f022ef64..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegateMethods.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview; - -public enum WebViewChannelDelegateMethods { - getUrl, - getTitle, - getProgress, - loadUrl, - postUrl, - loadData, - loadFile, - evaluateJavascript, - injectJavascriptFileFromUrl, - injectCSSCode, - injectCSSFileFromUrl, - reload, - goBack, - canGoBack, - goForward, - canGoForward, - goBackOrForward, - canGoBackOrForward, - stopLoading, - isLoading, - takeScreenshot, - setSettings, - getSettings, - close, - show, - hide, - isHidden, - getCopyBackForwardList, - startSafeBrowsing, - /** - * @deprecated - */ - @Deprecated - clearCache, - clearSslPreferences, - /** - * @deprecated - */ - @Deprecated - findAll, - findNext, - clearMatches, - scrollTo, - scrollBy, - pause, - resume, - pauseTimers, - resumeTimers, - printCurrentPage, - getContentHeight, - getContentWidth, - zoomBy, - getOriginalUrl, - getZoomScale, - getSelectedText, - getHitTestResult, - pageDown, - pageUp, - saveWebArchive, - zoomIn, - zoomOut, - requestFocus, - clearFocus, - setContextMenu, - requestFocusNodeHref, - requestImageRef, - getScrollX, - getScrollY, - getCertificate, - clearHistory, - addUserScript, - removeUserScript, - removeUserScriptsByGroupName, - removeAllUserScripts, - callAsyncJavaScript, - isSecureContext, - createWebMessageChannel, - postWebMessage, - addWebMessageListener, - canScrollVertically, - canScrollHorizontally, - isInFullscreen, - clearFormData, - hideInputMethod, - showInputMethod, - saveState, - restoreState, -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/DisplayListenerProxy.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/DisplayListenerProxy.java deleted file mode 100755 index ebe487ef95..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/DisplayListenerProxy.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview; - -import static android.hardware.display.DisplayManager.DisplayListener; - -import android.annotation.TargetApi; -import android.hardware.display.DisplayManager; -import android.os.Build; -import android.util.Log; -import java.lang.reflect.Field; -import java.util.ArrayList; - -/** - * Works around an Android WebView bug by filtering some DisplayListener invocations. - * https://github.com/flutter/plugins/blob/master/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/DisplayListenerProxy.java - */ -@TargetApi(Build.VERSION_CODES.KITKAT) -public -class DisplayListenerProxy { - private static final String TAG = "DisplayListenerProxy"; - - private ArrayList listenersBeforeWebView; - - /** Should be called prior to the webview's initialization. */ - public void onPreWebViewInitialization(DisplayManager displayManager) { - listenersBeforeWebView = yoinkDisplayListeners(displayManager); - } - - /** Should be called after the webview's initialization. */ - public void onPostWebViewInitialization(final DisplayManager displayManager) { - final ArrayList webViewListeners = yoinkDisplayListeners(displayManager); - // We recorded the list of listeners prior to initializing webview, any new listeners we see - // after initializing the webview are listeners added by the webview. - webViewListeners.removeAll(listenersBeforeWebView); - - if (webViewListeners.isEmpty()) { - // The Android WebView registers a single display listener per process (even if there - // are multiple WebView instances) so this list is expected to be non-empty only the - // first time a webview is initialized. - // Note that in an add2app scenario if the application had instantiated a non Flutter - // WebView prior to instantiating the Flutter WebView we are not able to get a reference - // to the WebView's display listener and can't work around the bug. - // - // This means that webview resizes in add2app Flutter apps with a non Flutter WebView - // running on a system with a webview prior to 58.0.3029.125 may crash (the Android's - // behavior seems to be racy so it doesn't always happen). - return; - } - - for (DisplayListener webViewListener : webViewListeners) { - // Note that while DisplayManager.unregisterDisplayListener throws when given an - // unregistered listener, this isn't an issue as the WebView code never calls - // unregisterDisplayListener. - displayManager.unregisterDisplayListener(webViewListener); - - // We never explicitly unregister this listener as the webview's listener is never - // unregistered (it's released when the process is terminated). - displayManager.registerDisplayListener( - new DisplayListener() { - @Override - public void onDisplayAdded(int displayId) { - for (DisplayListener webViewListener : webViewListeners) { - webViewListener.onDisplayAdded(displayId); - } - } - - @Override - public void onDisplayRemoved(int displayId) { - for (DisplayListener webViewListener : webViewListeners) { - webViewListener.onDisplayRemoved(displayId); - } - } - - @Override - public void onDisplayChanged(int displayId) { - if (displayManager.getDisplay(displayId) == null) { - return; - } - for (DisplayListener webViewListener : webViewListeners) { - webViewListener.onDisplayChanged(displayId); - } - } - }, - null); - } - } - - @SuppressWarnings({"unchecked", "PrivateApi"}) - private static ArrayList yoinkDisplayListeners(DisplayManager displayManager) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - // We cannot use reflection on Android P, but it shouldn't matter as it shipped - // with WebView 66.0.3359.158 and the WebView version the bug this code is working around was - // fixed in 61.0.3116.0. - return new ArrayList<>(); - } - try { - Field displayManagerGlobalField = DisplayManager.class.getDeclaredField("mGlobal"); - displayManagerGlobalField.setAccessible(true); - Object displayManagerGlobal = displayManagerGlobalField.get(displayManager); - Field displayListenersField = - displayManagerGlobal.getClass().getDeclaredField("mDisplayListeners"); - displayListenersField.setAccessible(true); - ArrayList delegates = - (ArrayList) displayListenersField.get(displayManagerGlobal); - - Field listenerField = null; - ArrayList listeners = new ArrayList<>(); - for (Object delegate : delegates) { - if (listenerField == null) { - listenerField = delegate.getClass().getField("mListener"); - listenerField.setAccessible(true); - } - DisplayManager.DisplayListener listener = - (DisplayManager.DisplayListener) listenerField.get(delegate); - listeners.add(listener); - } - return listeners; - } catch (NoSuchFieldException | IllegalAccessException e) { - Log.w(TAG, "Could not extract WebView's display listeners. " + e); - return new ArrayList<>(); - } - } -} \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/FlutterWebView.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/FlutterWebView.java deleted file mode 100755 index 5605b68e3b..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/FlutterWebView.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.hardware.display.DisplayManager; -import android.os.Message; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.webkit.WebView; -import android.widget.FrameLayout; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.find_interaction.FindInteractionController; -import com.pichillilorenzo.flutter_inappwebview_android.pull_to_refresh.PullToRefreshLayout; -import com.pichillilorenzo.flutter_inappwebview_android.pull_to_refresh.PullToRefreshSettings; -import com.pichillilorenzo.flutter_inappwebview_android.webview.PlatformWebView; -import com.pichillilorenzo.flutter_inappwebview_android.types.URLRequest; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserScript; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class FlutterWebView implements PlatformWebView { - - static final String LOG_TAG = "IAWFlutterWebView"; - - @Nullable - public InAppWebView webView; - @Nullable - public PullToRefreshLayout pullToRefreshLayout; - @Nullable - public String keepAliveId; - - public FlutterWebView(final InAppWebViewFlutterPlugin plugin, final Context context, Object id, - HashMap params) { - DisplayListenerProxy displayListenerProxy = new DisplayListenerProxy(); - DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); - displayListenerProxy.onPreWebViewInitialization(displayManager); - - keepAliveId = (String) params.get("keepAliveId"); - - Map initialSettings = (Map) params.get("initialSettings"); - Map contextMenu = (Map) params.get("contextMenu"); - Integer windowId = (Integer) params.get("windowId"); - List> initialUserScripts = (List>) params.get("initialUserScripts"); - Map pullToRefreshInitialSettings = (Map) params.get("pullToRefreshSettings"); - - InAppWebViewSettings customSettings = new InAppWebViewSettings(); - customSettings.parse(initialSettings); - - List userScripts = new ArrayList<>(); - if (initialUserScripts != null) { - for (Map initialUserScript : initialUserScripts) { - userScripts.add(UserScript.fromMap(initialUserScript)); - } - } - - webView = new InAppWebView(context, plugin, id, windowId, customSettings, contextMenu, - customSettings.useHybridComposition ? null : plugin.flutterView, userScripts); - displayListenerProxy.onPostWebViewInitialization(displayManager); - - // set MATCH_PARENT layout params to the WebView, otherwise it won't take all the available space! - webView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - PullToRefreshSettings pullToRefreshSettings = new PullToRefreshSettings(); - pullToRefreshSettings.parse(pullToRefreshInitialSettings); - pullToRefreshLayout = new PullToRefreshLayout(context, plugin, id, pullToRefreshSettings); - pullToRefreshLayout.addView(webView); - pullToRefreshLayout.prepare(); - - FindInteractionController findInteractionController = new FindInteractionController(webView, plugin, id, null); - webView.findInteractionController = findInteractionController; - findInteractionController.prepare(); - - webView.prepare(); - } - - @Override - public View getView() { - return pullToRefreshLayout != null ? pullToRefreshLayout : webView; - } - - @SuppressLint("RestrictedApi") - public void makeInitialLoad(HashMap params) { - if (webView == null) { - return; - } - - Integer windowId = (Integer) params.get("windowId"); - Map initialUrlRequest = (Map) params.get("initialUrlRequest"); - final String initialFile = (String) params.get("initialFile"); - final Map initialData = (Map) params.get("initialData"); - - if (windowId != null) { - if (webView.plugin != null && webView.plugin.inAppWebViewManager != null) { - Message resultMsg = webView.plugin.inAppWebViewManager.windowWebViewMessages.get(windowId); - if (resultMsg != null) { - ((WebView.WebViewTransport) resultMsg.obj).setWebView(webView); - resultMsg.sendToTarget(); - if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { - // for some reason, if a WebView is created using a window id, - // the initial plugin and user scripts injected - // with WebViewCompat.addDocumentStartJavaScript will not be added! - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1455 - // - // Also, calling the prepareAndAddUserScripts method right after won't work, - // so use the View.post method here. - webView.post(new Runnable() { - @Override - public void run() { - if (webView != null) { - webView.prepareAndAddUserScripts(); - } - } - }); - } - } - } - } else { - if (initialFile != null) { - try { - webView.loadFile(initialFile); - } catch (IOException e) { - Log.e(LOG_TAG, initialFile + " asset file cannot be found!", e); - } - } - else if (initialData != null) { - String data = initialData.get("data"); - String mimeType = initialData.get("mimeType"); - String encoding = initialData.get("encoding"); - String baseUrl = initialData.get("baseUrl"); - String historyUrl = initialData.get("historyUrl"); - webView.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl); - } - else if (initialUrlRequest != null) { - URLRequest urlRequest = URLRequest.fromMap(initialUrlRequest); - if (urlRequest != null) { - webView.loadUrl(urlRequest); - } - } - } - } - - @Override - public void dispose() { - if (keepAliveId == null && webView != null) { - webView.dispose(); - webView = null; - - if (pullToRefreshLayout != null) { - pullToRefreshLayout.dispose(); - pullToRefreshLayout = null; - } - } - } - - @Override - public void onInputConnectionLocked() { - if (webView != null && webView.inAppBrowserDelegate == null && !webView.customSettings.useHybridComposition) - webView.lockInputConnection(); - } - - @Override - public void onInputConnectionUnlocked() { - if (webView != null && webView.inAppBrowserDelegate == null && !webView.customSettings.useHybridComposition) - webView.unlockInputConnection(); - } - - @Override - public void onFlutterViewAttached(@NonNull View flutterView) { - if (webView != null && !webView.customSettings.useHybridComposition) { - webView.setContainerView(flutterView); - } - } - - @Override - public void onFlutterViewDetached() { - if (webView != null && !webView.customSettings.useHybridComposition) { - webView.setContainerView(null); - } - } -} \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java deleted file mode 100755 index 7cf3f7f558..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java +++ /dev/null @@ -1,2248 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview; - -import static android.content.Context.INPUT_METHOD_SERVICE; -import static com.pichillilorenzo.flutter_inappwebview_android.types.PreferredContentModeOptionType.fromValue; - -import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; -import android.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Point; -import android.graphics.drawable.ColorDrawable; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.Parcel; -import android.print.InAppWebViewPrintDocumentAdapter; -import android.print.PrintAttributes; -import android.print.PrintDocumentAdapter; -import android.print.PrintJob; -import android.print.PrintManager; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Log; -import android.view.ActionMode; -import android.view.ContextMenu; -import android.view.GestureDetector; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.view.ViewTreeObserver; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; -import android.view.inputmethod.InputMethodManager; -import android.webkit.CookieManager; -import android.webkit.DownloadListener; -import android.webkit.URLUtil; -import android.webkit.ValueCallback; -import android.webkit.WebBackForwardList; -import android.webkit.WebChromeClient; -import android.webkit.WebHistoryItem; -import android.webkit.WebSettings; -import android.webkit.WebStorage; -import android.webkit.WebView; -import android.webkit.WebViewClient; -import android.widget.HorizontalScrollView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; -import androidx.webkit.WebSettingsCompat; -import androidx.webkit.WebViewCompat; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.R; -import com.pichillilorenzo.flutter_inappwebview_android.Util; -import com.pichillilorenzo.flutter_inappwebview_android.content_blocker.ContentBlocker; -import com.pichillilorenzo.flutter_inappwebview_android.content_blocker.ContentBlockerAction; -import com.pichillilorenzo.flutter_inappwebview_android.content_blocker.ContentBlockerHandler; -import com.pichillilorenzo.flutter_inappwebview_android.content_blocker.ContentBlockerTrigger; -import com.pichillilorenzo.flutter_inappwebview_android.find_interaction.FindInteractionController; -import com.pichillilorenzo.flutter_inappwebview_android.in_app_browser.InAppBrowserDelegate; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.InterceptAjaxRequestJS; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.InterceptFetchRequestJS; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.JavaScriptBridgeJS; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.OnLoadResourceJS; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.OnWindowBlurEventJS; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.OnWindowFocusEventJS; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.PluginScriptsUtil; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.PrintJS; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.PromisePolyfillJS; -import com.pichillilorenzo.flutter_inappwebview_android.print_job.PrintJobController; -import com.pichillilorenzo.flutter_inappwebview_android.print_job.PrintJobSettings; -import com.pichillilorenzo.flutter_inappwebview_android.pull_to_refresh.PullToRefreshLayout; -import com.pichillilorenzo.flutter_inappwebview_android.types.ContentWorld; -import com.pichillilorenzo.flutter_inappwebview_android.types.DownloadStartRequest; -import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; -import com.pichillilorenzo.flutter_inappwebview_android.types.PreferredContentModeOptionType; -import com.pichillilorenzo.flutter_inappwebview_android.types.URLRequest; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserContentController; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserScript; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebViewAssetLoaderExt; -import com.pichillilorenzo.flutter_inappwebview_android.webview.ContextMenuSettings; -import com.pichillilorenzo.flutter_inappwebview_android.webview.InAppWebViewInterface; -import com.pichillilorenzo.flutter_inappwebview_android.webview.JavaScriptBridgeInterface; -import com.pichillilorenzo.flutter_inappwebview_android.webview.WebViewChannelDelegate; -import com.pichillilorenzo.flutter_inappwebview_android.webview.web_message.WebMessageChannel; -import com.pichillilorenzo.flutter_inappwebview_android.webview.web_message.WebMessageListener; - -import org.json.JSONObject; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -import io.flutter.plugin.common.MethodChannel; - -final public class InAppWebView extends InputAwareWebView implements InAppWebViewInterface { - private static final String LOG_TAG = "InAppWebView"; - public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_"; - - @Nullable - public InAppWebViewFlutterPlugin plugin; - @Nullable - public InAppBrowserDelegate inAppBrowserDelegate; - public Object id; - @Nullable - public Integer windowId; - @Nullable - public InAppWebViewClient inAppWebViewClient; - @Nullable - public InAppWebViewClientCompat inAppWebViewClientCompat; - @Nullable - public InAppWebViewChromeClient inAppWebViewChromeClient; - @Nullable - public InAppWebViewRenderProcessClient inAppWebViewRenderProcessClient; - @Nullable - public WebViewChannelDelegate channelDelegate; - @Nullable - public JavaScriptBridgeInterface javaScriptBridgeInterface; - public InAppWebViewSettings customSettings = new InAppWebViewSettings(); - public boolean isLoading = false; - private boolean inFullscreen = false; - public float zoomScale = 1.0f; - public ContentBlockerHandler contentBlockerHandler = new ContentBlockerHandler(); - @Nullable - public GestureDetector gestureDetector = null; - @Nullable - public LinearLayout floatingContextMenu = null; - @Nullable - public Map contextMenu = null; - public Handler mainLooperHandler = new Handler(getWebViewLooper()); - static Handler mHandler = new Handler(); - - public Runnable checkScrollStoppedTask; - public int initialPositionScrollStoppedTask; - public int newCheckScrollStoppedTask = 100; // ms - - public Runnable checkContextMenuShouldBeClosedTask; - public int newCheckContextMenuShouldBeClosedTaskTask = 100; // ms - - public UserContentController userContentController = new UserContentController(this); - - public Map> callAsyncJavaScriptCallbacks = new HashMap<>(); - public Map> evaluateJavaScriptContentWorldCallbacks = new HashMap<>(); - - public Map webMessageChannels = new HashMap<>(); - public List webMessageListeners = new ArrayList<>(); - - private List initialUserOnlyScripts = new ArrayList<>(); - - @Nullable - public FindInteractionController findInteractionController; - - @Nullable - public WebViewAssetLoaderExt webViewAssetLoaderExt; - - @Nullable - private PluginScript interceptOnlyAsyncAjaxRequestsPluginScript; - - @NonNull - private final String expectedBridgeSecret = UUID.randomUUID().toString(); - private boolean javaScriptBridgeEnabled = true; - - public InAppWebView(Context context) { - super(context); - } - - public InAppWebView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public InAppWebView(Context context, AttributeSet attrs, int defaultStyle) { - super(context, attrs, defaultStyle); - } - - public InAppWebView(Context context, @NonNull InAppWebViewFlutterPlugin plugin, - @NonNull Object id, @Nullable Integer windowId, InAppWebViewSettings customSettings, - @Nullable Map contextMenu, View containerView, - List userScripts) { - super(context, containerView, customSettings.useHybridComposition); - this.plugin = plugin; - this.id = id; - final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id); - this.channelDelegate = new WebViewChannelDelegate(this, channel); - this.windowId = windowId; - this.customSettings = customSettings; - this.contextMenu = contextMenu; - this.initialUserOnlyScripts = userScripts; - if (plugin != null && plugin.activity != null) { - plugin.activity.registerForContextMenu(this); - } - } - - public WebViewClient createWebViewClient(InAppBrowserDelegate inAppBrowserDelegate) { - // bug https://bugs.chromium.org/p/chromium/issues/detail?id=925887 - PackageInfo packageInfo = WebViewCompat.getCurrentWebViewPackage(getContext()); - if (packageInfo == null) { - Log.d(LOG_TAG, "Using InAppWebViewClient implementation"); - return new InAppWebViewClient(inAppBrowserDelegate); - } - - boolean isChromiumWebView = "com.android.webview".equals(packageInfo.packageName) || - "com.google.android.webview".equals(packageInfo.packageName) || - "com.android.chrome".equals(packageInfo.packageName); - boolean isChromiumWebViewBugFixed = false; - if (isChromiumWebView) { - String versionName = packageInfo.versionName != null ? packageInfo.versionName : ""; - try { - int majorVersion = versionName.contains(".") ? - Integer.parseInt(versionName.split("\\.")[0]) : 0; - isChromiumWebViewBugFixed = majorVersion >= 73; - } catch (NumberFormatException ignored) { - } - } - - if (isChromiumWebViewBugFixed || !isChromiumWebView) { - Log.d(LOG_TAG, "Using InAppWebViewClientCompat implementation"); - return new InAppWebViewClientCompat(inAppBrowserDelegate); - } else { - Log.d(LOG_TAG, "Using InAppWebViewClient implementation"); - return new InAppWebViewClient(inAppBrowserDelegate); - } - } - - @Override - public void setAlpha(float alpha) { - ViewParent parent = getParent(); - if (parent instanceof PullToRefreshLayout) { - ((PullToRefreshLayout) parent).setAlpha(alpha); - } else { - super.setAlpha(alpha); - } - } - - @SuppressLint("RestrictedApi") - public void prepare() { - if (customSettings.alpha != null) { - setAlpha(customSettings.alpha.floatValue()); - } - - javaScriptBridgeEnabled = customSettings.javaScriptBridgeEnabled; - if (customSettings.javaScriptBridgeOriginAllowList != null && customSettings.javaScriptBridgeOriginAllowList.isEmpty()) { - // an empty list means that the JavaScript Bridge is not allowed for any origin. - javaScriptBridgeEnabled = false; - } - - if (plugin != null) { - webViewAssetLoaderExt = WebViewAssetLoaderExt.fromMap(customSettings.webViewAssetLoader, plugin, getContext()); - } - - if (javaScriptBridgeEnabled) { - javaScriptBridgeInterface = new JavaScriptBridgeInterface(this, expectedBridgeSecret); - addJavascriptInterface(javaScriptBridgeInterface, JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()); - } - - inAppWebViewChromeClient = new InAppWebViewChromeClient(plugin, this, inAppBrowserDelegate); - setWebChromeClient(inAppWebViewChromeClient); - - WebViewClient webViewClient = createWebViewClient(inAppBrowserDelegate); - if (webViewClient instanceof InAppWebViewClientCompat) { - inAppWebViewClientCompat = (InAppWebViewClientCompat) webViewClient; - setWebViewClient(inAppWebViewClientCompat); - } else if (webViewClient instanceof InAppWebViewClient) { - inAppWebViewClient = (InAppWebViewClient) webViewClient; - setWebViewClient(inAppWebViewClient); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE)) { - inAppWebViewRenderProcessClient = new InAppWebViewRenderProcessClient(); - WebViewCompat.setWebViewRenderProcessClient(this, inAppWebViewRenderProcessClient); - } - - if (windowId == null || !WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { - // for some reason, if a WebView is created using a window id, - // the initial plugin and user scripts injected - // with WebViewCompat.addDocumentStartJavaScript will not be added! - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1455 - prepareAndAddUserScripts(); - } - - if (customSettings.useOnDownloadStart) - setDownloadListener(new DownloadStartListener()); - - WebSettings settings = getSettings(); - - settings.setJavaScriptEnabled(customSettings.javaScriptEnabled); - settings.setJavaScriptCanOpenWindowsAutomatically(customSettings.javaScriptCanOpenWindowsAutomatically); - settings.setBuiltInZoomControls(customSettings.builtInZoomControls); - settings.setDisplayZoomControls(customSettings.displayZoomControls); - settings.setSupportMultipleWindows(customSettings.supportMultipleWindows); - - if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_ENABLE)) - WebSettingsCompat.setSafeBrowsingEnabled(settings, customSettings.safeBrowsingEnabled); - else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) - settings.setSafeBrowsingEnabled(customSettings.safeBrowsingEnabled); - - settings.setMediaPlaybackRequiresUserGesture(customSettings.mediaPlaybackRequiresUserGesture); - - settings.setDatabaseEnabled(customSettings.databaseEnabled); - settings.setDomStorageEnabled(customSettings.domStorageEnabled); - - if (customSettings.userAgent != null && !customSettings.userAgent.isEmpty()) - settings.setUserAgentString(customSettings.userAgent); - else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) - settings.setUserAgentString(WebSettings.getDefaultUserAgent(getContext())); - - if (customSettings.applicationNameForUserAgent != null && !customSettings.applicationNameForUserAgent.isEmpty()) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - String userAgent = (customSettings.userAgent != null && !customSettings.userAgent.isEmpty()) ? customSettings.userAgent : WebSettings.getDefaultUserAgent(getContext()); - String userAgentWithApplicationName = userAgent + " " + customSettings.applicationNameForUserAgent; - settings.setUserAgentString(userAgentWithApplicationName); - } - } - - if (customSettings.clearCache) - clearAllCache(); - else if (customSettings.clearSessionCache) - CookieManager.getInstance().removeSessionCookie(); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - CookieManager.getInstance().setAcceptThirdPartyCookies(this, customSettings.thirdPartyCookiesEnabled); - - settings.setLoadWithOverviewMode(customSettings.loadWithOverviewMode); - settings.setUseWideViewPort(customSettings.useWideViewPort); - settings.setSupportZoom(customSettings.supportZoom); - if (customSettings.textZoom != null) - settings.setTextZoom(customSettings.textZoom); - - setVerticalScrollBarEnabled(!customSettings.disableVerticalScroll && customSettings.verticalScrollBarEnabled); - setHorizontalScrollBarEnabled(!customSettings.disableHorizontalScroll && customSettings.horizontalScrollBarEnabled); - - if (customSettings.transparentBackground) - setBackgroundColor(Color.TRANSPARENT); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && customSettings.mixedContentMode != null) - settings.setMixedContentMode(customSettings.mixedContentMode); - - settings.setAllowContentAccess(customSettings.allowContentAccess); - settings.setAllowFileAccess(customSettings.allowFileAccess); - settings.setAllowFileAccessFromFileURLs(customSettings.allowFileAccessFromFileURLs); - settings.setAllowUniversalAccessFromFileURLs(customSettings.allowUniversalAccessFromFileURLs); - setCacheEnabled(customSettings.cacheEnabled); - if (customSettings.appCachePath != null && !customSettings.appCachePath.isEmpty() && customSettings.cacheEnabled) { - // removed from Android API 33+ (https://developer.android.com/sdk/api_diff/33/changes) - // settings.setAppCachePath(customSettings.appCachePath); - Util.invokeMethodIfExists(settings, "setAppCachePath", customSettings.appCachePath); - } - settings.setBlockNetworkImage(customSettings.blockNetworkImage); - settings.setBlockNetworkLoads(customSettings.blockNetworkLoads); - if (customSettings.cacheMode != null) - settings.setCacheMode(customSettings.cacheMode); - settings.setCursiveFontFamily(customSettings.cursiveFontFamily); - settings.setDefaultFixedFontSize(customSettings.defaultFixedFontSize); - settings.setDefaultFontSize(customSettings.defaultFontSize); - settings.setDefaultTextEncodingName(customSettings.defaultTextEncodingName); - if (customSettings.disabledActionModeMenuItems != null) { - if (WebViewFeature.isFeatureSupported(WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS)) - WebSettingsCompat.setDisabledActionModeMenuItems(settings, customSettings.disabledActionModeMenuItems); - else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - settings.setDisabledActionModeMenuItems(customSettings.disabledActionModeMenuItems); - } - settings.setFantasyFontFamily(customSettings.fantasyFontFamily); - settings.setFixedFontFamily(customSettings.fixedFontFamily); - if (customSettings.forceDark != null) { - if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) - WebSettingsCompat.setForceDark(settings, customSettings.forceDark); - else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) - settings.setForceDark(customSettings.forceDark); - } - if (customSettings.forceDarkStrategy != null && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) { - try { - // for some reason the setForceDarkStrategy method could throw a ClassCastException - // from the Android WebView Chromium library. - WebSettingsCompat.setForceDarkStrategy(settings, customSettings.forceDarkStrategy); - } catch (Exception e) { - e.printStackTrace(); - } - } - settings.setGeolocationEnabled(customSettings.geolocationEnabled); - if (customSettings.layoutAlgorithm != null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && customSettings.layoutAlgorithm.equals(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING)) { - settings.setLayoutAlgorithm(customSettings.layoutAlgorithm); - } else { - settings.setLayoutAlgorithm(customSettings.layoutAlgorithm); - } - } - settings.setLoadsImagesAutomatically(customSettings.loadsImagesAutomatically); - settings.setMinimumFontSize(customSettings.minimumFontSize); - settings.setMinimumLogicalFontSize(customSettings.minimumLogicalFontSize); - setInitialScale(customSettings.initialScale); - settings.setNeedInitialFocus(customSettings.needInitialFocus); - if (WebViewFeature.isFeatureSupported(WebViewFeature.OFF_SCREEN_PRERASTER)) - WebSettingsCompat.setOffscreenPreRaster(settings, customSettings.offscreenPreRaster); - else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) - settings.setOffscreenPreRaster(customSettings.offscreenPreRaster); - settings.setSansSerifFontFamily(customSettings.sansSerifFontFamily); - settings.setSerifFontFamily(customSettings.serifFontFamily); - settings.setStandardFontFamily(customSettings.standardFontFamily); - if (customSettings.preferredContentMode != null && - customSettings.preferredContentMode == PreferredContentModeOptionType.DESKTOP.toValue()) { - setDesktopMode(true); - } - settings.setSaveFormData(customSettings.saveFormData); - if (customSettings.incognito) - setIncognito(true); - if (customSettings.useHybridComposition) { - if (customSettings.hardwareAcceleration) - setLayerType(View.LAYER_TYPE_HARDWARE, null); - else - setLayerType(View.LAYER_TYPE_NONE, null); - } - setScrollBarStyle(customSettings.scrollBarStyle); - if (customSettings.scrollBarDefaultDelayBeforeFade != null) { - setScrollBarDefaultDelayBeforeFade(customSettings.scrollBarDefaultDelayBeforeFade); - } else { - customSettings.scrollBarDefaultDelayBeforeFade = getScrollBarDefaultDelayBeforeFade(); - } - setScrollbarFadingEnabled(customSettings.scrollbarFadingEnabled); - if (customSettings.scrollBarFadeDuration != null) { - setScrollBarFadeDuration(customSettings.scrollBarFadeDuration); - } else { - customSettings.scrollBarFadeDuration = getScrollBarFadeDuration(); - } - setVerticalScrollbarPosition(customSettings.verticalScrollbarPosition); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - if (customSettings.verticalScrollbarThumbColor != null) - setVerticalScrollbarThumbDrawable(new ColorDrawable(Color.parseColor(customSettings.verticalScrollbarThumbColor))); - if (customSettings.verticalScrollbarTrackColor != null) - setVerticalScrollbarTrackDrawable(new ColorDrawable(Color.parseColor(customSettings.verticalScrollbarTrackColor))); - if (customSettings.horizontalScrollbarThumbColor != null) - setHorizontalScrollbarThumbDrawable(new ColorDrawable(Color.parseColor(customSettings.horizontalScrollbarThumbColor))); - if (customSettings.horizontalScrollbarTrackColor != null) - setHorizontalScrollbarTrackDrawable(new ColorDrawable(Color.parseColor(customSettings.horizontalScrollbarTrackColor))); - } - - setOverScrollMode(customSettings.overScrollMode); - if (customSettings.networkAvailable != null) { - setNetworkAvailable(customSettings.networkAvailable); - } - if (customSettings.rendererPriorityPolicy != null && !customSettings.rendererPriorityPolicy.isEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - setRendererPriorityPolicy( - (int) customSettings.rendererPriorityPolicy.get("rendererRequestedPriority"), - (boolean) customSettings.rendererPriorityPolicy.get("waivedWhenNotVisible")); - } - - if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - WebSettingsCompat.setAlgorithmicDarkeningAllowed(settings, customSettings.algorithmicDarkeningAllowed); - } - if (WebViewFeature.isFeatureSupported(WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY)) { - WebSettingsCompat.setEnterpriseAuthenticationAppLinkPolicyEnabled(settings, customSettings.enterpriseAuthenticationAppLinkPolicyEnabled); - } - if (customSettings.requestedWithHeaderOriginAllowList != null && - WebViewFeature.isFeatureSupported(WebViewFeature.REQUESTED_WITH_HEADER_ALLOW_LIST)) { - WebSettingsCompat.setRequestedWithHeaderOriginAllowList(settings, customSettings.requestedWithHeaderOriginAllowList); - } - - contentBlockerHandler.getRuleList().clear(); - for (Map> contentBlocker : customSettings.contentBlockers) { - // compile ContentBlockerTrigger urlFilter - ContentBlockerTrigger trigger = ContentBlockerTrigger.fromMap(contentBlocker.get("trigger")); - ContentBlockerAction action = ContentBlockerAction.fromMap(contentBlocker.get("action")); - contentBlockerHandler.getRuleList().add(new ContentBlocker(trigger, action)); - } - - setFindListener(new FindListener() { - @Override - public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) { - if (findInteractionController != null && findInteractionController.channelDelegate != null) - findInteractionController.channelDelegate.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting); - if (channelDelegate != null) - channelDelegate.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting); - } - }); - - gestureDetector = new GestureDetector(this.getContext(), new GestureDetector.SimpleOnGestureListener() { - @Override - public boolean onSingleTapUp(MotionEvent ev) { - if (floatingContextMenu != null) { - hideContextMenu(); - } - return super.onSingleTapUp(ev); - } - }); - - checkScrollStoppedTask = new Runnable() { - @Override - public void run() { - int newPosition = getScrollY(); - if (initialPositionScrollStoppedTask - newPosition == 0) { - // has stopped - onScrollStopped(); - } else { - initialPositionScrollStoppedTask = getScrollY(); - mainLooperHandler.postDelayed(checkScrollStoppedTask, newCheckScrollStoppedTask); - } - } - }; - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && !customSettings.useHybridComposition) { - checkContextMenuShouldBeClosedTask = new Runnable() { - @Override - public void run() { - if (floatingContextMenu != null) { - evaluateJavascript(PluginScriptsUtil.CHECK_CONTEXT_MENU_SHOULD_BE_HIDDEN_JS_SOURCE, new ValueCallback() { - @Override - public void onReceiveValue(String value) { - if (value == null || value.equals("true")) { - if (floatingContextMenu != null) { - hideContextMenu(); - } - } else { - mainLooperHandler.postDelayed(checkContextMenuShouldBeClosedTask, newCheckContextMenuShouldBeClosedTaskTask); - } - } - }); - } - } - }; - } - - setOnTouchListener(new OnTouchListener() { - float m_downX; - float m_downY; - - @Override - public boolean onTouch(View v, MotionEvent event) { - gestureDetector.onTouchEvent(event); - - if (event.getAction() == MotionEvent.ACTION_UP) { - checkScrollStoppedTask.run(); - } - - if (customSettings.disableHorizontalScroll && customSettings.disableVerticalScroll) { - return (event.getAction() == MotionEvent.ACTION_MOVE); - } else if (customSettings.disableHorizontalScroll || customSettings.disableVerticalScroll) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: { - // save the x - m_downX = event.getX(); - // save the y - m_downY = event.getY(); - break; - } - case MotionEvent.ACTION_MOVE: - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: { - if (customSettings.disableHorizontalScroll) { - // set x so that it doesn't move - event.setLocation(m_downX, event.getY()); - } else { - // set y so that it doesn't move - event.setLocation(event.getX(), m_downY); - } - break; - } - } - } - return false; - } - }); - - setOnLongClickListener(new OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - com.pichillilorenzo.flutter_inappwebview_android.types.HitTestResult hitTestResult = - com.pichillilorenzo.flutter_inappwebview_android.types.HitTestResult.fromWebViewHitTestResult(getHitTestResult()); - if (channelDelegate != null) channelDelegate.onLongPressHitTestResult(hitTestResult); - return false; - } - }); - } - - public void prepareAndAddUserScripts() { - if (javaScriptBridgeEnabled) { - // all the plugin scripts are using the JavaScript Bridge to work - userContentController.addPluginScript(PromisePolyfillJS.PROMISE_POLYFILL_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList, - customSettings.pluginScriptsForMainFrameOnly)); - - final Set javaScriptBridgeOriginAllowList = customSettings.javaScriptBridgeOriginAllowList != null ? - customSettings.javaScriptBridgeOriginAllowList : customSettings.pluginScriptsOriginAllowList; - final boolean javaScriptBridgeForMainFrameOnly = customSettings.javaScriptBridgeForMainFrameOnly != null ? - customSettings.javaScriptBridgeForMainFrameOnly : customSettings.pluginScriptsForMainFrameOnly; - userContentController.addPluginScript(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT(expectedBridgeSecret, - javaScriptBridgeOriginAllowList, - javaScriptBridgeForMainFrameOnly)); - - userContentController.addPluginScript(PrintJS.PRINT_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList, - customSettings.pluginScriptsForMainFrameOnly)); - userContentController.addPluginScript(OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList)); - userContentController.addPluginScript(OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList)); - interceptOnlyAsyncAjaxRequestsPluginScript = InterceptAjaxRequestJS.createInterceptOnlyAsyncAjaxRequestsPluginScript(customSettings.interceptOnlyAsyncAjaxRequests); - if (customSettings.useShouldInterceptAjaxRequest) { - userContentController.addPluginScript(interceptOnlyAsyncAjaxRequestsPluginScript); - userContentController.addPluginScript(InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT( - customSettings.pluginScriptsOriginAllowList, - customSettings.pluginScriptsForMainFrameOnly, - customSettings.useOnAjaxReadyStateChange, - customSettings.useOnAjaxProgress)); - } - if (customSettings.useShouldInterceptFetchRequest) { - userContentController.addPluginScript(InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList, - customSettings.pluginScriptsForMainFrameOnly)); - } - if (customSettings.useOnLoadResource) { - userContentController.addPluginScript(OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList, - customSettings.pluginScriptsForMainFrameOnly)); - } - if (!customSettings.useHybridComposition) { - userContentController.addPluginScript(PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList, - customSettings.pluginScriptsForMainFrameOnly)); - } - } - this.userContentController.addUserOnlyScripts(this.initialUserOnlyScripts); - } - - public void setIncognito(boolean enabled) { - WebSettings settings = getSettings(); - if (enabled) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - CookieManager.getInstance().removeAllCookies(null); - } else { - CookieManager.getInstance().removeAllCookie(); - } - - // Disable caching - settings.setCacheMode(WebSettings.LOAD_NO_CACHE); - - // removed from Android API 33+ (https://developer.android.com/sdk/api_diff/33/changes) - // settings.setAppCacheEnabled(false); - Util.invokeMethodIfExists(settings, "setAppCacheEnabled", false); - - clearHistory(); - clearCache(true); - - // No form data or autofill enabled - clearFormData(); - settings.setSavePassword(false); - settings.setSaveFormData(false); - } else { - settings.setCacheMode(WebSettings.LOAD_DEFAULT); - - // removed from Android API 33+ (https://developer.android.com/sdk/api_diff/33/changes) - // settings.setAppCacheEnabled(true); - Util.invokeMethodIfExists(settings, "setAppCacheEnabled", true); - - settings.setSavePassword(true); - settings.setSaveFormData(true); - } - } - - public void setCacheEnabled(boolean enabled) { - WebSettings settings = getSettings(); - if (enabled) { - Context ctx = getContext(); - if (ctx != null) { - // removed from Android API 33+ (https://developer.android.com/sdk/api_diff/33/changes) - // settings.setAppCachePath(ctx.getCacheDir().getAbsolutePath()); - Util.invokeMethodIfExists(settings, "setAppCachePath", ctx.getCacheDir().getAbsolutePath()); - - settings.setCacheMode(WebSettings.LOAD_DEFAULT); - - // removed from Android API 33+ (https://developer.android.com/sdk/api_diff/33/changes) - // settings.setAppCacheEnabled(true); - Util.invokeMethodIfExists(settings, "setAppCacheEnabled", true); - } - } else { - settings.setCacheMode(WebSettings.LOAD_NO_CACHE); - - // removed from Android API 33+ (https://developer.android.com/sdk/api_diff/33/changes) - // settings.setAppCacheEnabled(false); - Util.invokeMethodIfExists(settings, "setAppCacheEnabled", false); - } - } - - public void loadUrl(URLRequest urlRequest) { - String url = urlRequest.getUrl(); - String method = urlRequest.getMethod(); - if (method != null && method.equals("POST")) { - byte[] postData = urlRequest.getBody(); - postUrl(url, postData); - return; - } - Map headers = urlRequest.getHeaders(); - if (headers != null) { - loadUrl(url, headers); - return; - } - loadUrl(url); - } - - public void loadFile(String assetFilePath) throws IOException { - if (plugin == null) { - return; - } - - loadUrl(Util.getUrlAsset(plugin, assetFilePath)); - } - - public boolean isLoading() { - return isLoading; - } - - /** - * @deprecated - */ - @Deprecated - private void clearCookies() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - CookieManager.getInstance().removeAllCookies(new ValueCallback() { - @Override - public void onReceiveValue(Boolean aBoolean) { - - } - }); - } else { - CookieManager.getInstance().removeAllCookie(); - } - } - - /** - * @deprecated - */ - @Deprecated - public void clearAllCache() { - clearCache(true); - clearCookies(); - clearFormData(); - WebStorage.getInstance().deleteAllData(); - } - - public void takeScreenshot(final @Nullable Map screenshotConfiguration, final MethodChannel.Result result) { - final float pixelDensity = Util.getPixelDensity(getContext()); - - mainLooperHandler.post(new Runnable() { - @Override - public void run() { - try { - int bitmapWidth = getMeasuredWidth(); - int bitmapHeight = getMeasuredHeight(); - int bitmapScrollX = getScrollX(); - int bitmapScrollY = getScrollY(); - - Bitmap.CompressFormat compressFormat = Bitmap.CompressFormat.PNG; - int quality = 100; - - if (screenshotConfiguration != null) { - Map rect = (Map) screenshotConfiguration.get("rect"); - if (rect != null) { - bitmapScrollX = (int) Math.floor(rect.get("x") * pixelDensity + 0.5); - bitmapScrollY = (int) Math.floor(rect.get("y") * pixelDensity + 0.5); - bitmapWidth = (int) Math.floor(rect.get("width") * pixelDensity + 0.5); - bitmapHeight = (int) Math.floor(rect.get("height") * pixelDensity + 0.5); - } - - try { - compressFormat = Bitmap.CompressFormat.valueOf((String) screenshotConfiguration.get("compressFormat")); - } catch (IllegalArgumentException e) { - Log.e(LOG_TAG, "", e); - } - - quality = (Integer) screenshotConfiguration.get("quality"); - } - - Bitmap screenshotBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(screenshotBitmap); - c.translate(-bitmapScrollX, -bitmapScrollY); - draw(c); - - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - - if (screenshotConfiguration != null) { - Double snapshotWidth = (Double) screenshotConfiguration.get("snapshotWidth"); - if (snapshotWidth != null) { - int dstWidth = (int) Math.floor(snapshotWidth * pixelDensity + 0.5); - float ratioBitmap = (float) screenshotBitmap.getWidth() / (float) screenshotBitmap.getHeight(); - int dstHeight = (int) ((float) dstWidth / ratioBitmap); - screenshotBitmap = Bitmap.createScaledBitmap(screenshotBitmap, dstWidth, dstHeight, true); - } - } - - final boolean compressed = screenshotBitmap.compress( - compressFormat, - quality, - byteArrayOutputStream); - if (!compressed) { - Log.e(LOG_TAG, "Screenshot cannot be compressed using compressFormat " + - compressFormat.name() + " with quality " + quality, null); - } - - try { - byteArrayOutputStream.close(); - } catch (IOException e) { - Log.e(LOG_TAG, "", e); - } - screenshotBitmap.recycle(); - result.success(byteArrayOutputStream.toByteArray()); - - } catch (IllegalArgumentException e) { - Log.e(LOG_TAG, "", e); - result.success(null); - } - } - }); - } - - @SuppressLint("RestrictedApi") - public void setSettings(InAppWebViewSettings newCustomSettings, HashMap newSettingsMap) { - - WebSettings settings = getSettings(); - - if (newSettingsMap.get("javaScriptEnabled") != null && customSettings.javaScriptEnabled != newCustomSettings.javaScriptEnabled) - settings.setJavaScriptEnabled(newCustomSettings.javaScriptEnabled); - - if (newSettingsMap.get("useShouldInterceptAjaxRequest") != null && customSettings.useShouldInterceptAjaxRequest != newCustomSettings.useShouldInterceptAjaxRequest) { - enablePluginScriptAtRuntime( - InterceptAjaxRequestJS.FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE(), - newCustomSettings.useShouldInterceptAjaxRequest, - InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT( - customSettings.pluginScriptsOriginAllowList, - customSettings.pluginScriptsForMainFrameOnly, - newCustomSettings.useOnAjaxReadyStateChange, - newCustomSettings.useOnAjaxProgress) - ); - } - - if (newSettingsMap.get("useOnAjaxReadyStateChange") != null && customSettings.useOnAjaxReadyStateChange != newCustomSettings.useOnAjaxReadyStateChange) { - evaluateJavascript("((window.top == null || window.top === window) ? window : window.top)." + InterceptAjaxRequestJS.FLAG_VARIABLE_FOR_ON_AJAX_READY_STATE_CHANGE() + " = " + newCustomSettings.useOnAjaxReadyStateChange + ";", null); - } - - if (newSettingsMap.get("useOnAjaxProgress") != null && customSettings.useOnAjaxProgress != newCustomSettings.useOnAjaxProgress) { - evaluateJavascript("((window.top == null || window.top === window) ? window : window.top)." + InterceptAjaxRequestJS.FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS() + " = " + newCustomSettings.useOnAjaxProgress + ";", null); - } - - if (newSettingsMap.get("interceptOnlyAsyncAjaxRequests") != null && customSettings.interceptOnlyAsyncAjaxRequests != newCustomSettings.interceptOnlyAsyncAjaxRequests) { - enablePluginScriptAtRuntime( - InterceptAjaxRequestJS.FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE(), - newCustomSettings.interceptOnlyAsyncAjaxRequests, - interceptOnlyAsyncAjaxRequestsPluginScript - ); - } - - if (newSettingsMap.get("useShouldInterceptFetchRequest") != null && customSettings.useShouldInterceptFetchRequest != newCustomSettings.useShouldInterceptFetchRequest) { - enablePluginScriptAtRuntime( - InterceptFetchRequestJS.FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE(), - newCustomSettings.useShouldInterceptFetchRequest, - InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList, - customSettings.pluginScriptsForMainFrameOnly) - ); - } - - if (newSettingsMap.get("useOnLoadResource") != null && customSettings.useOnLoadResource != newCustomSettings.useOnLoadResource) { - enablePluginScriptAtRuntime( - OnLoadResourceJS.FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE(), - newCustomSettings.useOnLoadResource, - OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList, - customSettings.pluginScriptsForMainFrameOnly) - ); - } - - if (newSettingsMap.get("javaScriptCanOpenWindowsAutomatically") != null && customSettings.javaScriptCanOpenWindowsAutomatically != newCustomSettings.javaScriptCanOpenWindowsAutomatically) - settings.setJavaScriptCanOpenWindowsAutomatically(newCustomSettings.javaScriptCanOpenWindowsAutomatically); - - if (newSettingsMap.get("builtInZoomControls") != null && customSettings.builtInZoomControls != newCustomSettings.builtInZoomControls) - settings.setBuiltInZoomControls(newCustomSettings.builtInZoomControls); - - if (newSettingsMap.get("displayZoomControls") != null && customSettings.displayZoomControls != newCustomSettings.displayZoomControls) - settings.setDisplayZoomControls(newCustomSettings.displayZoomControls); - - if (newSettingsMap.get("safeBrowsingEnabled") != null && customSettings.safeBrowsingEnabled != newCustomSettings.safeBrowsingEnabled) { - if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_ENABLE)) - WebSettingsCompat.setSafeBrowsingEnabled(settings, newCustomSettings.safeBrowsingEnabled); - else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) - settings.setSafeBrowsingEnabled(newCustomSettings.safeBrowsingEnabled); - } - - if (newSettingsMap.get("mediaPlaybackRequiresUserGesture") != null && customSettings.mediaPlaybackRequiresUserGesture != newCustomSettings.mediaPlaybackRequiresUserGesture) - settings.setMediaPlaybackRequiresUserGesture(newCustomSettings.mediaPlaybackRequiresUserGesture); - - if (newSettingsMap.get("databaseEnabled") != null && customSettings.databaseEnabled != newCustomSettings.databaseEnabled) - settings.setDatabaseEnabled(newCustomSettings.databaseEnabled); - - if (newSettingsMap.get("domStorageEnabled") != null && customSettings.domStorageEnabled != newCustomSettings.domStorageEnabled) - settings.setDomStorageEnabled(newCustomSettings.domStorageEnabled); - - if (newSettingsMap.get("userAgent") != null && !customSettings.userAgent.equals(newCustomSettings.userAgent) && !newCustomSettings.userAgent.isEmpty()) - settings.setUserAgentString(newCustomSettings.userAgent); - - if (newSettingsMap.get("applicationNameForUserAgent") != null && !customSettings.applicationNameForUserAgent.equals(newCustomSettings.applicationNameForUserAgent) && !newCustomSettings.applicationNameForUserAgent.isEmpty()) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - String userAgent = (newCustomSettings.userAgent != null && !newCustomSettings.userAgent.isEmpty()) ? newCustomSettings.userAgent : WebSettings.getDefaultUserAgent(getContext()); - String userAgentWithApplicationName = userAgent + " " + customSettings.applicationNameForUserAgent; - settings.setUserAgentString(userAgentWithApplicationName); - } - } - - if (newSettingsMap.get("clearCache") != null && newCustomSettings.clearCache) - clearAllCache(); - else if (newSettingsMap.get("clearSessionCache") != null && newCustomSettings.clearSessionCache) - CookieManager.getInstance().removeSessionCookie(); - - if (newSettingsMap.get("thirdPartyCookiesEnabled") != null && customSettings.thirdPartyCookiesEnabled != newCustomSettings.thirdPartyCookiesEnabled && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - CookieManager.getInstance().setAcceptThirdPartyCookies(this, newCustomSettings.thirdPartyCookiesEnabled); - - if (newSettingsMap.get("useWideViewPort") != null && customSettings.useWideViewPort != newCustomSettings.useWideViewPort) - settings.setUseWideViewPort(newCustomSettings.useWideViewPort); - - if (newSettingsMap.get("supportZoom") != null && customSettings.supportZoom != newCustomSettings.supportZoom) - settings.setSupportZoom(newCustomSettings.supportZoom); - - if (newSettingsMap.get("textZoom") != null && (customSettings.textZoom == null || !customSettings.textZoom.equals(newCustomSettings.textZoom))) - settings.setTextZoom(newCustomSettings.textZoom); - - if (newSettingsMap.get("verticalScrollBarEnabled") != null && customSettings.verticalScrollBarEnabled != newCustomSettings.verticalScrollBarEnabled) - setVerticalScrollBarEnabled(newCustomSettings.verticalScrollBarEnabled); - - if (newSettingsMap.get("horizontalScrollBarEnabled") != null && customSettings.horizontalScrollBarEnabled != newCustomSettings.horizontalScrollBarEnabled) - setHorizontalScrollBarEnabled(newCustomSettings.horizontalScrollBarEnabled); - - if (newSettingsMap.get("transparentBackground") != null && customSettings.transparentBackground != newCustomSettings.transparentBackground) { - if (newCustomSettings.transparentBackground) { - setBackgroundColor(Color.TRANSPARENT); - } else { - setBackgroundColor(Color.parseColor("#FFFFFF")); - } - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - if (newSettingsMap.get("mixedContentMode") != null && (customSettings.mixedContentMode == null || !customSettings.mixedContentMode.equals(newCustomSettings.mixedContentMode))) - settings.setMixedContentMode(newCustomSettings.mixedContentMode); - - if (newSettingsMap.get("supportMultipleWindows") != null && customSettings.supportMultipleWindows != newCustomSettings.supportMultipleWindows) - settings.setSupportMultipleWindows(newCustomSettings.supportMultipleWindows); - - if (newSettingsMap.get("useOnDownloadStart") != null && customSettings.useOnDownloadStart != newCustomSettings.useOnDownloadStart) { - if (newCustomSettings.useOnDownloadStart) { - setDownloadListener(new DownloadStartListener()); - } else { - setDownloadListener(null); - } - } - - if (newSettingsMap.get("allowContentAccess") != null && customSettings.allowContentAccess != newCustomSettings.allowContentAccess) - settings.setAllowContentAccess(newCustomSettings.allowContentAccess); - - if (newSettingsMap.get("allowFileAccess") != null && customSettings.allowFileAccess != newCustomSettings.allowFileAccess) - settings.setAllowFileAccess(newCustomSettings.allowFileAccess); - - if (newSettingsMap.get("allowFileAccessFromFileURLs") != null && customSettings.allowFileAccessFromFileURLs != newCustomSettings.allowFileAccessFromFileURLs) - settings.setAllowFileAccessFromFileURLs(newCustomSettings.allowFileAccessFromFileURLs); - - if (newSettingsMap.get("allowUniversalAccessFromFileURLs") != null && customSettings.allowUniversalAccessFromFileURLs != newCustomSettings.allowUniversalAccessFromFileURLs) - settings.setAllowUniversalAccessFromFileURLs(newCustomSettings.allowUniversalAccessFromFileURLs); - - if (newSettingsMap.get("cacheEnabled") != null && customSettings.cacheEnabled != newCustomSettings.cacheEnabled) - setCacheEnabled(newCustomSettings.cacheEnabled); - - if (newSettingsMap.get("appCachePath") != null && (customSettings.appCachePath == null || !customSettings.appCachePath.equals(newCustomSettings.appCachePath))) { - // removed from Android API 33+ (https://developer.android.com/sdk/api_diff/33/changes) - // settings.setAppCachePath(newCustomSettings.appCachePath); - Util.invokeMethodIfExists(settings, "setAppCachePath", newCustomSettings.appCachePath); - } - - if (newSettingsMap.get("blockNetworkImage") != null && customSettings.blockNetworkImage != newCustomSettings.blockNetworkImage) - settings.setBlockNetworkImage(newCustomSettings.blockNetworkImage); - - if (newSettingsMap.get("blockNetworkLoads") != null && customSettings.blockNetworkLoads != newCustomSettings.blockNetworkLoads) - settings.setBlockNetworkLoads(newCustomSettings.blockNetworkLoads); - - if (newSettingsMap.get("cacheMode") != null && !customSettings.cacheMode.equals(newCustomSettings.cacheMode)) - settings.setCacheMode(newCustomSettings.cacheMode); - - if (newSettingsMap.get("cursiveFontFamily") != null && !customSettings.cursiveFontFamily.equals(newCustomSettings.cursiveFontFamily)) - settings.setCursiveFontFamily(newCustomSettings.cursiveFontFamily); - - if (newSettingsMap.get("defaultFixedFontSize") != null && !customSettings.defaultFixedFontSize.equals(newCustomSettings.defaultFixedFontSize)) - settings.setDefaultFixedFontSize(newCustomSettings.defaultFixedFontSize); - - if (newSettingsMap.get("defaultFontSize") != null && !customSettings.defaultFontSize.equals(newCustomSettings.defaultFontSize)) - settings.setDefaultFontSize(newCustomSettings.defaultFontSize); - - if (newSettingsMap.get("defaultTextEncodingName") != null && !customSettings.defaultTextEncodingName.equals(newCustomSettings.defaultTextEncodingName)) - settings.setDefaultTextEncodingName(newCustomSettings.defaultTextEncodingName); - - if (newSettingsMap.get("disabledActionModeMenuItems") != null && - (customSettings.disabledActionModeMenuItems == null || - !customSettings.disabledActionModeMenuItems.equals(newCustomSettings.disabledActionModeMenuItems))) { - if (WebViewFeature.isFeatureSupported(WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS)) - WebSettingsCompat.setDisabledActionModeMenuItems(settings, newCustomSettings.disabledActionModeMenuItems); - else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - settings.setDisabledActionModeMenuItems(newCustomSettings.disabledActionModeMenuItems); - } - - if (newSettingsMap.get("fantasyFontFamily") != null && !customSettings.fantasyFontFamily.equals(newCustomSettings.fantasyFontFamily)) - settings.setFantasyFontFamily(newCustomSettings.fantasyFontFamily); - - if (newSettingsMap.get("fixedFontFamily") != null && !customSettings.fixedFontFamily.equals(newCustomSettings.fixedFontFamily)) - settings.setFixedFontFamily(newCustomSettings.fixedFontFamily); - - if (newSettingsMap.get("forceDark") != null && !Util.objEquals(customSettings.forceDark, newCustomSettings.forceDark)) { - if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) - WebSettingsCompat.setForceDark(settings, newCustomSettings.forceDark); - else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) - settings.setForceDark(newCustomSettings.forceDark); - } - - if (newSettingsMap.get("forceDarkStrategy") != null && - !Util.objEquals(customSettings.forceDarkStrategy, newCustomSettings.forceDarkStrategy) && - WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) { - try { - // for some reason the setForceDarkStrategy method could throw a ClassCastException - // from the Android WebView Chromium library. - WebSettingsCompat.setForceDarkStrategy(settings, newCustomSettings.forceDarkStrategy); - } catch (Exception e) { - e.printStackTrace(); - } - } - - if (newSettingsMap.get("geolocationEnabled") != null && customSettings.geolocationEnabled != newCustomSettings.geolocationEnabled) - settings.setGeolocationEnabled(newCustomSettings.geolocationEnabled); - - if (newSettingsMap.get("layoutAlgorithm") != null && customSettings.layoutAlgorithm != newCustomSettings.layoutAlgorithm) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && newCustomSettings.layoutAlgorithm.equals(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING)) { - settings.setLayoutAlgorithm(newCustomSettings.layoutAlgorithm); - } else { - settings.setLayoutAlgorithm(newCustomSettings.layoutAlgorithm); - } - } - - if (newSettingsMap.get("loadWithOverviewMode") != null && customSettings.loadWithOverviewMode != newCustomSettings.loadWithOverviewMode) - settings.setLoadWithOverviewMode(newCustomSettings.loadWithOverviewMode); - - if (newSettingsMap.get("loadsImagesAutomatically") != null && customSettings.loadsImagesAutomatically != newCustomSettings.loadsImagesAutomatically) - settings.setLoadsImagesAutomatically(newCustomSettings.loadsImagesAutomatically); - - if (newSettingsMap.get("minimumFontSize") != null && !customSettings.minimumFontSize.equals(newCustomSettings.minimumFontSize)) - settings.setMinimumFontSize(newCustomSettings.minimumFontSize); - - if (newSettingsMap.get("minimumLogicalFontSize") != null && !customSettings.minimumLogicalFontSize.equals(newCustomSettings.minimumLogicalFontSize)) - settings.setMinimumLogicalFontSize(newCustomSettings.minimumLogicalFontSize); - - if (newSettingsMap.get("initialScale") != null && !customSettings.initialScale.equals(newCustomSettings.initialScale)) - setInitialScale(newCustomSettings.initialScale); - - if (newSettingsMap.get("needInitialFocus") != null && customSettings.needInitialFocus != newCustomSettings.needInitialFocus) - settings.setNeedInitialFocus(newCustomSettings.needInitialFocus); - - if (newSettingsMap.get("offscreenPreRaster") != null && customSettings.offscreenPreRaster != newCustomSettings.offscreenPreRaster) { - if (WebViewFeature.isFeatureSupported(WebViewFeature.OFF_SCREEN_PRERASTER)) - WebSettingsCompat.setOffscreenPreRaster(settings, newCustomSettings.offscreenPreRaster); - else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) - settings.setOffscreenPreRaster(newCustomSettings.offscreenPreRaster); - } - - if (newSettingsMap.get("sansSerifFontFamily") != null && !customSettings.sansSerifFontFamily.equals(newCustomSettings.sansSerifFontFamily)) - settings.setSansSerifFontFamily(newCustomSettings.sansSerifFontFamily); - - if (newSettingsMap.get("serifFontFamily") != null && !customSettings.serifFontFamily.equals(newCustomSettings.serifFontFamily)) - settings.setSerifFontFamily(newCustomSettings.serifFontFamily); - - if (newSettingsMap.get("standardFontFamily") != null && !customSettings.standardFontFamily.equals(newCustomSettings.standardFontFamily)) - settings.setStandardFontFamily(newCustomSettings.standardFontFamily); - - if (newSettingsMap.get("preferredContentMode") != null && !customSettings.preferredContentMode.equals(newCustomSettings.preferredContentMode)) { - switch (fromValue(newCustomSettings.preferredContentMode)) { - case DESKTOP: - setDesktopMode(true); - break; - case MOBILE: - case RECOMMENDED: - setDesktopMode(false); - break; - } - } - - if (newSettingsMap.get("saveFormData") != null && customSettings.saveFormData != newCustomSettings.saveFormData) - settings.setSaveFormData(newCustomSettings.saveFormData); - - if (newSettingsMap.get("incognito") != null && customSettings.incognito != newCustomSettings.incognito) - setIncognito(newCustomSettings.incognito); - - if (customSettings.useHybridComposition) { - if (newSettingsMap.get("hardwareAcceleration") != null && customSettings.hardwareAcceleration != newCustomSettings.hardwareAcceleration) { - if (newCustomSettings.hardwareAcceleration) - setLayerType(View.LAYER_TYPE_HARDWARE, null); - else - setLayerType(View.LAYER_TYPE_NONE, null); - } - } - - if (newCustomSettings.contentBlockers != null) { - contentBlockerHandler.getRuleList().clear(); - for (Map> contentBlocker : newCustomSettings.contentBlockers) { - // compile ContentBlockerTrigger urlFilter - ContentBlockerTrigger trigger = ContentBlockerTrigger.fromMap(contentBlocker.get("trigger")); - ContentBlockerAction action = ContentBlockerAction.fromMap(contentBlocker.get("action")); - contentBlockerHandler.getRuleList().add(new ContentBlocker(trigger, action)); - } - } - - if (newSettingsMap.get("scrollBarStyle") != null && !customSettings.scrollBarStyle.equals(newCustomSettings.scrollBarStyle)) - setScrollBarStyle(newCustomSettings.scrollBarStyle); - - if (newSettingsMap.get("scrollBarDefaultDelayBeforeFade") != null && (customSettings.scrollBarDefaultDelayBeforeFade == null || - !customSettings.scrollBarDefaultDelayBeforeFade.equals(newCustomSettings.scrollBarDefaultDelayBeforeFade))) - setScrollBarDefaultDelayBeforeFade(newCustomSettings.scrollBarDefaultDelayBeforeFade); - - if (newSettingsMap.get("scrollbarFadingEnabled") != null && !customSettings.scrollbarFadingEnabled.equals(newCustomSettings.scrollbarFadingEnabled)) - setScrollbarFadingEnabled(newCustomSettings.scrollbarFadingEnabled); - - if (newSettingsMap.get("scrollBarFadeDuration") != null && (customSettings.scrollBarFadeDuration == null || - !customSettings.scrollBarFadeDuration.equals(newCustomSettings.scrollBarFadeDuration))) - setScrollBarFadeDuration(newCustomSettings.scrollBarFadeDuration); - - if (newSettingsMap.get("verticalScrollbarPosition") != null && !customSettings.verticalScrollbarPosition.equals(newCustomSettings.verticalScrollbarPosition)) - setVerticalScrollbarPosition(newCustomSettings.verticalScrollbarPosition); - - if (newSettingsMap.get("disableVerticalScroll") != null && customSettings.disableVerticalScroll != newCustomSettings.disableVerticalScroll) - setVerticalScrollBarEnabled(!newCustomSettings.disableVerticalScroll && newCustomSettings.verticalScrollBarEnabled); - - if (newSettingsMap.get("disableHorizontalScroll") != null && customSettings.disableHorizontalScroll != newCustomSettings.disableHorizontalScroll) - setHorizontalScrollBarEnabled(!newCustomSettings.disableHorizontalScroll && newCustomSettings.horizontalScrollBarEnabled); - - if (newSettingsMap.get("overScrollMode") != null && !customSettings.overScrollMode.equals(newCustomSettings.overScrollMode)) - setOverScrollMode(newCustomSettings.overScrollMode); - - if (newSettingsMap.get("networkAvailable") != null && customSettings.networkAvailable != newCustomSettings.networkAvailable) - setNetworkAvailable(newCustomSettings.networkAvailable); - - if (newSettingsMap.get("rendererPriorityPolicy") != null && (customSettings.rendererPriorityPolicy == null || - (customSettings.rendererPriorityPolicy.get("rendererRequestedPriority") != newCustomSettings.rendererPriorityPolicy.get("rendererRequestedPriority") || - customSettings.rendererPriorityPolicy.get("waivedWhenNotVisible") != newCustomSettings.rendererPriorityPolicy.get("waivedWhenNotVisible"))) && - Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - setRendererPriorityPolicy( - (int) newCustomSettings.rendererPriorityPolicy.get("rendererRequestedPriority"), - (boolean) newCustomSettings.rendererPriorityPolicy.get("waivedWhenNotVisible")); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - if (newSettingsMap.get("verticalScrollbarThumbColor") != null && !Util.objEquals(customSettings.verticalScrollbarThumbColor, newCustomSettings.verticalScrollbarThumbColor)) - setVerticalScrollbarThumbDrawable(new ColorDrawable(Color.parseColor(newCustomSettings.verticalScrollbarThumbColor))); - - if (newSettingsMap.get("verticalScrollbarTrackColor") != null && !Util.objEquals(customSettings.verticalScrollbarTrackColor, newCustomSettings.verticalScrollbarTrackColor)) - setVerticalScrollbarTrackDrawable(new ColorDrawable(Color.parseColor(newCustomSettings.verticalScrollbarTrackColor))); - - if (newSettingsMap.get("horizontalScrollbarThumbColor") != null && !Util.objEquals(customSettings.horizontalScrollbarThumbColor, newCustomSettings.horizontalScrollbarThumbColor)) - setHorizontalScrollbarThumbDrawable(new ColorDrawable(Color.parseColor(newCustomSettings.horizontalScrollbarThumbColor))); - - if (newSettingsMap.get("horizontalScrollbarTrackColor") != null && !Util.objEquals(customSettings.horizontalScrollbarTrackColor, newCustomSettings.horizontalScrollbarTrackColor)) - setHorizontalScrollbarTrackDrawable(new ColorDrawable(Color.parseColor(newCustomSettings.horizontalScrollbarTrackColor))); - } - - if (newSettingsMap.get("algorithmicDarkeningAllowed") != null && - !Util.objEquals(customSettings.algorithmicDarkeningAllowed, newCustomSettings.algorithmicDarkeningAllowed) && - WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - WebSettingsCompat.setAlgorithmicDarkeningAllowed(settings, newCustomSettings.algorithmicDarkeningAllowed); - } - if (newSettingsMap.get("enterpriseAuthenticationAppLinkPolicyEnabled") != null && - !Util.objEquals(customSettings.enterpriseAuthenticationAppLinkPolicyEnabled, newCustomSettings.enterpriseAuthenticationAppLinkPolicyEnabled) && - WebViewFeature.isFeatureSupported(WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY)) { - WebSettingsCompat.setEnterpriseAuthenticationAppLinkPolicyEnabled(settings, newCustomSettings.enterpriseAuthenticationAppLinkPolicyEnabled); - } - if (newSettingsMap.get("requestedWithHeaderOriginAllowList") != null && - !Util.objEquals(customSettings.requestedWithHeaderOriginAllowList, newCustomSettings.requestedWithHeaderOriginAllowList) && - WebViewFeature.isFeatureSupported(WebViewFeature.REQUESTED_WITH_HEADER_ALLOW_LIST)) { - WebSettingsCompat.setRequestedWithHeaderOriginAllowList(settings, newCustomSettings.requestedWithHeaderOriginAllowList); - } - - if (plugin != null) { - if (webViewAssetLoaderExt != null) { - webViewAssetLoaderExt.dispose(); - } - webViewAssetLoaderExt = WebViewAssetLoaderExt.fromMap(customSettings.webViewAssetLoader, plugin, getContext()); - } - - customSettings = newCustomSettings; - } - - public Map getCustomSettingsMap() { - return (customSettings != null) ? customSettings.getRealSettings(this) : null; - } - - public void enablePluginScriptAtRuntime(final String flagVariable, - final boolean enable, - final PluginScript pluginScript) { - evaluateJavascript("((window.top == null || window.top === window) ? window : window.top)." + flagVariable, null, new ValueCallback() { - @Override - public void onReceiveValue(String value) { - boolean alreadyLoaded = value != null && !value.equalsIgnoreCase("null"); - if (alreadyLoaded) { - String enableSource = "((window.top == null || window.top === window) ? window : window.top)." + flagVariable + " = " + enable + ";"; - evaluateJavascript(enableSource, null, null); - if (!enable) { - userContentController.removePluginScript(pluginScript); - } - } else if (enable && javaScriptBridgeEnabled) { - evaluateJavascript(pluginScript.getSource(), null, null); - userContentController.addPluginScript(pluginScript); - } - } - }); - } - - public void injectDeferredObject(String source, @Nullable final ContentWorld contentWorld, String jsWrapper, @Nullable final ValueCallback resultCallback) { - final String resultUuid = contentWorld != null && !contentWorld.equals(ContentWorld.PAGE) ? UUID.randomUUID().toString() : null; - String scriptToInject = source; - if (jsWrapper != null) { - org.json.JSONArray jsonEsc = new org.json.JSONArray(); - jsonEsc.put(source); - String jsonRepr = jsonEsc.toString(); - String jsonSourceString = jsonRepr.substring(1, jsonRepr.length() - 1); - scriptToInject = String.format(jsWrapper, jsonSourceString); - } - if (resultUuid != null && resultCallback != null) { - evaluateJavaScriptContentWorldCallbacks.put(resultUuid, resultCallback); - scriptToInject = Util.replaceAll(PluginScriptsUtil.EVALUATE_JAVASCRIPT_WITH_CONTENT_WORLD_WRAPPER_JS_SOURCE(), - PluginScriptsUtil.VAR_RANDOM_NAME, "_" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_" + Math.round(Math.random() * 1000000)) - .replace(PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, UserContentController.escapeCode(source)) - .replace(PluginScriptsUtil.VAR_RESULT_UUID, resultUuid); - } - final String finalScriptToInject = scriptToInject; - mainLooperHandler.post(new Runnable() { - @Override - public void run() { - String scriptToInject = userContentController.generateCodeForScriptEvaluation(finalScriptToInject, contentWorld); - evaluateJavascript(scriptToInject, new ValueCallback() { - @Override - public void onReceiveValue(String s) { - if (resultUuid != null || resultCallback == null) - return; - resultCallback.onReceiveValue(s); - } - }); - } - }); - } - - public void evaluateJavascript(String source, @Nullable ContentWorld contentWorld, @Nullable ValueCallback resultCallback) { - injectDeferredObject(source, contentWorld, null, resultCallback); - } - - public void injectJavascriptFileFromUrl(String urlFile, @Nullable Map scriptHtmlTagAttributes) { - String scriptAttributes = ""; - if (scriptHtmlTagAttributes != null) { - String typeAttr = (String) scriptHtmlTagAttributes.get("type"); - if (typeAttr != null) { - scriptAttributes += " script.type = '" + typeAttr.replaceAll("'", "\\\\'") + "'; "; - } - String idAttr = (String) scriptHtmlTagAttributes.get("id"); - if (idAttr != null) { - String scriptIdEscaped = idAttr.replaceAll("'", "\\\\'"); - scriptAttributes += " script.id = '" + scriptIdEscaped + "'; "; - scriptAttributes += " script.onload = function() {" + - " if (window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + " != null) {" + - " window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onInjectedScriptLoaded', '" + scriptIdEscaped + "');" + - " }" + - "};"; - scriptAttributes += " script.onerror = function() {" + - " if (window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + " != null) {" + - " window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onInjectedScriptError', '" + scriptIdEscaped + "');" + - " }" + - "};"; - } - Boolean asyncAttr = (Boolean) scriptHtmlTagAttributes.get("async"); - if (asyncAttr != null && asyncAttr) { - scriptAttributes += " script.async = true; "; - } - Boolean deferAttr = (Boolean) scriptHtmlTagAttributes.get("defer"); - if (deferAttr != null && deferAttr) { - scriptAttributes += " script.defer = true; "; - } - String crossOriginAttr = (String) scriptHtmlTagAttributes.get("crossOrigin"); - if (crossOriginAttr != null) { - scriptAttributes += " script.crossOrigin = '" + crossOriginAttr.replaceAll("'", "\\\\'") + "'; "; - } - String integrityAttr = (String) scriptHtmlTagAttributes.get("integrity"); - if (integrityAttr != null) { - scriptAttributes += " script.integrity = '" + integrityAttr.replaceAll("'", "\\\\'") + "'; "; - } - Boolean noModuleAttr = (Boolean) scriptHtmlTagAttributes.get("noModule"); - if (noModuleAttr != null && noModuleAttr) { - scriptAttributes += " script.noModule = true; "; - } - String nonceAttr = (String) scriptHtmlTagAttributes.get("nonce"); - if (nonceAttr != null) { - scriptAttributes += " script.nonce = '" + nonceAttr.replaceAll("'", "\\\\'") + "'; "; - } - String referrerPolicyAttr = (String) scriptHtmlTagAttributes.get("referrerPolicy"); - if (referrerPolicyAttr != null) { - scriptAttributes += " script.referrerPolicy = '" + referrerPolicyAttr.replaceAll("'", "\\\\'") + "'; "; - } - } - String jsWrapper = "(function(d) { var script = d.createElement('script'); " + scriptAttributes + - " script.src = %s; if (d.body != null) { d.body.appendChild(script); } })(document);"; - injectDeferredObject(urlFile, null, jsWrapper, null); - } - - public void injectCSSCode(String source) { - String jsWrapper = "(function(d) { var style = d.createElement('style'); style.innerHTML = %s;" + - " if (d.head != null) { d.head.appendChild(style); } })(document);"; - injectDeferredObject(source, null, jsWrapper, null); - } - - public void injectCSSFileFromUrl(String urlFile, @Nullable Map cssLinkHtmlTagAttributes) { - String cssLinkAttributes = ""; - String alternateStylesheet = ""; - if (cssLinkHtmlTagAttributes != null) { - String idAttr = (String) cssLinkHtmlTagAttributes.get("id"); - if (idAttr != null) { - cssLinkAttributes += " link.id = '" + idAttr.replaceAll("'", "\\\\'") + "'; "; - } - String mediaAttr = (String) cssLinkHtmlTagAttributes.get("media"); - if (mediaAttr != null) { - cssLinkAttributes += " link.media = '" + mediaAttr.replaceAll("'", "\\\\'") + "'; "; - } - String crossOriginAttr = (String) cssLinkHtmlTagAttributes.get("crossOrigin"); - if (crossOriginAttr != null) { - cssLinkAttributes += " link.crossOrigin = '" + crossOriginAttr.replaceAll("'", "\\\\'") + "'; "; - } - String integrityAttr = (String) cssLinkHtmlTagAttributes.get("integrity"); - if (integrityAttr != null) { - cssLinkAttributes += " link.integrity = '" + integrityAttr.replaceAll("'", "\\\\'") + "'; "; - } - String referrerPolicyAttr = (String) cssLinkHtmlTagAttributes.get("referrerPolicy"); - if (referrerPolicyAttr != null) { - cssLinkAttributes += " link.referrerPolicy = '" + referrerPolicyAttr.replaceAll("'", "\\\\'") + "'; "; - } - Boolean disabledAttr = (Boolean) cssLinkHtmlTagAttributes.get("disabled"); - if (disabledAttr != null && disabledAttr) { - cssLinkAttributes += " link.disabled = true; "; - } - Boolean alternateAttr = (Boolean) cssLinkHtmlTagAttributes.get("alternate"); - if (alternateAttr != null && alternateAttr) { - alternateStylesheet = "alternate "; - } - String titleAttr = (String) cssLinkHtmlTagAttributes.get("title"); - if (titleAttr != null) { - cssLinkAttributes += " link.title = '" + titleAttr.replaceAll("'", "\\\\'") + "'; "; - } - } - String jsWrapper = "(function(d) { var link = d.createElement('link'); link.rel='" + alternateStylesheet + "stylesheet'; link.type='text/css'; " + - cssLinkAttributes + " link.href = %s; if (d.head != null) { d.head.appendChild(link); } })(document);"; - injectDeferredObject(urlFile, null, jsWrapper, null); - } - - public HashMap getCopyBackForwardList() { - WebBackForwardList currentList = copyBackForwardList(); - int currentSize = currentList.getSize(); - int currentIndex = currentList.getCurrentIndex(); - - List> history = new ArrayList>(); - - for (int i = 0; i < currentSize; i++) { - WebHistoryItem historyItem = currentList.getItemAtIndex(i); - HashMap historyItemMap = new HashMap<>(); - - historyItemMap.put("originalUrl", historyItem.getOriginalUrl()); - historyItemMap.put("title", historyItem.getTitle()); - historyItemMap.put("url", historyItem.getUrl()); - historyItemMap.put("index", i); - historyItemMap.put("offset", i - currentIndex); - - history.add(historyItemMap); - } - - HashMap result = new HashMap<>(); - - result.put("list", history); - result.put("currentIndex", currentIndex); - - return result; - } - - @Override - protected void onScrollChanged(int x, - int y, - int oldX, - int oldY) { - super.onScrollChanged(x, y, oldX, oldY); - - if (floatingContextMenu != null) { - floatingContextMenu.setAlpha(0f); - floatingContextMenu.setVisibility(View.GONE); - } - - if (channelDelegate != null) channelDelegate.onScrollChanged(x, y); - } - - public void scrollTo(Integer x, Integer y, Boolean animated) { - if (animated) { - PropertyValuesHolder pvhX = PropertyValuesHolder.ofInt("scrollX", x); - PropertyValuesHolder pvhY = PropertyValuesHolder.ofInt("scrollY", y); - ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(this, pvhX, pvhY); - anim.setDuration(300).start(); - } else { - scrollTo(x, y); - } - } - - public void scrollBy(Integer x, Integer y, Boolean animated) { - if (animated) { - PropertyValuesHolder pvhX = PropertyValuesHolder.ofInt("scrollX", getScrollX() + x); - PropertyValuesHolder pvhY = PropertyValuesHolder.ofInt("scrollY", getScrollY() + y); - ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(this, pvhX, pvhY); - anim.setDuration(300).start(); - } else { - scrollBy(x, y); - } - } - - class DownloadStartListener implements DownloadListener { - @Override - public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) { - DownloadStartRequest downloadStartRequest = new DownloadStartRequest( - url, - userAgent, - contentDisposition, - mimeType, - contentLength, - URLUtil.guessFileName(url, contentDisposition, mimeType), - null - ); - if (channelDelegate != null) channelDelegate.onDownloadStarting(downloadStartRequest); - } - } - - public void setDesktopMode(final boolean enabled) { - final WebSettings webSettings = getSettings(); - - final String newUserAgent; - if (enabled) { - newUserAgent = webSettings.getUserAgentString().replace("Mobile", "eliboM").replace("Android", "diordnA"); - } else { - newUserAgent = webSettings.getUserAgentString().replace("eliboM", "Mobile").replace("diordnA", "Android"); - } - - webSettings.setUserAgentString(newUserAgent); - webSettings.setUseWideViewPort(enabled); - webSettings.setLoadWithOverviewMode(enabled); - webSettings.setSupportZoom(enabled); - webSettings.setBuiltInZoomControls(enabled); - } - - @Nullable - public String printCurrentPage(@Nullable PrintJobSettings settings) { - if (plugin != null && plugin.activity != null) { - // Get a PrintManager instance - PrintManager printManager = (PrintManager) plugin.activity.getSystemService(Context.PRINT_SERVICE); - - if (printManager != null) { - PrintAttributes.Builder builder = new PrintAttributes.Builder(); - - String jobName = (getTitle() != null ? getTitle() : getUrl()) + " Document"; - - if (settings != null) { - if (settings.jobName != null && !settings.jobName.isEmpty()) { - jobName = settings.jobName; - } - if (settings.orientation != null) { - int orientation = settings.orientation; - switch (orientation) { - case 0: - // PORTRAIT - builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_PORTRAIT); - break; - case 1: - // LANDSCAPE - builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE); - break; - } - } -// if (settings.margins != null) { -// // for some reason, Android doesn't set the margins -// builder.setMinMargins(settings.margins.toMargins()); -// } - if (settings.mediaSize != null) { - builder.setMediaSize(settings.mediaSize.toMediaSize()); - } - if (settings.colorMode != null) { - builder.setColorMode(settings.colorMode); - } - if (settings.duplexMode != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - builder.setDuplexMode(settings.duplexMode); - } - if (settings.resolution != null) { - builder.setResolution(settings.resolution.toResolution()); - } - } - - // Get a printCurrentPage adapter instance - PrintDocumentAdapter printAdapter; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - printAdapter = createPrintDocumentAdapter(jobName); - } else { - printAdapter = createPrintDocumentAdapter(); - } - - PrintJobController printJobController = null; - String id = null; - - if (settings != null && settings.handledByClient && plugin.printJobManager != null) { - id = UUID.randomUUID().toString(); - printJobController = new PrintJobController(id, settings, plugin); - plugin.printJobManager.jobs.put(printJobController.id, printJobController); - final PrintJobController finalPrintJobController = printJobController; - printAdapter = new InAppWebViewPrintDocumentAdapter(printAdapter, new InAppWebViewPrintDocumentAdapter.PrintDocumentAdapterCallback() { - @Override - public void onFinish() { - finalPrintJobController.onComplete(true, null); - } - }); - } - - // Create a printCurrentPage job with name and adapter instance - PrintJob job = printManager.print(jobName, printAdapter, builder.build()); - if (printJobController != null) printJobController.setJob(job); - - return id; - } else { - Log.e(LOG_TAG, "No PrintManager available"); - } - } - return null; - } - - @Override - public void onCreateContextMenu(ContextMenu menu) { - super.onCreateContextMenu(menu); - sendOnCreateContextMenuEvent(); - } - - private void sendOnCreateContextMenuEvent() { - com.pichillilorenzo.flutter_inappwebview_android.types.HitTestResult hitTestResult = - com.pichillilorenzo.flutter_inappwebview_android.types.HitTestResult.fromWebViewHitTestResult(getHitTestResult()); - if (channelDelegate != null) channelDelegate.onCreateContextMenu(hitTestResult); - } - - private Point contextMenuPoint = new Point(0, 0); - private Point lastTouch = new Point(0, 0); - - @Override - public boolean onTouchEvent(MotionEvent ev) { - if (!customSettings.isUserInteractionEnabled) { - return true; - } - - lastTouch = new Point((int) ev.getX(), (int) ev.getY()); - - ViewParent parent = getParent(); - if (parent instanceof PullToRefreshLayout) { - PullToRefreshLayout pullToRefreshLayout = (PullToRefreshLayout) parent; - if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { - pullToRefreshLayout.setEnabled(false); - } - } - - return super.onTouchEvent(ev); - } - - @Override - protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { - super.onOverScrolled(scrollX, scrollY, clampedX, clampedY); - - boolean overScrolledHorizontally = canScrollHorizontally() && clampedX; - boolean overScrolledVertically = canScrollVertically() && clampedY; - - ViewParent parent = getParent(); - if (parent instanceof PullToRefreshLayout && overScrolledVertically && scrollY <= 10) { - PullToRefreshLayout pullToRefreshLayout = (PullToRefreshLayout) parent; - // change over scroll mode to OVER_SCROLL_NEVER in order to disable temporarily the glow effect - setOverScrollMode(OVER_SCROLL_NEVER); - pullToRefreshLayout.setEnabled(pullToRefreshLayout.settings.enabled); - // reset over scroll mode - setOverScrollMode(customSettings.overScrollMode); - } - - if (overScrolledHorizontally || overScrolledVertically) { - if (channelDelegate != null) - channelDelegate.onOverScrolled(scrollX, scrollY, overScrolledHorizontally, overScrolledVertically); - } - } - - @Override - public boolean dispatchTouchEvent(MotionEvent event) { - return super.dispatchTouchEvent(event); - } - - @Override - public InputConnection onCreateInputConnection(EditorInfo outAttrs) { - InputConnection connection = super.onCreateInputConnection(outAttrs); - if (connection == null && !customSettings.useHybridComposition && containerView != null) { - // workaround to hide the Keyboard when the user click outside - // on something not focusable such as input or a textarea. - containerView - .getHandler() - .postDelayed( - new Runnable() { - @Override - public void run() { - InputMethodManager imm = - (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE); - - boolean isAcceptingText = false; - if (imm != null) { - try { - // imm.isAcceptingText() seems to sometimes crash on some devices - isAcceptingText = imm.isAcceptingText(); - } catch (Exception ignored) { - } - } - - if (containerView != null && imm != null && !isAcceptingText) { - imm.hideSoftInputFromWindow( - containerView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); - } - } - }, - 128); - } - return connection; - } - - @Override - public ActionMode startActionMode(ActionMode.Callback callback) { - if (customSettings.useHybridComposition && !customSettings.disableContextMenu && (contextMenu == null || contextMenu.keySet().size() == 0)) { - return super.startActionMode(callback); - } - return rebuildActionMode(super.startActionMode(callback), callback); - } - - @RequiresApi(api = Build.VERSION_CODES.M) - @Override - public ActionMode startActionMode(ActionMode.Callback callback, int type) { - if (customSettings.useHybridComposition && !customSettings.disableContextMenu && (contextMenu == null || contextMenu.keySet().size() == 0)) { - return super.startActionMode(callback, type); - } - return rebuildActionMode(super.startActionMode(callback, type), callback); - } - - public ActionMode rebuildActionMode( - final ActionMode actionMode, - final ActionMode.Callback callback - ) { - // fix Android 10 clipboard not working properly https://github.com/pichillilorenzo/flutter_inappwebview/issues/678 - if (!customSettings.useHybridComposition && containerView != null) { - onWindowFocusChanged(containerView.isFocused()); - } - - boolean hasBeenRemovedAndRebuilt = false; - if (floatingContextMenu != null) { - hideContextMenu(); - hasBeenRemovedAndRebuilt = true; - } - if (actionMode == null) { - return null; - } - - Menu actionMenu = actionMode.getMenu(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - actionMode.hide(3000); - } - List defaultMenuItems = new ArrayList<>(); - for (int i = 0; i < actionMenu.size(); i++) { - defaultMenuItems.add(actionMenu.getItem(i)); - } - actionMenu.clear(); - actionMode.finish(); - if (customSettings.disableContextMenu) { - return actionMode; - } - - floatingContextMenu = (LinearLayout) LayoutInflater.from(this.getContext()) - .inflate(R.layout.floating_action_mode, this, false); - HorizontalScrollView horizontalScrollView = (HorizontalScrollView) floatingContextMenu.getChildAt(0); - LinearLayout menuItemListLayout = (LinearLayout) horizontalScrollView.getChildAt(0); - - List> customMenuItems = new ArrayList<>(); - ContextMenuSettings contextMenuSettings = new ContextMenuSettings(); - if (contextMenu != null) { - customMenuItems = (List>) contextMenu.get("menuItems"); - Map contextMenuSettingsMap = (Map) contextMenu.get("settings"); - if (contextMenuSettingsMap != null) { - contextMenuSettings.parse(contextMenuSettingsMap); - } - } - customMenuItems = customMenuItems == null ? new ArrayList>() : customMenuItems; - - if (contextMenuSettings.hideDefaultSystemContextMenuItems == null || !contextMenuSettings.hideDefaultSystemContextMenuItems) { - for (final MenuItem menuItem : defaultMenuItems) { - final int itemId = menuItem.getItemId(); - final String itemTitle = menuItem.getTitle().toString(); - - TextView text = (TextView) LayoutInflater.from(this.getContext()) - .inflate(R.layout.floating_action_mode_item, this, false); - text.setText(itemTitle); - text.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - hideContextMenu(); - callback.onActionItemClicked(actionMode, menuItem); - - if (channelDelegate != null) - channelDelegate.onContextMenuActionItemClicked(itemId, itemTitle); - } - }); - if (floatingContextMenu != null) { - menuItemListLayout.addView(text); - } - } - } - - for (final Map menuItem : customMenuItems) { - final int itemId = (int) menuItem.get("id"); - final String itemTitle = (String) menuItem.get("title"); - TextView text = (TextView) LayoutInflater.from(this.getContext()) - .inflate(R.layout.floating_action_mode_item, this, false); - text.setText(itemTitle); - text.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - hideContextMenu(); - - if (channelDelegate != null) - channelDelegate.onContextMenuActionItemClicked(itemId, itemTitle); - } - }); - if (floatingContextMenu != null) { - menuItemListLayout.addView(text); - } - } - - final int x = (lastTouch != null) ? lastTouch.x : 0; - final int y = (lastTouch != null) ? lastTouch.y : 0; - contextMenuPoint = new Point(x, y); - - if (floatingContextMenu != null) { - floatingContextMenu.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { - - @Override - public void onGlobalLayout() { - if (floatingContextMenu != null) { - floatingContextMenu.getViewTreeObserver().removeOnGlobalLayoutListener(this); - if (getSettings().getJavaScriptEnabled()) { - onScrollStopped(); - } else { - onFloatingActionGlobalLayout(x, y); - } - } - } - }); - addView(floatingContextMenu, new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, x, y)); - if (hasBeenRemovedAndRebuilt) { - sendOnCreateContextMenuEvent(); - } - if (checkContextMenuShouldBeClosedTask != null) { - checkContextMenuShouldBeClosedTask.run(); - } - } - - return actionMode; - } - - public void onFloatingActionGlobalLayout(int x, int y) { - int maxWidth = getWidth(); - int maxHeight = getHeight(); - int width = floatingContextMenu.getWidth(); - int height = floatingContextMenu.getHeight(); - int curx = x - (width / 2); - if (curx < 0) { - curx = 0; - } else if (curx + width > maxWidth) { - curx = maxWidth - width; - } - // float size = 12 * scale; - float cury = y - (height * 1.5f); - if (cury < 0) { - cury = y + height; - } - - updateViewLayout( - floatingContextMenu, - new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, curx + getScrollX(), ((int) cury) + getScrollY()) - ); - - mainLooperHandler.post(new Runnable() { - @Override - public void run() { - if (floatingContextMenu != null) { - floatingContextMenu.setVisibility(View.VISIBLE); - floatingContextMenu.animate().alpha(1f).setDuration(100).setListener(null); - } - } - }); - } - - public void hideContextMenu() { - removeView(floatingContextMenu); - floatingContextMenu = null; - - if (channelDelegate != null) channelDelegate.onHideContextMenu(); - } - - public void onScrollStopped() { - if (floatingContextMenu != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - adjustFloatingContextMenuPosition(); - } - } - - @RequiresApi(api = Build.VERSION_CODES.KITKAT) - public void adjustFloatingContextMenuPosition() { - evaluateJavascript("(function(){" + - " var selection = window.getSelection();" + - " var rangeY = null;" + - " if (selection != null && selection.rangeCount > 0) {" + - " var range = selection.getRangeAt(0);" + - " var clientRect = range.getClientRects();" + - " if (clientRect.length > 0) {" + - " rangeY = clientRect[0].y;" + - " } else if (document.activeElement != null && document.activeElement.tagName.toLowerCase() !== 'iframe') {" + - " var boundingClientRect = document.activeElement.getBoundingClientRect();" + - " rangeY = boundingClientRect.y;" + - " }" + - " }" + - " return rangeY;" + - "})();", new ValueCallback() { - @Override - public void onReceiveValue(String value) { - if (floatingContextMenu != null) { - if (value != null && !value.equalsIgnoreCase("null")) { - int x = contextMenuPoint.x; - int y = (int) ((Float.parseFloat(value) * Util.getPixelDensity(getContext())) + (floatingContextMenu.getHeight() / 3.5)); - contextMenuPoint.y = y; - onFloatingActionGlobalLayout(x, y); - } else { - floatingContextMenu.setVisibility(View.VISIBLE); - floatingContextMenu.animate().alpha(1f).setDuration(100).setListener(null); - onFloatingActionGlobalLayout(contextMenuPoint.x, contextMenuPoint.y); - } - } - } - }); - } - - @RequiresApi(api = Build.VERSION_CODES.KITKAT) - public void getSelectedText(final ValueCallback resultCallback) { - evaluateJavascript(PluginScriptsUtil.GET_SELECTED_TEXT_JS_SOURCE, new ValueCallback() { - @Override - public void onReceiveValue(String value) { - value = (value != null && !value.equalsIgnoreCase("null")) ? value.substring(1, value.length() - 1) : null; - resultCallback.onReceiveValue(value); - } - }); - } - - public Map requestFocusNodeHref() { - Message msg = InAppWebView.mHandler.obtainMessage(); - requestFocusNodeHref(msg); - Bundle bundle = msg.peekData(); - - Map obj = new HashMap<>(); - obj.put("src", bundle.getString("src")); - obj.put("url", bundle.getString("url")); - obj.put("title", bundle.getString("title")); - - return obj; - } - - public Map requestImageRef() { - Message msg = InAppWebView.mHandler.obtainMessage(); - requestImageRef(msg); - Bundle bundle = msg.peekData(); - - Map obj = new HashMap<>(); - obj.put("url", bundle.getString("url")); - - return obj; - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public void callAsyncJavaScript(String functionBody, Map arguments, @Nullable ContentWorld contentWorld, @Nullable ValueCallback resultCallback) { - String resultUuid = UUID.randomUUID().toString(); - if (resultCallback != null) { - callAsyncJavaScriptCallbacks.put(resultUuid, resultCallback); - } - - JSONObject functionArguments = new JSONObject(arguments); - Iterator keys = functionArguments.keys(); - - List functionArgumentNamesList = new ArrayList<>(); - List functionArgumentValuesList = new ArrayList<>(); - while (keys.hasNext()) { - String key = keys.next(); - functionArgumentNamesList.add(key); - functionArgumentValuesList.add("obj." + key); - } - - String functionArgumentNames = TextUtils.join(", ", functionArgumentNamesList); - String functionArgumentValues = TextUtils.join(", ", functionArgumentValuesList); - String functionArgumentsObj = Util.JSONStringify(arguments); - - String sourceToInject = PluginScriptsUtil.CALL_ASYNC_JAVA_SCRIPT_WRAPPER_JS_SOURCE() - .replace(PluginScriptsUtil.VAR_FUNCTION_ARGUMENT_NAMES, functionArgumentNames) - .replace(PluginScriptsUtil.VAR_FUNCTION_ARGUMENT_VALUES, functionArgumentValues) - .replace(PluginScriptsUtil.VAR_FUNCTION_ARGUMENTS_OBJ, functionArgumentsObj) - .replace(PluginScriptsUtil.VAR_FUNCTION_BODY, functionBody) - .replace(PluginScriptsUtil.VAR_RESULT_UUID, resultUuid) - .replace(PluginScriptsUtil.VAR_RESULT_UUID, resultUuid); - - sourceToInject = userContentController.generateCodeForScriptEvaluation(sourceToInject, contentWorld); - evaluateJavascript(sourceToInject, null); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public void isSecureContext(final ValueCallback resultCallback) { - evaluateJavascript("window.isSecureContext", new ValueCallback() { - @Override - public void onReceiveValue(String value) { - if (value == null || value.isEmpty() || value.equalsIgnoreCase("null") - || value.equalsIgnoreCase("false")) { - resultCallback.onReceiveValue(false); - return; - } - resultCallback.onReceiveValue(true); - } - }); - } - - public boolean canScrollVertically() { - return computeVerticalScrollRange() > computeVerticalScrollExtent(); - } - - public boolean canScrollHorizontally() { - return computeHorizontalScrollRange() > computeHorizontalScrollExtent(); - } - - public WebMessageChannel createCompatWebMessageChannel() { - String id = UUID.randomUUID().toString(); - WebMessageChannel webMessageChannel = new WebMessageChannel(id, this); - webMessageChannels.put(id, webMessageChannel); - return webMessageChannel; - } - - @Override - public WebMessageChannel createWebMessageChannel(ValueCallback callback) { - WebMessageChannel webMessageChannel = createCompatWebMessageChannel(); - callback.onReceiveValue(webMessageChannel); - return webMessageChannel; - } - - public void addWebMessageListener(@NonNull WebMessageListener webMessageListener) throws Exception { - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) { - WebViewCompat.addWebMessageListener(this, webMessageListener.jsObjectName, webMessageListener.allowedOriginRules, webMessageListener.listener); - webMessageListeners.add(webMessageListener); - } - } - - public void disposeWebMessageChannels() { - for (WebMessageChannel webMessageChannel : webMessageChannels.values()) { - webMessageChannel.dispose(); - } - webMessageChannels.clear(); - } - - public void disposeWebMessageListeners() { - for (WebMessageListener webMessageListener : webMessageListeners) { - webMessageListener.dispose(); - } - webMessageListeners.clear(); - } - - @Override - public Looper getWebViewLooper() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - return super.getWebViewLooper(); - } - return Looper.getMainLooper(); - } - - @Override - public boolean isInFullscreen() { - return inFullscreen; - } - - @Override - public void setInFullscreen(boolean inFullscreen) { - this.inFullscreen = inFullscreen; - } - - @Override - public void postWebMessage(com.pichillilorenzo.flutter_inappwebview_android.types.WebMessage message, Uri targetOrigin, ValueCallback callback) throws Exception { - throw new UnsupportedOperationException(); - } - - @Override - protected void onWindowVisibilityChanged(int visibility) { - if (customSettings.allowBackgroundAudioPlaying) { - if (visibility != View.GONE) { - super.onWindowVisibilityChanged(View.VISIBLE); - } - return; - } - super.onWindowVisibilityChanged(visibility); - } - - public float getZoomScale() { - return zoomScale; - } - - @Override - public void getZoomScale(final ValueCallback callback) { - callback.onReceiveValue(zoomScale); - } - - @Nullable - public Map getContextMenu() { - return contextMenu; - } - - public void setContextMenu(@Nullable Map contextMenu) { - this.contextMenu = contextMenu; - } - - @Nullable - public InAppWebViewFlutterPlugin getPlugin() { - return plugin; - } - - public void setPlugin(@Nullable InAppWebViewFlutterPlugin plugin) { - this.plugin = plugin; - } - - @Nullable - public InAppBrowserDelegate getInAppBrowserDelegate() { - return inAppBrowserDelegate; - } - - public void setInAppBrowserDelegate(@Nullable InAppBrowserDelegate inAppBrowserDelegate) { - this.inAppBrowserDelegate = inAppBrowserDelegate; - } - - public UserContentController getUserContentController() { - return userContentController; - } - - public void setUserContentController(UserContentController userContentController) { - this.userContentController = userContentController; - } - - public Map getWebMessageChannels() { - return webMessageChannels; - } - - public void setWebMessageChannels(Map webMessageChannels) { - this.webMessageChannels = webMessageChannels; - } - - @Override - public void getContentHeight(ValueCallback callback) { - callback.onReceiveValue(getContentHeight()); - } - - public void getContentWidth(final ValueCallback callback) { - evaluateJavascript("document.documentElement.scrollWidth;", new ValueCallback() { - @Override - public void onReceiveValue(@Nullable String value) { - Integer contentWidth = null; - if (value != null && !value.equalsIgnoreCase("null")) { - contentWidth = Integer.parseInt(value); - } - callback.onReceiveValue(contentWidth); - } - }); - } - - @Override - public void getHitTestResult(ValueCallback callback) { - callback.onReceiveValue(com.pichillilorenzo.flutter_inappwebview_android.types.HitTestResult.fromWebViewHitTestResult(getHitTestResult())); - } - - @Nullable - @Override - public WebViewChannelDelegate getChannelDelegate() { - return channelDelegate; - } - - @Override - public void setChannelDelegate(@Nullable WebViewChannelDelegate channelDelegate) { - this.channelDelegate = channelDelegate; - } - - @Override - public InAppWebViewSettings getCustomSettings() { - return customSettings; - } - - @Override - public void showInputMethod() { - if (plugin == null || plugin.activity == null) { - return; - } - InputMethodManager imm = (InputMethodManager) plugin.activity.getSystemService(INPUT_METHOD_SERVICE); - if (imm != null) { - imm.showSoftInput(this, 0); - } - } - - @Override - public void hideInputMethod() { - if (plugin == null || plugin.activity == null) { - return; - } - InputMethodManager imm = (InputMethodManager) plugin.activity.getSystemService(INPUT_METHOD_SERVICE); - if (imm != null) { - IBinder windowToken = getWindowToken(); - if (!customSettings.useHybridComposition && containerView != null) { - windowToken = containerView.getWindowToken(); - } - imm.hideSoftInputFromWindow(windowToken, 0); - } - } - - @Override - @Nullable - public byte[] saveState() { - Bundle bundle = new Bundle(); - if (saveState(bundle) != null) { - Parcel parcel = Parcel.obtain(); - bundle.writeToParcel(parcel, 0); - byte[] bytes = parcel.marshall(); - parcel.recycle(); - return bytes; - } - return null; - } - - @Override - public boolean restoreState(byte[] state) { - boolean restored = false; - Parcel parcel = Parcel.obtain(); - try { - parcel.unmarshall(state, 0, state.length); - parcel.setDataPosition(0); - Bundle bundle = Bundle.CREATOR.createFromParcel(parcel); - restored = restoreState(bundle) != null; - } catch (Exception e) { - e.printStackTrace(); - } finally { - parcel.recycle(); - } - return restored; - } - - - @Override - public void dispose() { - if (channelDelegate != null) { - channelDelegate.dispose(); - channelDelegate = null; - } - super.dispose(); - WebSettings settings = getSettings(); - settings.setJavaScriptEnabled(false); - removeJavascriptInterface(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE)) { - WebViewCompat.setWebViewRenderProcessClient(this, null); - } - setWebChromeClient(new WebChromeClient()); - setWebViewClient(new WebViewClient() { - public void onPageFinished(WebView view, String url) { - destroy(); - } - }); - interceptOnlyAsyncAjaxRequestsPluginScript = null; - userContentController.dispose(); - if (findInteractionController != null) { - findInteractionController.dispose(); - findInteractionController = null; - } - if (webViewAssetLoaderExt != null) { - webViewAssetLoaderExt.dispose(); - webViewAssetLoaderExt = null; - } - if (windowId != null && plugin != null && plugin.inAppWebViewManager != null) { - plugin.inAppWebViewManager.windowWebViewMessages.remove(windowId); - } - mainLooperHandler.removeCallbacksAndMessages(null); - mHandler.removeCallbacksAndMessages(null); - disposeWebMessageChannels(); - disposeWebMessageListeners(); - removeAllViews(); - if (checkContextMenuShouldBeClosedTask != null) - removeCallbacks(checkContextMenuShouldBeClosedTask); - if (checkScrollStoppedTask != null) - removeCallbacks(checkScrollStoppedTask); - callAsyncJavaScriptCallbacks.clear(); - evaluateJavaScriptContentWorldCallbacks.clear(); - inAppBrowserDelegate = null; - if (inAppWebViewRenderProcessClient != null) { - inAppWebViewRenderProcessClient.dispose(); - inAppWebViewRenderProcessClient = null; - } - if (inAppWebViewChromeClient != null) { - inAppWebViewChromeClient.dispose(); - inAppWebViewChromeClient = null; - } - if (inAppWebViewClientCompat != null) { - inAppWebViewClientCompat.dispose(); - inAppWebViewClientCompat = null; - } - if (inAppWebViewClient != null) { - inAppWebViewClient.dispose(); - inAppWebViewClient = null; - } - if (javaScriptBridgeInterface != null) { - javaScriptBridgeInterface.dispose(); - javaScriptBridgeInterface = null; - } - plugin = null; - loadUrl("about:blank"); - } - - @Override - public void destroy() { - super.destroy(); - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewChromeClient.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewChromeClient.java deleted file mode 100755 index 120962808d..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewChromeClient.java +++ /dev/null @@ -1,1384 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview; - -import static android.app.Activity.RESULT_OK; - -import android.Manifest; -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.res.AssetFileDescriptor; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Color; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Environment; -import android.os.Message; -import android.os.Parcelable; -import android.provider.MediaStore; -import android.util.Log; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.webkit.ConsoleMessage; -import android.webkit.GeolocationPermissions; -import android.webkit.JsPromptResult; -import android.webkit.JsResult; -import android.webkit.MimeTypeMap; -import android.webkit.PermissionRequest; -import android.webkit.ValueCallback; -import android.webkit.WebChromeClient; -import android.webkit.WebView; -import android.widget.EditText; -import android.widget.FrameLayout; -import android.widget.LinearLayout; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; -import androidx.appcompat.app.AlertDialog; -import androidx.core.content.ContextCompat; -import androidx.core.content.FileProvider; - -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFileProvider; -import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; -import com.pichillilorenzo.flutter_inappwebview_android.in_app_browser.ActivityResultListener; -import com.pichillilorenzo.flutter_inappwebview_android.in_app_browser.InAppBrowserDelegate; -import com.pichillilorenzo.flutter_inappwebview_android.types.CreateWindowAction; -import com.pichillilorenzo.flutter_inappwebview_android.types.GeolocationPermissionShowPromptResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.JsAlertResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.JsBeforeUnloadResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.JsConfirmResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.JsPromptResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.PermissionResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.ShowFileChooserRequest; -import com.pichillilorenzo.flutter_inappwebview_android.types.ShowFileChooserResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.URLRequest; -import com.pichillilorenzo.flutter_inappwebview_android.webview.WebViewChannelDelegate; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.flutter.plugin.common.PluginRegistry; - -public class InAppWebViewChromeClient extends WebChromeClient implements PluginRegistry.ActivityResultListener, ActivityResultListener { - - protected static final String LOG_TAG = "IABWebChromeClient"; - private InAppBrowserDelegate inAppBrowserDelegate; - - private static final int PICKER = 1; - private static final int PICKER_LEGACY = 3; - final String DEFAULT_MIME_TYPES = "*/*"; - final Map dialogs = new HashMap<>(); - - protected static final FrameLayout.LayoutParams FULLSCREEN_LAYOUT_PARAMS = new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER); - - @RequiresApi(api = Build.VERSION_CODES.KITKAT) - protected static final int FULLSCREEN_SYSTEM_UI_VISIBILITY_KITKAT = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | - View.SYSTEM_UI_FLAG_LAYOUT_STABLE | - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_FULLSCREEN | - View.SYSTEM_UI_FLAG_IMMERSIVE | - View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; - - protected static final int FULLSCREEN_SYSTEM_UI_VISIBILITY = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | - View.SYSTEM_UI_FLAG_LAYOUT_STABLE | - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_FULLSCREEN; - - @Nullable - private View mCustomView; - @Nullable - private WebChromeClient.CustomViewCallback mCustomViewCallback; - private int mOriginalOrientation; - private int mOriginalSystemUiVisibility; - @Nullable - public InAppWebViewFlutterPlugin plugin; - @Nullable - public InAppWebView inAppWebView; - - @Nullable - private ValueCallback filePathCallbackLegacy; - @Nullable - private ValueCallback filePathCallback; - @Nullable - private Uri videoOutputFileUri; - @Nullable - private Uri imageOutputFileUri; - - public InAppWebViewChromeClient(@NonNull final InAppWebViewFlutterPlugin plugin, - @NonNull InAppWebView inAppWebView, InAppBrowserDelegate inAppBrowserDelegate) { - super(); - this.plugin = plugin; - this.inAppWebView = inAppWebView; - this.inAppBrowserDelegate = inAppBrowserDelegate; - if (this.inAppBrowserDelegate != null) { - this.inAppBrowserDelegate.getActivityResultListeners().add(this); - } - - if (plugin.activityPluginBinding != null) - plugin.activityPluginBinding.addActivityResultListener(this); - } - - @Nullable - @Override - public Bitmap getDefaultVideoPoster() { - if (inAppWebView != null && inAppWebView.customSettings.defaultVideoPoster != null) { - final byte[] data = inAppWebView.customSettings.defaultVideoPoster; - BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); - bitmapOptions.inMutable = true; - return BitmapFactory.decodeByteArray( - data, 0, data.length, bitmapOptions - ); - } - return Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888); - } - - @Override - public void onHideCustomView() { - Activity activity = getActivity(); - if (activity == null) { - return; - } - - View decorView = getRootView(); - if (decorView == null) { - return; - } - if (this.mCustomView != null) { - ((FrameLayout) decorView).removeView(this.mCustomView); - } - this.mCustomView = null; - decorView.setSystemUiVisibility(this.mOriginalSystemUiVisibility); - activity.setRequestedOrientation(this.mOriginalOrientation); - if (this.mCustomViewCallback != null) { - this.mCustomViewCallback.onCustomViewHidden(); - } - this.mCustomViewCallback = null; - activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); - - if (inAppWebView != null) { - WebViewChannelDelegate eventWebViewChannelDelegate = inAppWebView.channelDelegate; - if (eventWebViewChannelDelegate != null) - eventWebViewChannelDelegate.onExitFullscreen(); - inAppWebView.setInFullscreen(false); - } - } - - @Override - public void onShowCustomView(final View paramView, final CustomViewCallback paramCustomViewCallback) { - if (this.mCustomView != null) { - onHideCustomView(); - return; - } - - Activity activity = getActivity(); - if (activity == null) { - return; - } - - View decorView = getRootView(); - if (decorView == null) { - return; - } - this.mCustomView = paramView; - this.mOriginalSystemUiVisibility = decorView.getSystemUiVisibility(); - this.mOriginalOrientation = activity.getRequestedOrientation(); - this.mCustomViewCallback = paramCustomViewCallback; - if (this.mCustomView != null) { - this.mCustomView.setBackgroundColor(Color.BLACK); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - decorView.setSystemUiVisibility(FULLSCREEN_SYSTEM_UI_VISIBILITY_KITKAT); - } else { - decorView.setSystemUiVisibility(FULLSCREEN_SYSTEM_UI_VISIBILITY); - } - activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); - ((FrameLayout) decorView).addView(this.mCustomView, FULLSCREEN_LAYOUT_PARAMS); - - if (inAppWebView != null) { - WebViewChannelDelegate eventWebViewChannelDelegate = inAppWebView.channelDelegate; - if (eventWebViewChannelDelegate != null) - eventWebViewChannelDelegate.onEnterFullscreen(); - inAppWebView.setInFullscreen(true); - } - } - - @Override - public boolean onJsAlert(final WebView view, String url, final String message, - final JsResult result) { - if (inAppWebView != null && inAppWebView.channelDelegate != null) { - inAppWebView.channelDelegate.onJsAlert(url, message, null, new WebViewChannelDelegate.JsAlertCallback() { - @Override - public boolean nonNullSuccess(@NonNull JsAlertResponse response) { - if (response.isHandledByClient()) { - Integer action = response.getAction(); - action = action != null ? action : 1; - switch (action) { - case 0: - result.confirm(); - break; - case 1: - default: - result.cancel(); - } - return false; - } - return true; - } - - @Override - public void defaultBehaviour(@Nullable JsAlertResponse response) { - String responseMessage = null; - String confirmButtonTitle = null; - if (response != null) { - responseMessage = response.getMessage(); - confirmButtonTitle = response.getConfirmButtonTitle(); - } - createAlertDialog(message, result, responseMessage, confirmButtonTitle); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - result.cancel(); - } - }); - - return true; - } - - return false; - } - - public void createAlertDialog(String message, final JsResult result, String responseMessage, String confirmButtonTitle) { - String alertMessage = (responseMessage != null && !responseMessage.isEmpty()) ? responseMessage : message; - - DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - result.confirm(); - dialog.dismiss(); - dialogs.remove(dialog); - } - }; - - Activity activity = getActivity(); - if (activity == null) { - return; - } - - AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, androidx.appcompat.R.style.Theme_AppCompat_Dialog_Alert); - alertDialogBuilder.setMessage(alertMessage); - if (confirmButtonTitle != null && !confirmButtonTitle.isEmpty()) { - alertDialogBuilder.setPositiveButton(confirmButtonTitle, clickListener); - } else { - alertDialogBuilder.setPositiveButton(android.R.string.ok, clickListener); - } - - alertDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - result.cancel(); - dialog.dismiss(); - dialogs.remove(dialog); - } - }); - - AlertDialog alertDialog = alertDialogBuilder.create(); - dialogs.put(alertDialog, result); - alertDialog.show(); - } - - @Override - public boolean onJsConfirm(final WebView view, String url, final String message, - final JsResult result) { - if (inAppWebView != null && inAppWebView.channelDelegate != null) { - inAppWebView.channelDelegate.onJsConfirm(url, message, null, new WebViewChannelDelegate.JsConfirmCallback() { - @Override - public boolean nonNullSuccess(@NonNull JsConfirmResponse response) { - if (response.isHandledByClient()) { - Integer action = response.getAction(); - action = action != null ? action : 1; - switch (action) { - case 0: - result.confirm(); - break; - case 1: - default: - result.cancel(); - } - return false; - } - return true; - } - - @Override - public void defaultBehaviour(@Nullable JsConfirmResponse response) { - String responseMessage = null; - String confirmButtonTitle = null; - String cancelButtonTitle = null; - if (response != null) { - responseMessage = response.getMessage(); - confirmButtonTitle = response.getConfirmButtonTitle(); - cancelButtonTitle = response.getCancelButtonTitle(); - } - createConfirmDialog(message, result, responseMessage, confirmButtonTitle, cancelButtonTitle); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - result.cancel(); - } - }); - - return true; - } - - return false; - } - - public void createConfirmDialog(String message, final JsResult result, String responseMessage, String confirmButtonTitle, String cancelButtonTitle) { - String alertMessage = (responseMessage != null && !responseMessage.isEmpty()) ? responseMessage : message; - DialogInterface.OnClickListener confirmClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - result.confirm(); - dialog.dismiss(); - dialogs.remove(dialog); - } - }; - DialogInterface.OnClickListener cancelClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - result.cancel(); - dialog.dismiss(); - dialogs.remove(dialog); - } - }; - - Activity activity = getActivity(); - if (activity == null) { - return; - } - - AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, androidx.appcompat.R.style.Theme_AppCompat_Dialog_Alert); - alertDialogBuilder.setMessage(alertMessage); - if (confirmButtonTitle != null && !confirmButtonTitle.isEmpty()) { - alertDialogBuilder.setPositiveButton(confirmButtonTitle, confirmClickListener); - } else { - alertDialogBuilder.setPositiveButton(android.R.string.ok, confirmClickListener); - } - if (cancelButtonTitle != null && !cancelButtonTitle.isEmpty()) { - alertDialogBuilder.setNegativeButton(cancelButtonTitle, cancelClickListener); - } else { - alertDialogBuilder.setNegativeButton(android.R.string.cancel, cancelClickListener); - } - - alertDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - result.cancel(); - dialog.dismiss(); - dialogs.remove(dialog); - } - }); - - AlertDialog alertDialog = alertDialogBuilder.create(); - dialogs.put(alertDialog, result); - alertDialog.show(); - } - - @Override - public boolean onJsPrompt(final WebView view, String url, final String message, - final String defaultValue, final JsPromptResult result) { - if (inAppWebView != null && inAppWebView.channelDelegate != null) { - inAppWebView.channelDelegate.onJsPrompt(url, message, defaultValue, null, new WebViewChannelDelegate.JsPromptCallback() { - @Override - public boolean nonNullSuccess(@NonNull JsPromptResponse response) { - if (response.isHandledByClient()) { - Integer action = response.getAction(); - action = action != null ? action : 1; - switch (action) { - case 0: - result.confirm(response.getValue()); - break; - case 1: - default: - result.cancel(); - } - return false; - } - return true; - } - - @Override - public void defaultBehaviour(@Nullable JsPromptResponse response) { - String responseMessage = null; - String responseDefaultValue = null; - String value = null; - String confirmButtonTitle = null; - String cancelButtonTitle = null; - if (response != null) { - responseMessage = response.getMessage(); - responseDefaultValue = response.getDefaultValue(); - value = response.getValue(); - confirmButtonTitle = response.getConfirmButtonTitle(); - cancelButtonTitle = response.getCancelButtonTitle(); - } - createPromptDialog(view, message, defaultValue, result, responseMessage, responseDefaultValue, value, cancelButtonTitle, confirmButtonTitle); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - result.cancel(); - } - }); - - return true; - } - - return false; - } - - public void createPromptDialog(WebView view, String message, String defaultValue, final JsPromptResult result, String responseMessage, String responseDefaultValue, String value, String cancelButtonTitle, String confirmButtonTitle) { - FrameLayout layout = new FrameLayout(view.getContext()); - - final EditText input = new EditText(view.getContext()); - input.setMaxLines(1); - input.setText((responseDefaultValue != null && !responseDefaultValue.isEmpty()) ? responseDefaultValue : defaultValue); - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.MATCH_PARENT); - input.setLayoutParams(lp); - - layout.setPaddingRelative(45, 15, 45, 0); - layout.addView(input); - - String alertMessage = (responseMessage != null && !responseMessage.isEmpty()) ? responseMessage : message; - - final String finalValue = value; - DialogInterface.OnClickListener confirmClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String text = input.getText().toString(); - result.confirm(finalValue != null ? finalValue : text); - dialog.dismiss(); - dialogs.remove(dialog); - } - }; - DialogInterface.OnClickListener cancelClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - result.cancel(); - dialog.dismiss(); - dialogs.remove(dialog); - } - }; - - Activity activity = getActivity(); - if (activity == null) { - return; - } - - AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, androidx.appcompat.R.style.Theme_AppCompat_Dialog_Alert); - alertDialogBuilder.setMessage(alertMessage); - if (confirmButtonTitle != null && !confirmButtonTitle.isEmpty()) { - alertDialogBuilder.setPositiveButton(confirmButtonTitle, confirmClickListener); - } else { - alertDialogBuilder.setPositiveButton(android.R.string.ok, confirmClickListener); - } - if (cancelButtonTitle != null && !cancelButtonTitle.isEmpty()) { - alertDialogBuilder.setNegativeButton(cancelButtonTitle, cancelClickListener); - } else { - alertDialogBuilder.setNegativeButton(android.R.string.cancel, cancelClickListener); - } - - alertDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - result.cancel(); - dialog.dismiss(); - dialogs.remove(dialog); - } - }); - - AlertDialog alertDialog = alertDialogBuilder.create(); - alertDialog.setView(layout); - dialogs.put(alertDialog, result); - alertDialog.show(); - } - - @Override - public boolean onJsBeforeUnload(final WebView view, String url, final String message, - final JsResult result) { - if (inAppWebView != null && inAppWebView.channelDelegate != null) { - inAppWebView.channelDelegate.onJsBeforeUnload(url, message, new WebViewChannelDelegate.JsBeforeUnloadCallback() { - @Override - public boolean nonNullSuccess(@NonNull JsBeforeUnloadResponse response) { - if (response.isHandledByClient()) { - Integer action = response.getAction(); - action = action != null ? action : 1; - switch (action) { - case 0: - result.confirm(); - break; - case 1: - default: - result.cancel(); - } - return false; - } - return true; - } - - @Override - public void defaultBehaviour(@Nullable JsBeforeUnloadResponse response) { - String responseMessage = null; - String confirmButtonTitle = null; - String cancelButtonTitle = null; - if (response != null) { - responseMessage = response.getMessage(); - confirmButtonTitle = response.getConfirmButtonTitle(); - cancelButtonTitle = response.getCancelButtonTitle(); - } - createBeforeUnloadDialog(message, result, responseMessage, confirmButtonTitle, cancelButtonTitle); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - result.cancel(); - } - }); - - return true; - } - - return false; - } - - public void createBeforeUnloadDialog(String message, final JsResult result, String responseMessage, String confirmButtonTitle, String cancelButtonTitle) { - String alertMessage = (responseMessage != null && !responseMessage.isEmpty()) ? responseMessage : message; - DialogInterface.OnClickListener confirmClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - result.confirm(); - dialog.dismiss(); - dialogs.remove(dialog); - } - }; - DialogInterface.OnClickListener cancelClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - result.cancel(); - dialog.dismiss(); - dialogs.remove(dialog); - } - }; - - Activity activity = getActivity(); - if (activity == null) { - return; - } - - AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, androidx.appcompat.R.style.Theme_AppCompat_Dialog_Alert); - alertDialogBuilder.setMessage(alertMessage); - if (confirmButtonTitle != null && !confirmButtonTitle.isEmpty()) { - alertDialogBuilder.setPositiveButton(confirmButtonTitle, confirmClickListener); - } else { - alertDialogBuilder.setPositiveButton(android.R.string.ok, confirmClickListener); - } - if (cancelButtonTitle != null && !cancelButtonTitle.isEmpty()) { - alertDialogBuilder.setNegativeButton(cancelButtonTitle, cancelClickListener); - } else { - alertDialogBuilder.setNegativeButton(android.R.string.cancel, cancelClickListener); - } - - alertDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - result.cancel(); - dialog.dismiss(); - dialogs.remove(dialog); - } - }); - - AlertDialog alertDialog = alertDialogBuilder.create(); - dialogs.put(alertDialog, result); - alertDialog.show(); - } - - @Override - public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, final Message resultMsg) { - int windowId = 0; - if (plugin != null && plugin.inAppWebViewManager != null) { - plugin.inAppWebViewManager.windowAutoincrementId++; - windowId = plugin.inAppWebViewManager.windowAutoincrementId; - } - - WebView.HitTestResult result = view.getHitTestResult(); - String url = result.getExtra(); - - // Ensure that images with hyperlink return the correct URL, not the image source - if (result.getType() == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) { - Message href = view.getHandler().obtainMessage(); - view.requestFocusNodeHref(href); - Bundle data = href.getData(); - if (data != null) { - String imageUrl = data.getString("url"); - if (imageUrl != null && !imageUrl.isEmpty()) { - url = imageUrl; - } - } - } - - URLRequest request = new URLRequest(url, "GET", null, null); - CreateWindowAction createWindowAction = new CreateWindowAction( - request, - true, - isUserGesture, - false, - windowId, - isDialog - ); - - if (plugin != null && plugin.inAppWebViewManager != null) { - plugin.inAppWebViewManager.windowWebViewMessages.put(windowId, resultMsg); - } - - if (inAppWebView != null && inAppWebView.channelDelegate != null) { - final int finalWindowId = windowId; - inAppWebView.channelDelegate.onCreateWindow(createWindowAction, new WebViewChannelDelegate.CreateWindowCallback() { - @Override - public boolean nonNullSuccess(@NonNull Boolean handledByClient) { - return !handledByClient; - } - - @Override - public void defaultBehaviour(@Nullable Boolean handledByClient) { - if (plugin != null && plugin.inAppWebViewManager != null) { - plugin.inAppWebViewManager.windowWebViewMessages.remove(finalWindowId); - } - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }); - - return true; - } - - return false; - } - - @Override - public void onCloseWindow(WebView window) { - if (inAppWebView != null && inAppWebView.channelDelegate != null) { - inAppWebView.channelDelegate.onCloseWindow(); - } - - super.onCloseWindow(window); - } - - @Override - public void onGeolocationPermissionsShowPrompt(final String origin, final GeolocationPermissions.Callback callback) { - final WebViewChannelDelegate.GeolocationPermissionsShowPromptCallback resultCallback = new WebViewChannelDelegate.GeolocationPermissionsShowPromptCallback() { - @Override - public boolean nonNullSuccess(@NonNull GeolocationPermissionShowPromptResponse response) { - callback.invoke(response.getOrigin(), response.isAllow(), response.isRetain()); - return false; - } - - @Override - public void defaultBehaviour(@Nullable GeolocationPermissionShowPromptResponse response) { - callback.invoke(origin, false, false); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (inAppWebView != null && inAppWebView.channelDelegate != null) { - inAppWebView.channelDelegate.onGeolocationPermissionsShowPrompt(origin, resultCallback); - } else { - resultCallback.defaultBehaviour(null); - } - } - - @Override - public void onGeolocationPermissionsHidePrompt() { - if (inAppWebView != null && inAppWebView.channelDelegate != null) { - inAppWebView.channelDelegate.onGeolocationPermissionsHidePrompt(); - } - } - - @Override - public boolean onConsoleMessage(ConsoleMessage consoleMessage) { - if (inAppWebView != null && inAppWebView.channelDelegate != null) { - inAppWebView.channelDelegate.onConsoleMessage( - consoleMessage.message(), - consoleMessage.messageLevel().ordinal()); - } - return super.onConsoleMessage(consoleMessage); - } - - @Override - public void onProgressChanged(WebView view, int progress) { - super.onProgressChanged(view, progress); - - if (inAppBrowserDelegate != null) { - inAppBrowserDelegate.didChangeProgress(progress); - } - - - InAppWebView webView = (InAppWebView) view; - - if (webView.inAppWebViewClientCompat != null) { - webView.inAppWebViewClientCompat.loadCustomJavaScriptOnPageStarted(view); - } else if (webView.inAppWebViewClient != null) { - webView.inAppWebViewClient.loadCustomJavaScriptOnPageStarted(view); - } - - if (webView.channelDelegate != null) { - webView.channelDelegate.onProgressChanged(progress); - } - } - - @Override - public void onReceivedTitle(WebView view, String title) { - super.onReceivedTitle(view, title); - - if (inAppBrowserDelegate != null) { - inAppBrowserDelegate.didChangeTitle(title); - } - - InAppWebView webView = (InAppWebView) view; - - if (webView.channelDelegate != null) { - webView.channelDelegate.onTitleChanged(title); - } - } - - @Override - public void onReceivedIcon(WebView view, Bitmap icon) { - super.onReceivedIcon(view, icon); - - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - icon.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream); - try { - byteArrayOutputStream.close(); - } catch (IOException e) { - Log.e(LOG_TAG, "", e); - } - icon.recycle(); - - InAppWebView webView = (InAppWebView) view; - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedIcon(byteArrayOutputStream.toByteArray()); - } - } - - @Override - public void onReceivedTouchIconUrl(WebView view, - String url, - boolean precomposed) { - super.onReceivedTouchIconUrl(view, url, precomposed); - - InAppWebView webView = (InAppWebView) view; - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedTouchIconUrl(url, precomposed); - } - } - - @Nullable - protected ViewGroup getRootView() { - Activity activity = getActivity(); - if (activity == null) { - return null; - } - return (ViewGroup) activity.findViewById(android.R.id.content); - } - - private boolean onShowFileChooser(@NonNull ShowFileChooserRequest request, @NonNull ValueCallback filePathsCallback) { - WebViewChannelDelegate.ShowFileChooserCallback callback = new WebViewChannelDelegate.ShowFileChooserCallback() { - @Override - public boolean nonNullSuccess(@NonNull ShowFileChooserResponse response) { - if (response.isHandledByClient()) { - Uri[] uriArray = null; - if (response.getFilePaths() != null) { - uriArray = new Uri[response.getFilePaths().size()]; - for (int i = 0; i < response.getFilePaths().size(); i++) { - uriArray[i] = Uri.parse(response.getFilePaths().get(i)); - } - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - ((ValueCallback) filePathsCallback).onReceiveValue(uriArray); - } else { - ((ValueCallback) filePathsCallback).onReceiveValue(uriArray != null ? uriArray[0] : null); - } - return false; - } - return true; - } - - @Override - public void defaultBehaviour(@Nullable ShowFileChooserResponse response) { - String[] acceptTypes = request.getAcceptTypes().toArray(new String[0]); - boolean captureEnabled = request.isCaptureEnabled(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - boolean allowMultiple = request.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE; - startPickerIntent((ValueCallback) filePathsCallback, acceptTypes, allowMultiple, captureEnabled); - } else { - startPickerIntent((ValueCallback) filePathsCallback, acceptTypes.length > 0 ? acceptTypes[0] : "", captureEnabled); - } - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (inAppWebView != null && inAppWebView.channelDelegate != null && inAppWebView.customSettings.useOnShowFileChooser) { - inAppWebView.channelDelegate.onShowFileChooser(request, callback); - } else { - callback.defaultBehaviour(null); - } - - return true; - } - - protected void openFileChooser(ValueCallback filePathCallback, String acceptType) { - List acceptTypes = new ArrayList<>(); - acceptTypes.add(acceptType); - onShowFileChooser(new ShowFileChooserRequest(0, acceptTypes, false, null, null), filePathCallback); - } - - protected void openFileChooser(ValueCallback filePathCallback) { - List acceptTypes = new ArrayList<>(); - acceptTypes.add(""); - onShowFileChooser(new ShowFileChooserRequest(0, acceptTypes, false, null, null), filePathCallback); - } - - protected void openFileChooser(ValueCallback filePathCallback, String acceptType, String capture) { - List acceptTypes = new ArrayList<>(); - acceptTypes.add(acceptType); - onShowFileChooser(new ShowFileChooserRequest(0, acceptTypes, true, null, null), filePathCallback); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - @Override - public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) { - return onShowFileChooser(ShowFileChooserRequest.fromFileChooserParams(fileChooserParams), filePathCallback); - } - - @Override - public boolean onActivityResult(int requestCode, int resultCode, Intent data) { - if (filePathCallback == null && filePathCallbackLegacy == null) { - return true; - } - - // based off of which button was pressed, we get an activity result and a file - // the camera activity doesn't properly return the filename* (I think?) so we use - // this filename instead - switch (requestCode) { - case PICKER: - Uri[] results = null; - if (resultCode == RESULT_OK) { - results = getSelectedFiles(data, resultCode); - } - - if (filePathCallback != null) { - filePathCallback.onReceiveValue(results); - } - break; - - case PICKER_LEGACY: - Uri result = null; - if (resultCode == RESULT_OK) { - result = data != null ? data.getData() : getCapturedMediaFile(); - } - if (filePathCallbackLegacy != null) { - filePathCallbackLegacy.onReceiveValue(result); - } - break; - } - - filePathCallback = null; - filePathCallbackLegacy = null; - imageOutputFileUri = null; - videoOutputFileUri = null; - - return true; - } - - private Uri[] getSelectedFiles(Intent data, int resultCode) { - // we have one file selected - if (data != null && data.getData() != null) { - if (resultCode == RESULT_OK && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - return WebChromeClient.FileChooserParams.parseResult(resultCode, data); - } else { - return null; - } - } - - // we have multiple files selected - if (data != null && data.getClipData() != null) { - final int numSelectedFiles = data.getClipData().getItemCount(); - Uri[] result = new Uri[numSelectedFiles]; - for (int i = 0; i < numSelectedFiles; i++) { - result[i] = data.getClipData().getItemAt(i).getUri(); - } - return result; - } - - // we have a captured image or video file - Uri mediaUri = getCapturedMediaFile(); - if (mediaUri != null) { - return new Uri[]{mediaUri}; - } - - return null; - } - - private boolean isFileNotEmpty(Uri uri) { - Activity activity = getActivity(); - if (activity == null) { - return false; - } - - long length; - try { - AssetFileDescriptor descriptor = activity.getContentResolver().openAssetFileDescriptor(uri, "r"); - length = descriptor.getLength(); - descriptor.close(); - } catch (IOException e) { - return false; - } - - return length > 0; - } - - private Uri getCapturedMediaFile() { - if (imageOutputFileUri != null && isFileNotEmpty(imageOutputFileUri)) { - return imageOutputFileUri; - } - - if (videoOutputFileUri != null && isFileNotEmpty(videoOutputFileUri)) { - return videoOutputFileUri; - } - - return null; - } - - public void startPickerIntent(ValueCallback filePathCallback, String acceptType, boolean captureEnabled) { - filePathCallbackLegacy = filePathCallback; - - boolean images = acceptsImages(acceptType); - boolean video = acceptsVideo(acceptType); - - Intent pickerIntent = null; - - if (captureEnabled) { - if (!needsCameraPermission()) { - if (images) { - pickerIntent = getPhotoIntent(); - } else if (video) { - pickerIntent = getVideoIntent(); - } - } - } - if (pickerIntent == null) { - Intent fileChooserIntent = getFileChooserIntent(acceptType); - pickerIntent = Intent.createChooser(fileChooserIntent, ""); - - ArrayList extraIntents = new ArrayList<>(); - if (!needsCameraPermission()) { - if (images) { - extraIntents.add(getPhotoIntent()); - } - if (video) { - extraIntents.add(getVideoIntent()); - } - } - pickerIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents.toArray(new Parcelable[]{})); - } - - Activity activity = getActivity(); - if (activity != null && pickerIntent.resolveActivity(activity.getPackageManager()) != null) { - activity.startActivityForResult(pickerIntent, PICKER_LEGACY); - } else { - Log.d(LOG_TAG, "there is no Activity to handle this Intent"); - } - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public boolean startPickerIntent(final ValueCallback callback, final String[] acceptTypes, - final boolean allowMultiple, final boolean captureEnabled) { - filePathCallback = callback; - - boolean images = acceptsImages(acceptTypes); - boolean video = acceptsVideo(acceptTypes); - - Intent pickerIntent = null; - - if (captureEnabled) { - if (!needsCameraPermission()) { - if (images) { - pickerIntent = getPhotoIntent(); - } else if (video) { - pickerIntent = getVideoIntent(); - } - } - } - if (pickerIntent == null) { - ArrayList extraIntents = new ArrayList<>(); - if (!needsCameraPermission()) { - if (images) { - extraIntents.add(getPhotoIntent()); - } - if (video) { - extraIntents.add(getVideoIntent()); - } - } - - Intent fileSelectionIntent = getFileChooserIntent(acceptTypes, allowMultiple); - - pickerIntent = new Intent(Intent.ACTION_CHOOSER); - pickerIntent.putExtra(Intent.EXTRA_INTENT, fileSelectionIntent); - pickerIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents.toArray(new Parcelable[]{})); - } - - Activity activity = getActivity(); - if (activity != null && pickerIntent.resolveActivity(activity.getPackageManager()) != null) { - activity.startActivityForResult(pickerIntent, PICKER); - } else { - Log.d(LOG_TAG, "there is no Activity to handle this Intent"); - } - - return true; - } - - protected boolean needsCameraPermission() { - boolean needed = false; - - Activity activity = getActivity(); - if (activity == null) { - return true; - } - PackageManager packageManager = activity.getPackageManager(); - try { - String[] requestedPermissions = packageManager.getPackageInfo(activity.getApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS).requestedPermissions; - if (Arrays.asList(requestedPermissions).contains(Manifest.permission.CAMERA) - && ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { - needed = true; - } - } catch (PackageManager.NameNotFoundException e) { - needed = true; - } - - return needed; - } - - private Intent getPhotoIntent() { - Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - imageOutputFileUri = getOutputUri(MediaStore.ACTION_IMAGE_CAPTURE); - intent.putExtra(MediaStore.EXTRA_OUTPUT, imageOutputFileUri); - return intent; - } - - private Intent getVideoIntent() { - Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); - videoOutputFileUri = getOutputUri(MediaStore.ACTION_VIDEO_CAPTURE); - intent.putExtra(MediaStore.EXTRA_OUTPUT, videoOutputFileUri); - return intent; - } - - private Intent getFileChooserIntent(String acceptTypes) { - String _acceptTypes = acceptTypes; - if (acceptTypes.isEmpty()) { - _acceptTypes = DEFAULT_MIME_TYPES; - } - if (acceptTypes.matches("\\.\\w+")) { - _acceptTypes = getMimeTypeFromExtension(acceptTypes.replace(".", "")); - } - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType(_acceptTypes); - return intent; - } - - @RequiresApi(api = Build.VERSION_CODES.KITKAT) - private Intent getFileChooserIntent(String[] acceptTypes, boolean allowMultiple) { - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType("*/*"); - intent.putExtra(Intent.EXTRA_MIME_TYPES, getAcceptedMimeType(acceptTypes)); - intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, allowMultiple); - return intent; - } - - private Boolean acceptsAny(String[] types) { - if (isArrayEmpty(types)) { - return true; - } - - for (String type : types) { - if (type.equals("*/*")) { - return true; - } - } - - return false; - } - - private Boolean acceptsImages(String types) { - String mimeType = types; - if (types.matches("\\.\\w+")) { - mimeType = getMimeTypeFromExtension(types.replace(".", "")); - } - return mimeType.isEmpty() || mimeType.toLowerCase().contains("image"); - } - - private Boolean acceptsImages(String[] types) { - String[] mimeTypes = getAcceptedMimeType(types); - return acceptsAny(types) || arrayContainsString(mimeTypes, "image"); - } - - private Boolean acceptsVideo(String types) { - String mimeType = types; - if (types.matches("\\.\\w+")) { - mimeType = getMimeTypeFromExtension(types.replace(".", "")); - } - return mimeType.isEmpty() || mimeType.toLowerCase().contains("video"); - } - - private Boolean acceptsVideo(String[] types) { - String[] mimeTypes = getAcceptedMimeType(types); - return acceptsAny(types) || arrayContainsString(mimeTypes, "video"); - } - - private Boolean arrayContainsString(String[] array, String pattern) { - for (String content : array) { - if (content != null && content.contains(pattern)) { - return true; - } - } - return false; - } - - private String[] getAcceptedMimeType(String[] types) { - if (isArrayEmpty(types)) { - return new String[]{DEFAULT_MIME_TYPES}; - } - String[] mimeTypes = new String[types.length]; - for (int i = 0; i < types.length; i++) { - String t = types[i]; - // convert file extensions to mime types - if (t.matches("\\.\\w+")) { - String mimeType = getMimeTypeFromExtension(t.replace(".", "")); - mimeTypes[i] = mimeType; - } else { - mimeTypes[i] = t; - } - } - return mimeTypes; - } - - private String getMimeTypeFromExtension(String extension) { - String type = null; - if (extension != null) { - type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); - } - return type; - } - - @Nullable - private Uri getOutputUri(String intentType) { - File capturedFile = null; - try { - capturedFile = getCapturedFile(intentType); - } catch (IOException e) { - Log.e(LOG_TAG, "Error occurred while creating the File", e); - } - if (capturedFile == null) { - return null; - } - - // for versions below 6.0 (23) we use the old File creation & permissions model - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - return Uri.fromFile(capturedFile); - } - - Activity activity = getActivity(); - if (activity == null) { - return null; - } - // for versions 6.0+ (23) we use the FileProvider to avoid runtime permissions - String fileProviderAuthority = activity.getApplicationContext().getPackageName() + "." + - InAppWebViewFileProvider.fileProviderAuthorityExtension; - try { - return FileProvider.getUriForFile(activity.getApplicationContext(), - fileProviderAuthority, - capturedFile); - } catch (Exception e) { - Log.e(LOG_TAG, "", e); - } - return null; - } - - @Nullable - private File getCapturedFile(String intentType) throws IOException { - String prefix = ""; - String suffix = ""; - String dir = ""; - - if (intentType.equals(MediaStore.ACTION_IMAGE_CAPTURE)) { - prefix = "image"; - suffix = ".jpg"; - dir = Environment.DIRECTORY_PICTURES; - } else if (intentType.equals(MediaStore.ACTION_VIDEO_CAPTURE)) { - prefix = "video"; - suffix = ".mp4"; - dir = Environment.DIRECTORY_MOVIES; - } - - // for versions below 6.0 (23) we use the old File creation & permissions model - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - // only this Directory works on all tested Android versions - // ctx.getExternalFilesDir(dir) was failing on Android 5.0 (sdk 21) - File storageDir = Environment.getExternalStoragePublicDirectory(dir); - String filename = String.format("%s-%d%s", prefix, System.currentTimeMillis(), suffix); - return new File(storageDir, filename); - } - - Activity activity = getActivity(); - if (activity == null) { - return null; - } - File storageDir = activity.getApplicationContext().getExternalFilesDir(null); - return File.createTempFile(prefix, suffix, storageDir); - } - - private Boolean isArrayEmpty(String[] arr) { - // when our array returned from getAcceptTypes() has no values set from the webview - // i.e. , without any "accept" attr - // will be an array with one empty string element, afaik - return arr.length == 0 || (arr.length == 1 && arr[0].length() == 0); - } - - @Override - public void onPermissionRequest(final PermissionRequest request) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - final WebViewChannelDelegate.PermissionRequestCallback callback = new WebViewChannelDelegate.PermissionRequestCallback() { - @Override - public boolean nonNullSuccess(@NonNull PermissionResponse response) { - Integer action = response.getAction(); - if (action != null) { - switch (action) { - case 1: - String[] resources = new String[response.getResources().size()]; - resources = response.getResources().toArray(resources); - request.grant(resources); - break; - case 0: - default: - request.deny(); - } - return false; - } - return true; - } - - @Override - public void defaultBehaviour(@Nullable PermissionResponse response) { - request.deny(); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (inAppWebView != null && inAppWebView.channelDelegate != null) { - inAppWebView.channelDelegate.onPermissionRequest(request.getOrigin().toString(), - Arrays.asList(request.getResources()), null, callback); - } else { - callback.defaultBehaviour(null); - } - } - } - - @Override - public void onRequestFocus(WebView view) { - if (inAppWebView != null && inAppWebView.channelDelegate != null) { - inAppWebView.channelDelegate.onRequestFocus(); - } - } - - @Override - public void onPermissionRequestCanceled(PermissionRequest request) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && - inAppWebView != null && inAppWebView.channelDelegate != null) { - inAppWebView.channelDelegate.onPermissionRequestCanceled(request.getOrigin().toString(), - Arrays.asList(request.getResources())); - } - } - - @Nullable - private Activity getActivity() { - if (inAppBrowserDelegate != null) { - return inAppBrowserDelegate.getActivity(); - } else if (plugin != null) { - return plugin.activity; - } - return null; - } - - public void dispose() { - for (Map.Entry dialog : dialogs.entrySet()) { - dialog.getValue().cancel(); - dialog.getKey().dismiss(); - } - dialogs.clear(); - if (plugin != null && plugin.activityPluginBinding != null) { - plugin.activityPluginBinding.removeActivityResultListener(this); - } - if (inAppBrowserDelegate != null) { - inAppBrowserDelegate.getActivityResultListeners().clear(); - inAppBrowserDelegate = null; - } - filePathCallbackLegacy = null; - filePathCallback = null; - videoOutputFileUri = null; - imageOutputFileUri = null; - inAppWebView = null; - plugin = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClient.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClient.java deleted file mode 100755 index aa59495267..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClient.java +++ /dev/null @@ -1,822 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview; - -import android.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.graphics.Bitmap; -import android.net.Uri; -import android.net.http.SslError; -import android.os.Build; -import android.os.Message; -import android.util.Log; -import android.view.KeyEvent; -import android.webkit.ClientCertRequest; -import android.webkit.CookieManager; -import android.webkit.CookieSyncManager; -import android.webkit.HttpAuthHandler; -import android.webkit.RenderProcessGoneDetail; -import android.webkit.SafeBrowsingResponse; -import android.webkit.SslErrorHandler; -import android.webkit.ValueCallback; -import android.webkit.WebResourceError; -import android.webkit.WebResourceRequest; -import android.webkit.WebResourceResponse; -import android.webkit.WebView; -import android.webkit.WebViewClient; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; -import androidx.webkit.WebResourceRequestCompat; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.Util; -import com.pichillilorenzo.flutter_inappwebview_android.credential_database.CredentialDatabase; -import com.pichillilorenzo.flutter_inappwebview_android.in_app_browser.InAppBrowserDelegate; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.JavaScriptBridgeJS; -import com.pichillilorenzo.flutter_inappwebview_android.types.ClientCertChallenge; -import com.pichillilorenzo.flutter_inappwebview_android.types.ClientCertResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.CustomSchemeResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.HttpAuthResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.HttpAuthenticationChallenge; -import com.pichillilorenzo.flutter_inappwebview_android.types.NavigationAction; -import com.pichillilorenzo.flutter_inappwebview_android.types.NavigationActionPolicy; -import com.pichillilorenzo.flutter_inappwebview_android.types.ServerTrustAuthResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.ServerTrustChallenge; -import com.pichillilorenzo.flutter_inappwebview_android.types.URLCredential; -import com.pichillilorenzo.flutter_inappwebview_android.types.URLProtectionSpace; -import com.pichillilorenzo.flutter_inappwebview_android.types.URLRequest; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebResourceErrorExt; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebResourceRequestExt; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebResourceResponseExt; -import com.pichillilorenzo.flutter_inappwebview_android.webview.WebViewChannelDelegate; - -import java.io.ByteArrayInputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; - -public class InAppWebViewClient extends WebViewClient { - - protected static final String LOG_TAG = "IAWebViewClient"; - private InAppBrowserDelegate inAppBrowserDelegate; - private static int previousAuthRequestFailureCount = 0; - private static List credentialsProposed = null; - - public InAppWebViewClient(InAppBrowserDelegate inAppBrowserDelegate) { - super(); - this.inAppBrowserDelegate = inAppBrowserDelegate; - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - @Override - public boolean shouldOverrideUrlLoading(@NonNull WebView view, @NonNull WebResourceRequest request) { - InAppWebView webView = (InAppWebView) view; - - if (allowSyncUrlLoading(webView, request.getUrl().toString())) { - // Allow the request synchronously. - return false; - } - - if (webView.customSettings.useShouldOverrideUrlLoading) { - boolean isRedirect = false; - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT)) { - isRedirect = WebResourceRequestCompat.isRedirect(request); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - isRedirect = request.isRedirect(); - } - onShouldOverrideUrlLoading( - webView, - request.getUrl().toString(), - request.getMethod(), - request.getRequestHeaders(), - request.isForMainFrame(), - request.hasGesture(), - isRedirect); - } - if (webView.customSettings.regexToCancelSubFramesLoading != null && !request.isForMainFrame()) { - Matcher m = webView.customSettings.regexToCancelSubFramesLoading.matcher(request.getUrl().toString()); - return m.matches(); - } - if (webView.customSettings.useShouldOverrideUrlLoading) { - // There isn't any way to load an URL for a frame that is not the main frame, - // so if the request is not for the main frame, the navigation is allowed. - return request.isForMainFrame(); - } - - return false; - } - - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - InAppWebView webView = (InAppWebView) view; - - if (allowSyncUrlLoading(webView, url)) { - // Allow the request synchronously. - return false; - } - - if (webView.customSettings.useShouldOverrideUrlLoading) { - onShouldOverrideUrlLoading(webView, url, "GET", null,true, false, false); - return true; - } - return false; - } - - private boolean allowSyncUrlLoading(InAppWebView webView, String url) { - if (webView.customSettings.regexToAllowSyncUrlLoading != null) { - Matcher m = webView.customSettings.regexToAllowSyncUrlLoading.matcher(url); - if (m.matches()) { - Log.d(LOG_TAG, "Request '" + url + "' automatically allowed as it is a match for 'regexToAllowSyncUrlLoading'."); - return true; - } - } - return false; - } - - private void allowShouldOverrideUrlLoading(WebView webView, String url, - @Nullable Map headers, - boolean isForMainFrame) { - if (isForMainFrame) { - // There isn't any way to load an URL for a frame that is not the main frame, - // so call this only on main frame. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && headers != null) - webView.loadUrl(url, headers); - else - webView.loadUrl(url); - } - } - public void onShouldOverrideUrlLoading(final InAppWebView webView, final String url, - final String method, - @Nullable final Map headers, - final boolean isForMainFrame, boolean hasGesture, - boolean isRedirect) { - URLRequest request = new URLRequest(url, method, null, headers); - NavigationAction navigationAction = new NavigationAction( - request, - isForMainFrame, - hasGesture, - isRedirect - ); - - final WebViewChannelDelegate.ShouldOverrideUrlLoadingCallback callback = new WebViewChannelDelegate.ShouldOverrideUrlLoadingCallback() { - @Override - public boolean nonNullSuccess(@NonNull NavigationActionPolicy result) { - switch (result) { - case ALLOW: - allowShouldOverrideUrlLoading(webView, url, headers, isForMainFrame); - break; - case CANCEL: - default: - break; - } - return false; - } - - @Override - public void defaultBehaviour(@Nullable NavigationActionPolicy result) { - allowShouldOverrideUrlLoading(webView, url, headers, isForMainFrame); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (webView.channelDelegate != null) { - webView.channelDelegate.shouldOverrideUrlLoading(navigationAction, callback); - } else { - callback.defaultBehaviour(null); - } - } - - @SuppressLint("RestrictedApi") - public void loadCustomJavaScriptOnPageStarted(WebView view) { - InAppWebView webView = (InAppWebView) view; - - if (!WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { - String source = webView.userContentController.generateWrappedCodeForDocumentStart(); - webView.evaluateJavascript(source, (ValueCallback) null); - } - } - - public void loadCustomJavaScriptOnPageFinished(WebView view) { - InAppWebView webView = (InAppWebView) view; - - if (!WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { - String source = webView.userContentController.generateWrappedCodeForDocumentEnd(); - webView.evaluateJavascript(source, (ValueCallback) null); - } - } - - @Override - public void onPageStarted(WebView view, String url, Bitmap favicon) { - final InAppWebView webView = (InAppWebView) view; - webView.isLoading = true; - webView.disposeWebMessageChannels(); - webView.userContentController.resetContentWorlds(); - loadCustomJavaScriptOnPageStarted(webView); - - super.onPageStarted(view, url, favicon); - - if (inAppBrowserDelegate != null) { - inAppBrowserDelegate.didStartNavigation(url); - } - - if (webView.channelDelegate != null) { - webView.channelDelegate.onLoadStart(url); - } - } - - public void onPageFinished(WebView view, String url) { - final InAppWebView webView = (InAppWebView) view; - webView.isLoading = false; - loadCustomJavaScriptOnPageFinished(webView); - previousAuthRequestFailureCount = 0; - credentialsProposed = null; - - super.onPageFinished(view, url); - - if (inAppBrowserDelegate != null) { - inAppBrowserDelegate.didFinishNavigation(url); - } - - // WebView not storing cookies reliable to local device storage - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - CookieManager.getInstance().flush(); - } else { - CookieSyncManager.getInstance().sync(); - } - - String js = JavaScriptBridgeJS.PLATFORM_READY_JS_SOURCE(); - webView.evaluateJavascript(js, (ValueCallback) null); - - if (webView.channelDelegate != null) { - webView.channelDelegate.onLoadStop(url); - } - } - - @Override - public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) { - super.doUpdateVisitedHistory(view, url, isReload); - - // url argument sometimes doesn't contain the new changed URL, so we get it again from the webview. - url = view.getUrl(); - - if (inAppBrowserDelegate != null) { - inAppBrowserDelegate.didUpdateVisitedHistory(url); - } - - final InAppWebView webView = (InAppWebView) view; - if (webView.channelDelegate != null) { - webView.channelDelegate.onUpdateVisitedHistory(url, isReload); - } - } - - @RequiresApi(api = Build.VERSION_CODES.M) - @Override - public void onReceivedError(WebView view, @NonNull WebResourceRequest request, @NonNull WebResourceError error) { - final InAppWebView webView = (InAppWebView) view; - - if (request.isForMainFrame()) { - if (webView.customSettings.disableDefaultErrorPage) { - webView.stopLoading(); - webView.loadUrl("about:blank"); - } - - webView.isLoading = false; - previousAuthRequestFailureCount = 0; - credentialsProposed = null; - - if (inAppBrowserDelegate != null) { - inAppBrowserDelegate.didFailNavigation(request.getUrl().toString(), error.getErrorCode(), error.getDescription().toString()); - } - } - - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedError( - WebResourceRequestExt.fromWebResourceRequest(request), - WebResourceErrorExt.fromWebResourceError(error)); - } - } - - @SuppressLint("RestrictedApi") - @Override - public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { - final InAppWebView webView = (InAppWebView) view; - - if (webView.customSettings.disableDefaultErrorPage) { - webView.stopLoading(); - webView.loadUrl("about:blank"); - } - - webView.isLoading = false; - previousAuthRequestFailureCount = 0; - credentialsProposed = null; - - if (inAppBrowserDelegate != null) { - inAppBrowserDelegate.didFailNavigation(failingUrl, errorCode, description); - } - - WebResourceRequestExt request = new WebResourceRequestExt( - failingUrl, - null, - false, - false, - true, - "GET"); - - WebResourceErrorExt error = new WebResourceErrorExt( - errorCode, - description - ); - - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedError( - request, - error); - } - - super.onReceivedError(view, errorCode, description, failingUrl); - } - - @RequiresApi(api = Build.VERSION_CODES.M) - @Override - public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) { - super.onReceivedHttpError(view, request, errorResponse); - - final InAppWebView webView = (InAppWebView) view; - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedHttpError( - WebResourceRequestExt.fromWebResourceRequest(request), - WebResourceResponseExt.fromWebResourceResponse(errorResponse)); - } - } - - @Override - public void onReceivedHttpAuthRequest(final WebView view, final HttpAuthHandler handler, final String host, final String realm) { - final String url = view.getUrl(); - String protocol = "https"; - int port = 0; - - if (url != null) { - try { - URI uri = new URI(url); - protocol = uri.getScheme(); - port = uri.getPort(); - } catch (URISyntaxException e) { - Log.e(LOG_TAG, "", e); - } - } - - previousAuthRequestFailureCount++; - - if (credentialsProposed == null) - credentialsProposed = CredentialDatabase.getInstance(view.getContext()).getHttpAuthCredentials(host, protocol, realm, port); - - URLCredential credentialProposed = null; - if (credentialsProposed != null && !credentialsProposed.isEmpty()) { - credentialProposed = credentialsProposed.get(0); - } - - URLProtectionSpace protectionSpace = new URLProtectionSpace(host, protocol, realm, port, view.getCertificate(), null); - HttpAuthenticationChallenge challenge = new HttpAuthenticationChallenge(protectionSpace, previousAuthRequestFailureCount, credentialProposed); - - final InAppWebView webView = (InAppWebView) view; - final String finalProtocol = protocol; - final int finalPort = port; - final WebViewChannelDelegate.ReceivedHttpAuthRequestCallback callback = new WebViewChannelDelegate.ReceivedHttpAuthRequestCallback() { - @Override - public boolean nonNullSuccess(@NonNull HttpAuthResponse response) { - Integer action = response.getAction(); - if (action != null) { - switch (action) { - case 1: - String username = response.getUsername(); - String password = response.getPassword(); - boolean permanentPersistence = response.isPermanentPersistence(); - if (permanentPersistence) { - CredentialDatabase.getInstance(view.getContext()) - .setHttpAuthCredential(host, finalProtocol, realm, finalPort, username, password); - } - handler.proceed(username, password); - break; - case 2: - if (!credentialsProposed.isEmpty()) { - URLCredential credential = credentialsProposed.remove(0); - handler.proceed(credential.getUsername(), credential.getPassword()); - } else { - handler.cancel(); - } - // used custom CredentialDatabase! - // handler.useHttpAuthUsernamePassword(); - break; - case 0: - default: - credentialsProposed = null; - previousAuthRequestFailureCount = 0; - handler.cancel(); - } - - return false; - } - - return true; - } - - @Override - public void defaultBehaviour(@Nullable HttpAuthResponse result) { - InAppWebViewClient.super.onReceivedHttpAuthRequest(view, handler, host, realm); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedHttpAuthRequest(challenge, callback); - } else { - callback.defaultBehaviour(null); - } - } - - @Override - public void onReceivedSslError(final WebView view, final SslErrorHandler handler, final SslError sslError) { - final String url = sslError.getUrl(); - String host = ""; - String protocol = "https"; - int port = 0; - - try { - URI uri = new URI(url); - host = uri.getHost(); - protocol = uri.getScheme(); - port = uri.getPort(); - } catch (URISyntaxException e) { - Log.e(LOG_TAG, "", e); - } - - URLProtectionSpace protectionSpace = new URLProtectionSpace(host, protocol, null, port, sslError.getCertificate(), sslError); - ServerTrustChallenge challenge = new ServerTrustChallenge(protectionSpace); - - final InAppWebView webView = (InAppWebView) view; - final WebViewChannelDelegate.ReceivedServerTrustAuthRequestCallback callback = new WebViewChannelDelegate.ReceivedServerTrustAuthRequestCallback() { - @Override - public boolean nonNullSuccess(@NonNull ServerTrustAuthResponse response) { - Integer action = response.getAction(); - if (action != null) { - switch (action) { - case 1: - handler.proceed(); - break; - case 0: - default: - handler.cancel(); - } - - return false; - } - - return true; - } - - @Override - public void defaultBehaviour(@Nullable ServerTrustAuthResponse result) { - InAppWebViewClient.super.onReceivedSslError(view, handler, sslError); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedServerTrustAuthRequest(challenge, callback); - } else { - callback.defaultBehaviour(null); - } - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - @Override - public void onReceivedClientCertRequest(final WebView view, final ClientCertRequest request) { - final String url = view.getUrl(); - final String host = request.getHost(); - String protocol = "https"; - final int port = request.getPort(); - - if (url != null) { - try { - URI uri = new URI(url); - protocol = uri.getScheme(); - } catch (URISyntaxException e) { - Log.e(LOG_TAG, "", e); - } - } - - URLProtectionSpace protectionSpace = new URLProtectionSpace(host, protocol, null, port, view.getCertificate(), null); - ClientCertChallenge challenge = new ClientCertChallenge(protectionSpace, request.getPrincipals(), request.getKeyTypes()); - - final InAppWebView webView = (InAppWebView) view; - final WebViewChannelDelegate.ReceivedClientCertRequestCallback callback = new WebViewChannelDelegate.ReceivedClientCertRequestCallback() { - @Override - public boolean nonNullSuccess(@NonNull ClientCertResponse response) { - Integer action = response.getAction(); - if (action != null && webView.plugin != null) { - switch (action) { - case 1: - { - String certificatePath = (String) response.getCertificatePath(); - String certificatePassword = (String) response.getCertificatePassword(); - String keyStoreType = (String) response.getKeyStoreType(); - Util.PrivateKeyAndCertificates privateKeyAndCertificates = - Util.loadPrivateKeyAndCertificate(webView.plugin, certificatePath, certificatePassword, keyStoreType); - if (privateKeyAndCertificates != null) { - request.proceed(privateKeyAndCertificates.privateKey, privateKeyAndCertificates.certificates); - } else { - request.cancel(); - } - } - break; - case 2: - request.ignore(); - break; - case 0: - default: - request.cancel(); - } - - return false; - } - - return true; - } - - @Override - public void defaultBehaviour(@Nullable ClientCertResponse result) { - InAppWebViewClient.super.onReceivedClientCertRequest(view, request); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedClientCertRequest(challenge, callback); - } else { - callback.defaultBehaviour(null); - } - } - - @Override - public void onScaleChanged(WebView view, float oldScale, float newScale) { - super.onScaleChanged(view, oldScale, newScale); - final InAppWebView webView = (InAppWebView) view; - webView.zoomScale = newScale / Util.getPixelDensity(webView.getContext()); - - if (webView.channelDelegate != null) { - webView.channelDelegate.onZoomScaleChanged(oldScale, newScale); - } - } - - @RequiresApi(api = Build.VERSION_CODES.O_MR1) - @Override - public void onSafeBrowsingHit(final WebView view, final WebResourceRequest request, final int threatType, final SafeBrowsingResponse callback) { - final InAppWebView webView = (InAppWebView) view; - final WebViewChannelDelegate.SafeBrowsingHitCallback resultCallback = new WebViewChannelDelegate.SafeBrowsingHitCallback() { - @Override - public boolean nonNullSuccess(@NonNull com.pichillilorenzo.flutter_inappwebview_android.types.SafeBrowsingResponse response) { - Integer action = response.getAction(); - if (action != null) { - boolean report = response.isReport(); - switch (action) { - case 0: - callback.backToSafety(report); - break; - case 1: - callback.proceed(report); - break; - case 2: - default: - callback.showInterstitial(report); - } - - return false; - } - - return true; - } - - @Override - public void defaultBehaviour(@Nullable com.pichillilorenzo.flutter_inappwebview_android.types.SafeBrowsingResponse result) { - InAppWebViewClient.super.onSafeBrowsingHit(view, request, threatType, callback); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (webView.channelDelegate != null) { - webView.channelDelegate.onSafeBrowsingHit(request.getUrl().toString(), threatType, resultCallback); - } else { - resultCallback.defaultBehaviour(null); - } - } - - public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequestExt request) { - final InAppWebView webView = (InAppWebView) view; - - if (webView.webViewAssetLoaderExt != null && webView.webViewAssetLoaderExt.loader != null) { - try { - final Uri uri = Uri.parse(request.getUrl()); - WebResourceResponse webResourceResponse = webView.webViewAssetLoaderExt.loader.shouldInterceptRequest(uri); - if (webResourceResponse != null) { - return webResourceResponse; - } - } catch (Exception e) { - Log.e(LOG_TAG, "", e); - } - } - - if (webView.customSettings.useShouldInterceptRequest) { - WebResourceResponseExt response = null; - if (webView.channelDelegate != null) { - try { - response = webView.channelDelegate.shouldInterceptRequest(request); - } catch (InterruptedException e) { - Log.e(LOG_TAG, "", e); - return null; - } - } - - if (response != null) { - String contentType = response.getContentType(); - String contentEncoding = response.getContentEncoding(); - byte[] data = response.getData(); - Map responseHeaders = response.getHeaders(); - Integer statusCode = response.getStatusCode(); - String reasonPhrase = response.getReasonPhrase(); - - ByteArrayInputStream inputStream = (data != null) ? new ByteArrayInputStream(data) : null; - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && statusCode != null && reasonPhrase != null) { - return new WebResourceResponse(contentType, contentEncoding, statusCode, reasonPhrase, responseHeaders, inputStream); - } else { - return new WebResourceResponse(contentType, contentEncoding, inputStream); - } - } - - return null; - } - - final String url = request.getUrl(); - String scheme = url.split(":")[0].toLowerCase(); - try { - scheme = Uri.parse(request.getUrl()).getScheme(); - } catch (Exception ignored) {} - - if (webView.customSettings.resourceCustomSchemes != null && webView.customSettings.resourceCustomSchemes.contains(scheme)) { - CustomSchemeResponse customSchemeResponse = null; - if (webView.channelDelegate != null) { - try { - customSchemeResponse = webView.channelDelegate.onLoadResourceWithCustomScheme(request); - } catch (InterruptedException e) { - Log.e(LOG_TAG, "", e); - return null; - } - } - - if (customSchemeResponse != null) { - WebResourceResponse response = null; - try { - response = webView.contentBlockerHandler.checkUrl(webView, request, customSchemeResponse.getContentType()); - } catch (Exception e) { - Log.e(LOG_TAG, "", e); - } - if (response != null) - return response; - return new WebResourceResponse(customSchemeResponse.getContentType(), - customSchemeResponse.getContentType(), - new ByteArrayInputStream(customSchemeResponse.getData())); - } - } - - WebResourceResponse response = null; - if (!webView.contentBlockerHandler.getRuleList().isEmpty()) { - try { - response = webView.contentBlockerHandler.checkUrl(webView, request); - } catch (Exception e) { - Log.e(LOG_TAG, "", e); - } - } - return response; - } - - @Override - public WebResourceResponse shouldInterceptRequest(WebView view, final String url) { - WebResourceRequestExt requestExt = new WebResourceRequestExt( - url, null, false, - false, true, "GET" - ); - return shouldInterceptRequest(view, requestExt); - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - @Override - public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { - WebResourceRequestExt requestExt = WebResourceRequestExt.fromWebResourceRequest(request); - return shouldInterceptRequest(view, requestExt); - } - - @Override - public void onFormResubmission(final WebView view, final Message dontResend, final Message resend) { - final InAppWebView webView = (InAppWebView) view; - final WebViewChannelDelegate.FormResubmissionCallback callback = new WebViewChannelDelegate.FormResubmissionCallback() { - @Override - public boolean nonNullSuccess(@NonNull Integer action) { - switch (action) { - case 0: - resend.sendToTarget(); - break; - case 1: - default: - dontResend.sendToTarget(); - } - return false; - } - - @Override - public void defaultBehaviour(@Nullable Integer result) { - InAppWebViewClient.super.onFormResubmission(view, dontResend, resend); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (webView.channelDelegate != null) { - webView.channelDelegate.onFormResubmission(webView.getUrl(), callback); - } else { - callback.defaultBehaviour(null); - } - } - - @Override - public void onPageCommitVisible(WebView view, String url) { - super.onPageCommitVisible(view, url); - - final InAppWebView webView = (InAppWebView) view; - if (webView.channelDelegate != null) { - webView.channelDelegate.onPageCommitVisible(url); - } - } - - @RequiresApi(api = Build.VERSION_CODES.O) - @Override - public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) { - final InAppWebView webView = (InAppWebView) view; - - if (webView.customSettings.useOnRenderProcessGone && webView.channelDelegate != null) { - boolean didCrash = detail.didCrash(); - int rendererPriorityAtExit = detail.rendererPriorityAtExit(); - webView.channelDelegate.onRenderProcessGone(didCrash, rendererPriorityAtExit); - return true; - } - - return super.onRenderProcessGone(view, detail); - } - - @Override - public void onReceivedLoginRequest(WebView view, String realm, String account, String args) { - final InAppWebView webView = (InAppWebView) view; - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedLoginRequest(realm, account, args); - } - } - - @Override - public void onUnhandledKeyEvent(WebView view, KeyEvent event) {} - - public void dispose() { - if (inAppBrowserDelegate != null) { - inAppBrowserDelegate = null; - } - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClientCompat.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClientCompat.java deleted file mode 100755 index fed10340ce..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClientCompat.java +++ /dev/null @@ -1,848 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview; - -import android.annotation.SuppressLint; -import android.graphics.Bitmap; -import android.net.Uri; -import android.net.http.SslError; -import android.os.Build; -import android.os.Message; -import android.util.Log; -import android.view.KeyEvent; -import android.webkit.ClientCertRequest; -import android.webkit.CookieManager; -import android.webkit.CookieSyncManager; -import android.webkit.HttpAuthHandler; -import android.webkit.RenderProcessGoneDetail; -import android.webkit.SslErrorHandler; -import android.webkit.ValueCallback; -import android.webkit.WebResourceRequest; -import android.webkit.WebResourceResponse; -import android.webkit.WebView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; -import androidx.webkit.SafeBrowsingResponseCompat; -import androidx.webkit.WebResourceErrorCompat; -import androidx.webkit.WebResourceRequestCompat; -import androidx.webkit.WebViewClientCompat; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.Util; -import com.pichillilorenzo.flutter_inappwebview_android.credential_database.CredentialDatabase; -import com.pichillilorenzo.flutter_inappwebview_android.in_app_browser.InAppBrowserDelegate; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.JavaScriptBridgeJS; -import com.pichillilorenzo.flutter_inappwebview_android.types.ClientCertChallenge; -import com.pichillilorenzo.flutter_inappwebview_android.types.ClientCertResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.CustomSchemeResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.HttpAuthResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.HttpAuthenticationChallenge; -import com.pichillilorenzo.flutter_inappwebview_android.types.NavigationAction; -import com.pichillilorenzo.flutter_inappwebview_android.types.NavigationActionPolicy; -import com.pichillilorenzo.flutter_inappwebview_android.types.ServerTrustAuthResponse; -import com.pichillilorenzo.flutter_inappwebview_android.types.ServerTrustChallenge; -import com.pichillilorenzo.flutter_inappwebview_android.types.URLCredential; -import com.pichillilorenzo.flutter_inappwebview_android.types.URLProtectionSpace; -import com.pichillilorenzo.flutter_inappwebview_android.types.URLRequest; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebResourceErrorExt; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebResourceRequestExt; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebResourceResponseExt; -import com.pichillilorenzo.flutter_inappwebview_android.webview.WebViewChannelDelegate; - -import java.io.ByteArrayInputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; - -public class InAppWebViewClientCompat extends WebViewClientCompat { - - protected static final String LOG_TAG = "IAWebViewClientCompat"; - private InAppBrowserDelegate inAppBrowserDelegate; - private static int previousAuthRequestFailureCount = 0; - private static List credentialsProposed = null; - - public InAppWebViewClientCompat(InAppBrowserDelegate inAppBrowserDelegate) { - super(); - this.inAppBrowserDelegate = inAppBrowserDelegate; - } - - @RequiresApi(Build.VERSION_CODES.LOLLIPOP) - @Override - public boolean shouldOverrideUrlLoading(@NonNull WebView view, @NonNull WebResourceRequest request) { - InAppWebView webView = (InAppWebView) view; - - if (allowSyncUrlLoading(webView, request.getUrl().toString())) { - // Allow the request synchronously. - return false; - } - - if (webView.customSettings.useShouldOverrideUrlLoading) { - boolean isRedirect = false; - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT)) { - isRedirect = WebResourceRequestCompat.isRedirect(request); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - isRedirect = request.isRedirect(); - } - onShouldOverrideUrlLoading( - webView, - request.getUrl().toString(), - request.getMethod(), - request.getRequestHeaders(), - request.isForMainFrame(), - request.hasGesture(), - isRedirect); - } - if (webView.customSettings.regexToCancelSubFramesLoading != null && !request.isForMainFrame()) { - Matcher m = webView.customSettings.regexToCancelSubFramesLoading.matcher(request.getUrl().toString()); - return m.matches(); - } - if (webView.customSettings.useShouldOverrideUrlLoading) { - // There isn't any way to load an URL for a frame that is not the main frame, - // so if the request is not for the main frame, the navigation is allowed. - return request.isForMainFrame(); - } - - return false; - } - - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - InAppWebView webView = (InAppWebView) view; - - if (allowSyncUrlLoading(webView, url)) { - // Allow the request synchronously. - return false; - } - - if (webView.customSettings.useShouldOverrideUrlLoading) { - onShouldOverrideUrlLoading(webView, url, "GET", null,true, false, false); - return true; - } - return false; - } - - private boolean allowSyncUrlLoading(InAppWebView webView, String url) { - if (webView.customSettings.regexToAllowSyncUrlLoading != null) { - Matcher m = webView.customSettings.regexToAllowSyncUrlLoading.matcher(url); - if (m.matches()) { - Log.d(LOG_TAG, "Request '" + url + "' automatically allowed as it is a match for 'regexToAllowSyncUrlLoading'."); - return true; - } - } - return false; - } - - private void allowShouldOverrideUrlLoading(WebView webView, String url, - @Nullable Map headers, - boolean isForMainFrame) { - if (isForMainFrame) { - // There isn't any way to load an URL for a frame that is not the main frame, - // so call this only on main frame. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && headers != null) - webView.loadUrl(url, headers); - else - webView.loadUrl(url); - } - } - public void onShouldOverrideUrlLoading(final InAppWebView webView, final String url, - final String method, - @Nullable final Map headers, - final boolean isForMainFrame, boolean hasGesture, - boolean isRedirect) { - URLRequest request = new URLRequest(url, method, null, headers); - NavigationAction navigationAction = new NavigationAction( - request, - isForMainFrame, - hasGesture, - isRedirect - ); - - final WebViewChannelDelegate.ShouldOverrideUrlLoadingCallback callback = new WebViewChannelDelegate.ShouldOverrideUrlLoadingCallback() { - @Override - public boolean nonNullSuccess(@NonNull NavigationActionPolicy result) { - switch (result) { - case ALLOW: - allowShouldOverrideUrlLoading(webView, url, headers, isForMainFrame); - break; - case CANCEL: - default: - break; - } - return false; - } - - @Override - public void defaultBehaviour(@Nullable NavigationActionPolicy result) { - allowShouldOverrideUrlLoading(webView, url, headers, isForMainFrame); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (webView.channelDelegate != null) { - webView.channelDelegate.shouldOverrideUrlLoading(navigationAction, callback); - } else { - callback.defaultBehaviour(null); - } - } - - @SuppressLint("RestrictedApi") - public void loadCustomJavaScriptOnPageStarted(WebView view) { - InAppWebView webView = (InAppWebView) view; - - if (!WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { - String source = webView.userContentController.generateWrappedCodeForDocumentStart(); - webView.evaluateJavascript(source, (ValueCallback) null); - } - } - - public void loadCustomJavaScriptOnPageFinished(WebView view) { - InAppWebView webView = (InAppWebView) view; - - if (!WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { - String source = webView.userContentController.generateWrappedCodeForDocumentEnd(); - webView.evaluateJavascript(source, (ValueCallback) null); - } - } - - @Override - public void onPageStarted(WebView view, String url, Bitmap favicon) { - final InAppWebView webView = (InAppWebView) view; - webView.isLoading = true; - webView.disposeWebMessageChannels(); - webView.userContentController.resetContentWorlds(); - loadCustomJavaScriptOnPageStarted(webView); - - super.onPageStarted(view, url, favicon); - - if (inAppBrowserDelegate != null) { - inAppBrowserDelegate.didStartNavigation(url); - } - - if (webView.channelDelegate != null) { - webView.channelDelegate.onLoadStart(url); - } - } - - public void onPageFinished(WebView view, String url) { - final InAppWebView webView = (InAppWebView) view; - webView.isLoading = false; - loadCustomJavaScriptOnPageFinished(webView); - previousAuthRequestFailureCount = 0; - credentialsProposed = null; - - super.onPageFinished(view, url); - - if (inAppBrowserDelegate != null) { - inAppBrowserDelegate.didFinishNavigation(url); - } - - // WebView not storing cookies reliable to local device storage - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - CookieManager.getInstance().flush(); - } else { - CookieSyncManager.getInstance().sync(); - } - - String js = JavaScriptBridgeJS.PLATFORM_READY_JS_SOURCE(); - webView.evaluateJavascript(js, (ValueCallback) null); - - if (webView.channelDelegate != null) { - webView.channelDelegate.onLoadStop(url); - } - } - - @Override - public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) { - super.doUpdateVisitedHistory(view, url, isReload); - - // url argument sometimes doesn't contain the new changed URL, so we get it again from the webview. - url = view.getUrl(); - - if (inAppBrowserDelegate != null) { - inAppBrowserDelegate.didUpdateVisitedHistory(url); - } - - final InAppWebView webView = (InAppWebView) view; - if (webView.channelDelegate != null) { - webView.channelDelegate.onUpdateVisitedHistory(url, isReload); - } - } - - @RequiresApi(api = Build.VERSION_CODES.M) - @Override - public void onReceivedError(@NonNull WebView view, - @NonNull WebResourceRequest request, - @NonNull WebResourceErrorCompat error) { - final InAppWebView webView = (InAppWebView) view; - - if (request.isForMainFrame()) { - if (webView.customSettings.disableDefaultErrorPage) { - webView.stopLoading(); - webView.loadUrl("about:blank"); - } - - webView.isLoading = false; - previousAuthRequestFailureCount = 0; - credentialsProposed = null; - - if (inAppBrowserDelegate != null) { - int type = -1; - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_RESOURCE_ERROR_GET_CODE)) { - type = error.getErrorCode(); - } - String description = ""; - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_RESOURCE_ERROR_GET_DESCRIPTION)) { - description = error.getDescription().toString(); - } - inAppBrowserDelegate.didFailNavigation(request.getUrl().toString(), type, description); - } - } - - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedError( - WebResourceRequestExt.fromWebResourceRequest(request), - WebResourceErrorExt.fromWebResourceError(error)); - } - } - - @SuppressLint("RestrictedApi") - @Override - public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { - final InAppWebView webView = (InAppWebView) view; - - if (webView.customSettings.disableDefaultErrorPage) { - webView.stopLoading(); - webView.loadUrl("about:blank"); - } - - webView.isLoading = false; - previousAuthRequestFailureCount = 0; - credentialsProposed = null; - - if (inAppBrowserDelegate != null) { - inAppBrowserDelegate.didFailNavigation(failingUrl, errorCode, description); - } - - WebResourceRequestExt request = new WebResourceRequestExt( - failingUrl, - null, - false, - false, - true, - "GET"); - - WebResourceErrorExt error = new WebResourceErrorExt( - errorCode, - description - ); - - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedError( - request, - error); - } - - super.onReceivedError(view, errorCode, description, failingUrl); - } - - @RequiresApi(api = Build.VERSION_CODES.M) - @Override - public void onReceivedHttpError(@NonNull WebView view, - @NonNull WebResourceRequest request, - @NonNull WebResourceResponse errorResponse) { - super.onReceivedHttpError(view, request, errorResponse); - - final InAppWebView webView = (InAppWebView) view; - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedHttpError( - WebResourceRequestExt.fromWebResourceRequest(request), - WebResourceResponseExt.fromWebResourceResponse(errorResponse)); - } - } - - @Override - public void onReceivedHttpAuthRequest(final WebView view, final HttpAuthHandler handler, final String host, final String realm) { - final String url = view.getUrl(); - String protocol = "https"; - int port = 0; - - if (url != null) { - try { - URI uri = new URI(url); - protocol = uri.getScheme(); - port = uri.getPort(); - } catch (URISyntaxException e) { - Log.e(LOG_TAG, "", e); - } - } - - previousAuthRequestFailureCount++; - - if (credentialsProposed == null) - credentialsProposed = CredentialDatabase.getInstance(view.getContext()).getHttpAuthCredentials(host, protocol, realm, port); - - URLCredential credentialProposed = null; - if (credentialsProposed != null && !credentialsProposed.isEmpty()) { - credentialProposed = credentialsProposed.get(0); - } - - URLProtectionSpace protectionSpace = new URLProtectionSpace(host, protocol, realm, port, view.getCertificate(), null); - HttpAuthenticationChallenge challenge = new HttpAuthenticationChallenge(protectionSpace, previousAuthRequestFailureCount, credentialProposed); - - final InAppWebView webView = (InAppWebView) view; - final String finalProtocol = protocol; - final int finalPort = port; - final WebViewChannelDelegate.ReceivedHttpAuthRequestCallback callback = new WebViewChannelDelegate.ReceivedHttpAuthRequestCallback() { - @Override - public boolean nonNullSuccess(@NonNull HttpAuthResponse response) { - Integer action = response.getAction(); - if (action != null) { - switch (action) { - case 1: - String username = response.getUsername(); - String password = response.getPassword(); - boolean permanentPersistence = response.isPermanentPersistence(); - if (permanentPersistence) { - CredentialDatabase.getInstance(view.getContext()) - .setHttpAuthCredential(host, finalProtocol, realm, finalPort, username, password); - } - handler.proceed(username, password); - break; - case 2: - if (!credentialsProposed.isEmpty()) { - URLCredential credential = credentialsProposed.remove(0); - handler.proceed(credential.getUsername(), credential.getPassword()); - } else { - handler.cancel(); - } - // used custom CredentialDatabase! - // handler.useHttpAuthUsernamePassword(); - break; - case 0: - default: - credentialsProposed = null; - previousAuthRequestFailureCount = 0; - handler.cancel(); - } - - return false; - } - - return true; - } - - @Override - public void defaultBehaviour(@Nullable HttpAuthResponse result) { - InAppWebViewClientCompat.super.onReceivedHttpAuthRequest(view, handler, host, realm); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedHttpAuthRequest(challenge, callback); - } else { - callback.defaultBehaviour(null); - } - } - - @Override - public void onReceivedSslError(final WebView view, final SslErrorHandler handler, final SslError sslError) { - final String url = sslError.getUrl(); - String host = ""; - String protocol = "https"; - int port = 0; - - try { - URI uri = new URI(url); - host = uri.getHost(); - protocol = uri.getScheme(); - port = uri.getPort(); - } catch (URISyntaxException e) { - Log.e(LOG_TAG, "", e); - } - - URLProtectionSpace protectionSpace = new URLProtectionSpace(host, protocol, null, port, sslError.getCertificate(), sslError); - ServerTrustChallenge challenge = new ServerTrustChallenge(protectionSpace); - - final InAppWebView webView = (InAppWebView) view; - final WebViewChannelDelegate.ReceivedServerTrustAuthRequestCallback callback = new WebViewChannelDelegate.ReceivedServerTrustAuthRequestCallback() { - @Override - public boolean nonNullSuccess(@NonNull ServerTrustAuthResponse response) { - Integer action = response.getAction(); - if (action != null) { - switch (action) { - case 1: - handler.proceed(); - break; - case 0: - default: - handler.cancel(); - } - - return false; - } - - return true; - } - - @Override - public void defaultBehaviour(@Nullable ServerTrustAuthResponse result) { - InAppWebViewClientCompat.super.onReceivedSslError(view, handler, sslError); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedServerTrustAuthRequest(challenge, callback); - } else { - callback.defaultBehaviour(null); - } - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - @Override - public void onReceivedClientCertRequest(final WebView view, final ClientCertRequest request) { - final String url = view.getUrl(); - final String host = request.getHost(); - String protocol = "https"; - final int port = request.getPort(); - - if (url != null) { - try { - URI uri = new URI(url); - protocol = uri.getScheme(); - } catch (URISyntaxException e) { - Log.e(LOG_TAG, "", e); - } - } - - URLProtectionSpace protectionSpace = new URLProtectionSpace(host, protocol, null, port, view.getCertificate(), null); - ClientCertChallenge challenge = new ClientCertChallenge(protectionSpace, request.getPrincipals(), request.getKeyTypes()); - - final InAppWebView webView = (InAppWebView) view; - final WebViewChannelDelegate.ReceivedClientCertRequestCallback callback = new WebViewChannelDelegate.ReceivedClientCertRequestCallback() { - @Override - public boolean nonNullSuccess(@NonNull ClientCertResponse response) { - Integer action = response.getAction(); - if (action != null && webView.plugin != null) { - switch (action) { - case 1: - { - String certificatePath = (String) response.getCertificatePath(); - String certificatePassword = (String) response.getCertificatePassword(); - String keyStoreType = (String) response.getKeyStoreType(); - Util.PrivateKeyAndCertificates privateKeyAndCertificates = - Util.loadPrivateKeyAndCertificate(webView.plugin, certificatePath, certificatePassword, keyStoreType); - if (privateKeyAndCertificates != null) { - request.proceed(privateKeyAndCertificates.privateKey, privateKeyAndCertificates.certificates); - } else { - request.cancel(); - } - } - break; - case 2: - request.ignore(); - break; - case 0: - default: - request.cancel(); - } - - return false; - } - - return true; - } - - @Override - public void defaultBehaviour(@Nullable ClientCertResponse result) { - InAppWebViewClientCompat.super.onReceivedClientCertRequest(view, request); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedClientCertRequest(challenge, callback); - } else { - callback.defaultBehaviour(null); - } - } - - @Override - public void onScaleChanged(WebView view, float oldScale, float newScale) { - super.onScaleChanged(view, oldScale, newScale); - final InAppWebView webView = (InAppWebView) view; - webView.zoomScale = newScale / Util.getPixelDensity(webView.getContext()); - - if (webView.channelDelegate != null) { - webView.channelDelegate.onZoomScaleChanged(oldScale, newScale); - } - } - - @RequiresApi(api = Build.VERSION_CODES.O_MR1) - @Override - public void onSafeBrowsingHit(@NonNull final WebView view, - @NonNull final WebResourceRequest request, - final int threatType, - @NonNull final SafeBrowsingResponseCompat callback) { - final InAppWebView webView = (InAppWebView) view; - final WebViewChannelDelegate.SafeBrowsingHitCallback resultCallback = new WebViewChannelDelegate.SafeBrowsingHitCallback() { - @Override - public boolean nonNullSuccess(@NonNull com.pichillilorenzo.flutter_inappwebview_android.types.SafeBrowsingResponse response) { - Integer action = response.getAction(); - if (action != null) { - boolean report = response.isReport(); - switch (action) { - case 0: - if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY)) { - callback.backToSafety(report); - } else { - return true; - } - break; - case 1: - if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_RESPONSE_PROCEED)) { - callback.proceed(report); - } else { - return true; - } - break; - case 2: - default: - if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL)) { - callback.showInterstitial(report); - } else { - return true; - } - } - - return false; - } - - return true; - } - - @Override - public void defaultBehaviour(@Nullable com.pichillilorenzo.flutter_inappwebview_android.types.SafeBrowsingResponse result) { - InAppWebViewClientCompat.super.onSafeBrowsingHit(view, request, threatType, callback); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (webView.channelDelegate != null) { - webView.channelDelegate.onSafeBrowsingHit(request.getUrl().toString(), threatType, resultCallback); - } else { - resultCallback.defaultBehaviour(null); - } - } - - public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequestExt request) { - final InAppWebView webView = (InAppWebView) view; - - if (webView.webViewAssetLoaderExt != null && webView.webViewAssetLoaderExt.loader != null) { - try { - final Uri uri = Uri.parse(request.getUrl()); - WebResourceResponse webResourceResponse = webView.webViewAssetLoaderExt.loader.shouldInterceptRequest(uri); - if (webResourceResponse != null) { - return webResourceResponse; - } - } catch (Exception e) { - Log.e(LOG_TAG, "", e); - } - } - - if (webView.customSettings.useShouldInterceptRequest) { - WebResourceResponseExt response = null; - if (webView.channelDelegate != null) { - try { - response = webView.channelDelegate.shouldInterceptRequest(request); - } catch (InterruptedException e) { - Log.e(LOG_TAG, "", e); - return null; - } - } - - if (response != null) { - String contentType = response.getContentType(); - String contentEncoding = response.getContentEncoding(); - byte[] data = response.getData(); - Map responseHeaders = response.getHeaders(); - Integer statusCode = response.getStatusCode(); - String reasonPhrase = response.getReasonPhrase(); - - ByteArrayInputStream inputStream = (data != null) ? new ByteArrayInputStream(data) : null; - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && statusCode != null && reasonPhrase != null) { - return new WebResourceResponse(contentType, contentEncoding, statusCode, reasonPhrase, responseHeaders, inputStream); - } else { - return new WebResourceResponse(contentType, contentEncoding, inputStream); - } - } - - return null; - } - - final String url = request.getUrl(); - String scheme = url.split(":")[0].toLowerCase(); - try { - scheme = Uri.parse(request.getUrl()).getScheme(); - } catch (Exception ignored) {} - - if (webView.customSettings.resourceCustomSchemes != null && webView.customSettings.resourceCustomSchemes.contains(scheme)) { - CustomSchemeResponse customSchemeResponse = null; - if (webView.channelDelegate != null) { - try { - customSchemeResponse = webView.channelDelegate.onLoadResourceWithCustomScheme(request); - } catch (InterruptedException e) { - Log.e(LOG_TAG, "", e); - return null; - } - } - - if (customSchemeResponse != null) { - WebResourceResponse response = null; - try { - response = webView.contentBlockerHandler.checkUrl(webView, request, customSchemeResponse.getContentType()); - } catch (Exception e) { - Log.e(LOG_TAG, "", e); - } - if (response != null) - return response; - return new WebResourceResponse(customSchemeResponse.getContentType(), - customSchemeResponse.getContentType(), - new ByteArrayInputStream(customSchemeResponse.getData())); - } - } - - WebResourceResponse response = null; - if (!webView.contentBlockerHandler.getRuleList().isEmpty()) { - try { - response = webView.contentBlockerHandler.checkUrl(webView, request); - } catch (Exception e) { - Log.e(LOG_TAG, "", e); - } - } - return response; - } - - @Override - public WebResourceResponse shouldInterceptRequest(WebView view, final String url) { - WebResourceRequestExt requestExt = new WebResourceRequestExt( - url, null, false, - false, true, "GET" - ); - return shouldInterceptRequest(view, requestExt); - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - @Override - public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { - WebResourceRequestExt requestExt = WebResourceRequestExt.fromWebResourceRequest(request); - return shouldInterceptRequest(view, requestExt); - } - - @Override - public void onFormResubmission(final WebView view, final Message dontResend, final Message resend) { - final InAppWebView webView = (InAppWebView) view; - final WebViewChannelDelegate.FormResubmissionCallback callback = new WebViewChannelDelegate.FormResubmissionCallback() { - @Override - public boolean nonNullSuccess(@NonNull Integer action) { - switch (action) { - case 0: - resend.sendToTarget(); - break; - case 1: - default: - dontResend.sendToTarget(); - } - return false; - } - - @Override - public void defaultBehaviour(@Nullable Integer result) { - InAppWebViewClientCompat.super.onFormResubmission(view, dontResend, resend); - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (webView.channelDelegate != null) { - webView.channelDelegate.onFormResubmission(webView.getUrl(), callback); - } else { - callback.defaultBehaviour(null); - } - } - - @Override - public void onPageCommitVisible(@NonNull WebView view, @NonNull String url) { - super.onPageCommitVisible(view, url); - - final InAppWebView webView = (InAppWebView) view; - if (webView.channelDelegate != null) { - webView.channelDelegate.onPageCommitVisible(url); - } - } - - @RequiresApi(api = Build.VERSION_CODES.O) - @Override - public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) { - final InAppWebView webView = (InAppWebView) view; - - if (webView.customSettings.useOnRenderProcessGone && webView.channelDelegate != null) { - boolean didCrash = detail.didCrash(); - int rendererPriorityAtExit = detail.rendererPriorityAtExit(); - webView.channelDelegate.onRenderProcessGone(didCrash, rendererPriorityAtExit); - return true; - } - - return super.onRenderProcessGone(view, detail); - } - - @Override - public void onReceivedLoginRequest(WebView view, String realm, String account, String args) { - final InAppWebView webView = (InAppWebView) view; - if (webView.channelDelegate != null) { - webView.channelDelegate.onReceivedLoginRequest(realm, account, args); - } - } - - @Override - public void onUnhandledKeyEvent(WebView view, KeyEvent event) {} - - public void dispose() { - if (inAppBrowserDelegate != null) { - inAppBrowserDelegate = null; - } - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewRenderProcessClient.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewRenderProcessClient.java deleted file mode 100644 index 1fe8c509fd..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewRenderProcessClient.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview; - -import android.util.Log; -import android.webkit.WebView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.WebViewFeature; -import androidx.webkit.WebViewRenderProcess; -import androidx.webkit.WebViewRenderProcessClient; - -import com.pichillilorenzo.flutter_inappwebview_android.webview.WebViewChannelDelegate; - -public class InAppWebViewRenderProcessClient extends WebViewRenderProcessClient { - - protected static final String LOG_TAG = "IAWRenderProcessClient"; - - public InAppWebViewRenderProcessClient() { - super(); - } - - @Override - public void onRenderProcessUnresponsive(@NonNull WebView view, @Nullable final WebViewRenderProcess renderer) { - final InAppWebView webView = (InAppWebView) view; - final WebViewChannelDelegate.RenderProcessUnresponsiveCallback callback = new WebViewChannelDelegate.RenderProcessUnresponsiveCallback() { - @Override - public boolean nonNullSuccess(@NonNull Integer action) { - if (renderer != null) { - switch (action) { - case 0: - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_VIEW_RENDERER_TERMINATE)) - renderer.terminate(); - break; - } - return false; - } - return true; - } - - @Override - public void defaultBehaviour(@Nullable Integer result) { - - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (webView.channelDelegate != null) { - webView.channelDelegate.onRenderProcessUnresponsive(webView.getUrl(), callback); - } else { - callback.defaultBehaviour(null); - } - } - - @Override - public void onRenderProcessResponsive(@NonNull WebView view, @Nullable final WebViewRenderProcess renderer) { - final InAppWebView webView = (InAppWebView) view; - final WebViewChannelDelegate.RenderProcessResponsiveCallback callback = new WebViewChannelDelegate.RenderProcessResponsiveCallback() { - @Override - public boolean nonNullSuccess(@NonNull Integer action) { - if (renderer != null) { - switch (action) { - case 0: - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_VIEW_RENDERER_TERMINATE)) - renderer.terminate(); - break; - } - return false; - } - return true; - } - - @Override - public void defaultBehaviour(@Nullable Integer result) { - - } - - @Override - public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { - Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); - defaultBehaviour(null); - } - }; - - if (webView.channelDelegate != null) { - webView.channelDelegate.onRenderProcessResponsive(webView.getUrl(), callback); - } else { - callback.defaultBehaviour(null); - } - } - - void dispose() { - - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewSettings.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewSettings.java deleted file mode 100755 index 9a157f981f..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewSettings.java +++ /dev/null @@ -1,741 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview; - -import static android.webkit.WebSettings.LayoutAlgorithm.NARROW_COLUMNS; -import static android.webkit.WebSettings.LayoutAlgorithm.NORMAL; - -import android.annotation.SuppressLint; -import android.os.Build; -import android.view.View; -import android.webkit.WebSettings; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.WebSettingsCompat; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.ISettings; -import com.pichillilorenzo.flutter_inappwebview_android.types.PreferredContentModeOptionType; -import com.pichillilorenzo.flutter_inappwebview_android.webview.InAppWebViewInterface; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Pattern; - -public class InAppWebViewSettings implements ISettings { - - public static final String LOG_TAG = "InAppWebViewSettings"; - - public Boolean useShouldOverrideUrlLoading = false; - public Boolean useOnLoadResource = false; - public Boolean useOnDownloadStart = false; - /** - * @deprecated - */ - @Deprecated - public Boolean clearCache = false; - public String userAgent = ""; - public String applicationNameForUserAgent = ""; - public Boolean javaScriptEnabled = true; - public Boolean javaScriptCanOpenWindowsAutomatically = false; - public Boolean mediaPlaybackRequiresUserGesture = true; - public Integer minimumFontSize = 8; - public Boolean verticalScrollBarEnabled = true; - public Boolean horizontalScrollBarEnabled = true; - public List resourceCustomSchemes = new ArrayList<>(); - public List>> contentBlockers = new ArrayList<>(); - public Integer preferredContentMode = PreferredContentModeOptionType.RECOMMENDED.toValue(); - public Boolean useShouldInterceptAjaxRequest = false; - public Boolean useOnAjaxReadyStateChange = false; - public Boolean useOnAjaxProgress = false; - public Boolean interceptOnlyAsyncAjaxRequests = true; - public Boolean useShouldInterceptFetchRequest = false; - public Boolean incognito = false; - public Boolean cacheEnabled = true; - public Boolean transparentBackground = false; - public Boolean disableVerticalScroll = false; - public Boolean disableHorizontalScroll = false; - public Boolean disableContextMenu = false; - public Boolean supportZoom = true; - public Boolean allowFileAccessFromFileURLs = false; - public Boolean allowUniversalAccessFromFileURLs = false; - public Boolean allowBackgroundAudioPlaying = false; - @Nullable - public Integer textZoom; - /** - * @deprecated - */ - @Deprecated - public Boolean clearSessionCache = false; - public Boolean builtInZoomControls = true; - public Boolean displayZoomControls = false; - public Boolean databaseEnabled = false; - public Boolean domStorageEnabled = true; - public Boolean useWideViewPort = true; - public Boolean safeBrowsingEnabled = true; - @Nullable - public Integer mixedContentMode; - public Boolean allowContentAccess = true; - public Boolean allowFileAccess = true; - @Nullable - public String appCachePath; - public Boolean blockNetworkImage = false; - public Boolean blockNetworkLoads = false; - public Integer cacheMode = WebSettings.LOAD_DEFAULT; - public String cursiveFontFamily = "cursive"; - public Integer defaultFixedFontSize = 16; - public Integer defaultFontSize = 16; - public String defaultTextEncodingName = "UTF-8"; - public Integer disabledActionModeMenuItems; - public String fantasyFontFamily = "fantasy"; - public String fixedFontFamily = "monospace"; - @Nullable @Deprecated - public Integer forceDark; - @Nullable @Deprecated - public Integer forceDarkStrategy; - public Boolean geolocationEnabled = true; - public WebSettings.LayoutAlgorithm layoutAlgorithm; - public Boolean loadWithOverviewMode = true; - public Boolean loadsImagesAutomatically = true; - public Integer minimumLogicalFontSize = 8; - public Integer initialScale = 0; - public Boolean needInitialFocus = true; - public Boolean offscreenPreRaster = false; - public String sansSerifFontFamily = "sans-serif"; - public String serifFontFamily = "sans-serif"; - public String standardFontFamily = "sans-serif"; - public Boolean saveFormData = true; - public Boolean thirdPartyCookiesEnabled = true; - public Boolean hardwareAcceleration = true; - public Boolean supportMultipleWindows = false; - @Nullable - public Pattern regexToCancelSubFramesLoading; - @Nullable - public Pattern regexToAllowSyncUrlLoading; - public Integer overScrollMode = View.OVER_SCROLL_IF_CONTENT_SCROLLS; - @Nullable - public Boolean networkAvailable; - public Integer scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY; - public Integer verticalScrollbarPosition = View.SCROLLBAR_POSITION_DEFAULT; - @Nullable - public Integer scrollBarDefaultDelayBeforeFade; - public Boolean scrollbarFadingEnabled = true; - @Nullable - public Integer scrollBarFadeDuration; - @Nullable - public Map rendererPriorityPolicy; - public Boolean useShouldInterceptRequest = false; - public Boolean useOnRenderProcessGone = false; - public Boolean disableDefaultErrorPage = false; - public Boolean useHybridComposition = true; - @Nullable - public String verticalScrollbarThumbColor; - @Nullable - public String verticalScrollbarTrackColor; - @Nullable - public String horizontalScrollbarThumbColor; - @Nullable - public String horizontalScrollbarTrackColor; - public Boolean algorithmicDarkeningAllowed = false; - public Boolean enterpriseAuthenticationAppLinkPolicyEnabled = true; - @Nullable - public Map webViewAssetLoader; - @Nullable - public byte[] defaultVideoPoster; - @Nullable - public Set requestedWithHeaderOriginAllowList; - @Nullable - public Set javaScriptHandlersOriginAllowList; - public Boolean javaScriptHandlersForMainFrameOnly = false; - public Boolean javaScriptBridgeEnabled = true; - @Nullable - public Set javaScriptBridgeOriginAllowList; - @Nullable - public Boolean javaScriptBridgeForMainFrameOnly; - @Nullable - public Set pluginScriptsOriginAllowList; - public Boolean pluginScriptsForMainFrameOnly = false; - public Boolean isUserInteractionEnabled = true; - @Nullable - public Double alpha; - public Boolean useOnShowFileChooser = false; - - @NonNull - @Override - public InAppWebViewSettings parse(@NonNull Map settings) { - for (Map.Entry pair : settings.entrySet()) { - String key = pair.getKey(); - Object value = pair.getValue(); - if (value == null) { - continue; - } - - switch (key) { - case "useShouldOverrideUrlLoading": - useShouldOverrideUrlLoading = (Boolean) value; - break; - case "useOnLoadResource": - useOnLoadResource = (Boolean) value; - break; - case "useOnDownloadStart": - useOnDownloadStart = (Boolean) value; - break; - case "clearCache": - clearCache = (Boolean) value; - break; - case "userAgent": - userAgent = (String) value; - break; - case "applicationNameForUserAgent": - applicationNameForUserAgent = (String) value; - break; - case "javaScriptEnabled": - javaScriptEnabled = (Boolean) value; - break; - case "javaScriptCanOpenWindowsAutomatically": - javaScriptCanOpenWindowsAutomatically = (Boolean) value; - break; - case "mediaPlaybackRequiresUserGesture": - mediaPlaybackRequiresUserGesture = (Boolean) value; - break; - case "minimumFontSize": - minimumFontSize = (Integer) value; - break; - case "verticalScrollBarEnabled": - verticalScrollBarEnabled = (Boolean) value; - break; - case "horizontalScrollBarEnabled": - horizontalScrollBarEnabled = (Boolean) value; - break; - case "resourceCustomSchemes": - resourceCustomSchemes = (List) value; - break; - case "contentBlockers": - contentBlockers = (List>>) value; - break; - case "preferredContentMode": - preferredContentMode = (Integer) value; - break; - case "useShouldInterceptAjaxRequest": - useShouldInterceptAjaxRequest = (Boolean) value; - break; - case "useOnAjaxReadyStateChange": - useOnAjaxReadyStateChange = (Boolean) value; - break; - case "useOnAjaxProgress": - useOnAjaxProgress = (Boolean) value; - break; - case "interceptOnlyAsyncAjaxRequests": - interceptOnlyAsyncAjaxRequests = (Boolean) value; - break; - case "useShouldInterceptFetchRequest": - useShouldInterceptFetchRequest = (Boolean) value; - break; - case "incognito": - incognito = (Boolean) value; - break; - case "cacheEnabled": - cacheEnabled = (Boolean) value; - break; - case "transparentBackground": - transparentBackground = (Boolean) value; - break; - case "disableVerticalScroll": - disableVerticalScroll = (Boolean) value; - break; - case "disableHorizontalScroll": - disableHorizontalScroll = (Boolean) value; - break; - case "disableContextMenu": - disableContextMenu = (Boolean) value; - break; - case "textZoom": - textZoom = (Integer) value; - break; - case "clearSessionCache": - clearSessionCache = (Boolean) value; - break; - case "builtInZoomControls": - builtInZoomControls = (Boolean) value; - break; - case "displayZoomControls": - displayZoomControls = (Boolean) value; - break; - case "supportZoom": - supportZoom = (Boolean) value; - break; - case "databaseEnabled": - databaseEnabled = (Boolean) value; - break; - case "domStorageEnabled": - domStorageEnabled = (Boolean) value; - break; - case "useWideViewPort": - useWideViewPort = (Boolean) value; - break; - case "safeBrowsingEnabled": - safeBrowsingEnabled = (Boolean) value; - break; - case "mixedContentMode": - mixedContentMode = (Integer) value; - break; - case "allowContentAccess": - allowContentAccess = (Boolean) value; - break; - case "allowFileAccess": - allowFileAccess = (Boolean) value; - break; - case "allowFileAccessFromFileURLs": - allowFileAccessFromFileURLs = (Boolean) value; - break; - case "allowUniversalAccessFromFileURLs": - allowUniversalAccessFromFileURLs = (Boolean) value; - break; - case "appCachePath": - appCachePath = (String) value; - break; - case "blockNetworkImage": - blockNetworkImage = (Boolean) value; - break; - case "blockNetworkLoads": - blockNetworkLoads = (Boolean) value; - break; - case "cacheMode": - cacheMode = (Integer) value; - break; - case "cursiveFontFamily": - cursiveFontFamily = (String) value; - break; - case "defaultFixedFontSize": - defaultFixedFontSize = (Integer) value; - break; - case "defaultFontSize": - defaultFontSize = (Integer) value; - break; - case "defaultTextEncodingName": - defaultTextEncodingName = (String) value; - break; - case "disabledActionModeMenuItems": - disabledActionModeMenuItems = (Integer) value; - break; - case "fantasyFontFamily": - fantasyFontFamily = (String) value; - break; - case "fixedFontFamily": - fixedFontFamily = (String) value; - break; - case "forceDark": - forceDark = (Integer) value; - break; - case "forceDarkStrategy": - forceDarkStrategy = (Integer) value; - break; - case "geolocationEnabled": - geolocationEnabled = (Boolean) value; - break; - case "layoutAlgorithm": - setLayoutAlgorithm((String) value); - break; - case "loadWithOverviewMode": - loadWithOverviewMode = (Boolean) value; - break; - case "loadsImagesAutomatically": - loadsImagesAutomatically = (Boolean) value; - break; - case "minimumLogicalFontSize": - minimumLogicalFontSize = (Integer) value; - break; - case "initialScale": - initialScale = (Integer) value; - break; - case "needInitialFocus": - needInitialFocus = (Boolean) value; - break; - case "offscreenPreRaster": - offscreenPreRaster = (Boolean) value; - break; - case "sansSerifFontFamily": - sansSerifFontFamily = (String) value; - break; - case "serifFontFamily": - serifFontFamily = (String) value; - break; - case "standardFontFamily": - standardFontFamily = (String) value; - break; - case "saveFormData": - saveFormData = (Boolean) value; - break; - case "thirdPartyCookiesEnabled": - thirdPartyCookiesEnabled = (Boolean) value; - break; - case "hardwareAcceleration": - hardwareAcceleration = (Boolean) value; - break; - case "supportMultipleWindows": - supportMultipleWindows = (Boolean) value; - break; - case "regexToCancelSubFramesLoading": - regexToCancelSubFramesLoading = Pattern.compile((String) value); - break; - case "regexToAllowSyncUrlLoading": - regexToAllowSyncUrlLoading = Pattern.compile((String) value); - break; - case "overScrollMode": - overScrollMode = (Integer) value; - break; - case "networkAvailable": - networkAvailable = (Boolean) value; - break; - case "scrollBarStyle": - scrollBarStyle = (Integer) value; - break; - case "verticalScrollbarPosition": - verticalScrollbarPosition = (Integer) value; - break; - case "scrollBarDefaultDelayBeforeFade": - scrollBarDefaultDelayBeforeFade = (Integer) value; - break; - case "scrollbarFadingEnabled": - scrollbarFadingEnabled = (Boolean) value; - break; - case "scrollBarFadeDuration": - scrollBarFadeDuration = (Integer) value; - break; - case "rendererPriorityPolicy": - rendererPriorityPolicy = (Map) value; - break; - case "useShouldInterceptRequest": - useShouldInterceptRequest = (Boolean) value; - break; - case "useOnRenderProcessGone": - useOnRenderProcessGone = (Boolean) value; - break; - case "disableDefaultErrorPage": - disableDefaultErrorPage = (Boolean) value; - break; - case "useHybridComposition": - useHybridComposition = (Boolean) value; - break; - case "verticalScrollbarThumbColor": - verticalScrollbarThumbColor = (String) value; - break; - case "verticalScrollbarTrackColor": - verticalScrollbarTrackColor = (String) value; - break; - case "horizontalScrollbarThumbColor": - horizontalScrollbarThumbColor = (String) value; - break; - case "horizontalScrollbarTrackColor": - horizontalScrollbarTrackColor = (String) value; - break; - case "algorithmicDarkeningAllowed": - algorithmicDarkeningAllowed = (Boolean) value; - break; - case "enterpriseAuthenticationAppLinkPolicyEnabled": - enterpriseAuthenticationAppLinkPolicyEnabled = (Boolean) value; - break; - case "allowBackgroundAudioPlaying": - allowBackgroundAudioPlaying = (Boolean) value; - break; - case "webViewAssetLoader": - webViewAssetLoader = (Map) value; - break; - case "defaultVideoPoster": - defaultVideoPoster = (byte[]) value; - break; - case "requestedWithHeaderOriginAllowList": - requestedWithHeaderOriginAllowList = new HashSet<>((List) value); - break; - case "javaScriptHandlersOriginAllowList": - javaScriptHandlersOriginAllowList = new HashSet<>(); - for (String pattern : (List) value) { - javaScriptHandlersOriginAllowList.add(Pattern.compile(pattern)); - } - break; - case "javaScriptHandlersForMainFrameOnly": - javaScriptHandlersForMainFrameOnly = (Boolean) value; - break; - case "javaScriptBridgeEnabled": - javaScriptBridgeEnabled = (Boolean) value; - break; - case "javaScriptBridgeOriginAllowList": - javaScriptBridgeOriginAllowList = new HashSet<>((List) value); - break; - case "javaScriptBridgeForMainFrameOnly": - javaScriptBridgeForMainFrameOnly = (Boolean) value; - break; - case "pluginScriptsOriginAllowList": - pluginScriptsOriginAllowList = new HashSet<>((List) value); - break; - case "pluginScriptsForMainFrameOnly": - pluginScriptsForMainFrameOnly = (Boolean) value; - break; - case "isUserInteractionEnabled": - isUserInteractionEnabled = (Boolean) value; - break; - case "alpha": - alpha = (Double) value; - break; - case "useOnShowFileChooser": - useOnShowFileChooser = (Boolean) value; - break; - } - } - - return this; - } - - @NonNull - @Override - public Map toMap() { - Map settings = new HashMap<>(); - settings.put("useShouldOverrideUrlLoading", useShouldOverrideUrlLoading); - settings.put("useOnLoadResource", useOnLoadResource); - settings.put("useOnDownloadStart", useOnDownloadStart); - settings.put("clearCache", clearCache); - settings.put("userAgent", userAgent); - settings.put("applicationNameForUserAgent", applicationNameForUserAgent); - settings.put("javaScriptEnabled", javaScriptEnabled); - settings.put("javaScriptCanOpenWindowsAutomatically", javaScriptCanOpenWindowsAutomatically); - settings.put("mediaPlaybackRequiresUserGesture", mediaPlaybackRequiresUserGesture); - settings.put("minimumFontSize", minimumFontSize); - settings.put("verticalScrollBarEnabled", verticalScrollBarEnabled); - settings.put("horizontalScrollBarEnabled", horizontalScrollBarEnabled); - settings.put("resourceCustomSchemes", resourceCustomSchemes); - settings.put("contentBlockers", contentBlockers); - settings.put("preferredContentMode", preferredContentMode); - settings.put("useShouldInterceptAjaxRequest", useShouldInterceptAjaxRequest); - settings.put("useOnAjaxReadyStateChange", useOnAjaxReadyStateChange); - settings.put("useOnAjaxProgress", useOnAjaxProgress); - settings.put("interceptOnlyAsyncAjaxRequests", interceptOnlyAsyncAjaxRequests); - settings.put("useShouldInterceptFetchRequest", useShouldInterceptFetchRequest); - settings.put("incognito", incognito); - settings.put("cacheEnabled", cacheEnabled); - settings.put("transparentBackground", transparentBackground); - settings.put("disableVerticalScroll", disableVerticalScroll); - settings.put("disableHorizontalScroll", disableHorizontalScroll); - settings.put("disableContextMenu", disableContextMenu); - settings.put("textZoom", textZoom); - settings.put("clearSessionCache", clearSessionCache); - settings.put("builtInZoomControls", builtInZoomControls); - settings.put("displayZoomControls", displayZoomControls); - settings.put("supportZoom", supportZoom); - settings.put("databaseEnabled", databaseEnabled); - settings.put("domStorageEnabled", domStorageEnabled); - settings.put("useWideViewPort", useWideViewPort); - settings.put("safeBrowsingEnabled", safeBrowsingEnabled); - settings.put("mixedContentMode", mixedContentMode); - settings.put("allowContentAccess", allowContentAccess); - settings.put("allowFileAccess", allowFileAccess); - settings.put("allowFileAccessFromFileURLs", allowFileAccessFromFileURLs); - settings.put("allowUniversalAccessFromFileURLs", allowUniversalAccessFromFileURLs); - settings.put("appCachePath", appCachePath); - settings.put("blockNetworkImage", blockNetworkImage); - settings.put("blockNetworkLoads", blockNetworkLoads); - settings.put("cacheMode", cacheMode); - settings.put("cursiveFontFamily", cursiveFontFamily); - settings.put("defaultFixedFontSize", defaultFixedFontSize); - settings.put("defaultFontSize", defaultFontSize); - settings.put("defaultTextEncodingName", defaultTextEncodingName); - settings.put("disabledActionModeMenuItems", disabledActionModeMenuItems); - settings.put("fantasyFontFamily", fantasyFontFamily); - settings.put("fixedFontFamily", fixedFontFamily); - settings.put("forceDark", forceDark); - settings.put("forceDarkStrategy", forceDarkStrategy); - settings.put("geolocationEnabled", geolocationEnabled); - settings.put("layoutAlgorithm", getLayoutAlgorithm()); - settings.put("loadWithOverviewMode", loadWithOverviewMode); - settings.put("loadsImagesAutomatically", loadsImagesAutomatically); - settings.put("minimumLogicalFontSize", minimumLogicalFontSize); - settings.put("initialScale", initialScale); - settings.put("needInitialFocus", needInitialFocus); - settings.put("offscreenPreRaster", offscreenPreRaster); - settings.put("sansSerifFontFamily", sansSerifFontFamily); - settings.put("serifFontFamily", serifFontFamily); - settings.put("standardFontFamily", standardFontFamily); - settings.put("saveFormData", saveFormData); - settings.put("thirdPartyCookiesEnabled", thirdPartyCookiesEnabled); - settings.put("hardwareAcceleration", hardwareAcceleration); - settings.put("supportMultipleWindows", supportMultipleWindows); - settings.put("regexToCancelSubFramesLoading", regexToCancelSubFramesLoading != null ? regexToCancelSubFramesLoading.pattern() : null); - settings.put("regexToAllowSyncUrlLoading", regexToAllowSyncUrlLoading != null ? regexToAllowSyncUrlLoading.pattern() : null); - settings.put("overScrollMode", overScrollMode); - settings.put("networkAvailable", networkAvailable); - settings.put("scrollBarStyle", scrollBarStyle); - settings.put("verticalScrollbarPosition", verticalScrollbarPosition); - settings.put("scrollBarDefaultDelayBeforeFade", scrollBarDefaultDelayBeforeFade); - settings.put("scrollbarFadingEnabled", scrollbarFadingEnabled); - settings.put("scrollBarFadeDuration", scrollBarFadeDuration); - settings.put("rendererPriorityPolicy", rendererPriorityPolicy); - settings.put("useShouldInterceptRequest", useShouldInterceptRequest); - settings.put("useOnRenderProcessGone", useOnRenderProcessGone); - settings.put("disableDefaultErrorPage", disableDefaultErrorPage); - settings.put("useHybridComposition", useHybridComposition); - settings.put("verticalScrollbarThumbColor", verticalScrollbarThumbColor); - settings.put("verticalScrollbarTrackColor", verticalScrollbarTrackColor); - settings.put("horizontalScrollbarThumbColor", horizontalScrollbarThumbColor); - settings.put("horizontalScrollbarTrackColor", horizontalScrollbarTrackColor); - settings.put("algorithmicDarkeningAllowed", algorithmicDarkeningAllowed); - settings.put("enterpriseAuthenticationAppLinkPolicyEnabled", enterpriseAuthenticationAppLinkPolicyEnabled); - settings.put("allowBackgroundAudioPlaying", allowBackgroundAudioPlaying); - settings.put("defaultVideoPoster", defaultVideoPoster); - settings.put("requestedWithHeaderOriginAllowList", - requestedWithHeaderOriginAllowList != null ? new ArrayList<>(requestedWithHeaderOriginAllowList) : null); - settings.put("javaScriptHandlersOriginAllowList", - javaScriptHandlersOriginAllowList != null ? new ArrayList() {{ - for (Pattern pattern : javaScriptHandlersOriginAllowList) { - add(pattern.pattern()); - } - }} : null); - settings.put("javaScriptHandlersForMainFrameOnly", javaScriptHandlersForMainFrameOnly); - settings.put("javaScriptBridgeEnabled", javaScriptBridgeEnabled); - settings.put("javaScriptBridgeOriginAllowList", - javaScriptBridgeOriginAllowList != null ? new ArrayList<>(javaScriptBridgeOriginAllowList) : null); - settings.put("javaScriptBridgeForMainFrameOnly", javaScriptBridgeForMainFrameOnly); - settings.put("pluginScriptsOriginAllowList", - pluginScriptsOriginAllowList != null ? new ArrayList<>(pluginScriptsOriginAllowList) : null); - settings.put("pluginScriptsForMainFrameOnly", pluginScriptsForMainFrameOnly); - settings.put("isUserInteractionEnabled", isUserInteractionEnabled); - settings.put("alpha", alpha); - settings.put("useOnShowFileChooser", useOnShowFileChooser); - return settings; - } - - @SuppressLint("RestrictedApi") - @NonNull - @Override - public Map getRealSettings(@NonNull InAppWebViewInterface inAppWebView) { - Map realSettings = toMap(); - if (inAppWebView instanceof InAppWebView) { - InAppWebView webView = (InAppWebView) inAppWebView; - realSettings.put("alpha", webView.getAlpha()); - - WebSettings settings = webView.getSettings(); - realSettings.put("userAgent", settings.getUserAgentString()); - realSettings.put("javaScriptEnabled", settings.getJavaScriptEnabled()); - realSettings.put("javaScriptCanOpenWindowsAutomatically", settings.getJavaScriptCanOpenWindowsAutomatically()); - realSettings.put("mediaPlaybackRequiresUserGesture", settings.getMediaPlaybackRequiresUserGesture()); - realSettings.put("minimumFontSize", settings.getMinimumFontSize()); - realSettings.put("verticalScrollBarEnabled", webView.isVerticalScrollBarEnabled()); - realSettings.put("horizontalScrollBarEnabled", webView.isHorizontalScrollBarEnabled()); - realSettings.put("textZoom", settings.getTextZoom()); - realSettings.put("builtInZoomControls", settings.getBuiltInZoomControls()); - realSettings.put("supportZoom", settings.supportZoom()); - realSettings.put("displayZoomControls", settings.getDisplayZoomControls()); - realSettings.put("databaseEnabled", settings.getDatabaseEnabled()); - realSettings.put("domStorageEnabled", settings.getDomStorageEnabled()); - realSettings.put("useWideViewPort", settings.getUseWideViewPort()); - if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_ENABLE)) { - realSettings.put("safeBrowsingEnabled", WebSettingsCompat.getSafeBrowsingEnabled(settings)); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - realSettings.put("safeBrowsingEnabled", settings.getSafeBrowsingEnabled()); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - realSettings.put("mixedContentMode", settings.getMixedContentMode()); - } - realSettings.put("allowContentAccess", settings.getAllowContentAccess()); - realSettings.put("allowFileAccess", settings.getAllowFileAccess()); - realSettings.put("allowFileAccessFromFileURLs", settings.getAllowFileAccessFromFileURLs()); - realSettings.put("allowUniversalAccessFromFileURLs", settings.getAllowUniversalAccessFromFileURLs()); - realSettings.put("blockNetworkImage", settings.getBlockNetworkImage()); - realSettings.put("blockNetworkLoads", settings.getBlockNetworkLoads()); - realSettings.put("cacheMode", settings.getCacheMode()); - realSettings.put("cursiveFontFamily", settings.getCursiveFontFamily()); - realSettings.put("defaultFixedFontSize", settings.getDefaultFixedFontSize()); - realSettings.put("defaultFontSize", settings.getDefaultFontSize()); - realSettings.put("defaultTextEncodingName", settings.getDefaultTextEncodingName()); - if (WebViewFeature.isFeatureSupported(WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS)) { - realSettings.put("disabledActionModeMenuItems", WebSettingsCompat.getDisabledActionModeMenuItems(settings)); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - realSettings.put("disabledActionModeMenuItems", settings.getDisabledActionModeMenuItems()); - } - realSettings.put("fantasyFontFamily", settings.getFantasyFontFamily()); - realSettings.put("fixedFontFamily", settings.getFixedFontFamily()); - if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { - realSettings.put("forceDark", WebSettingsCompat.getForceDark(settings)); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - realSettings.put("forceDark", settings.getForceDark()); - } - if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) { - realSettings.put("forceDarkStrategy", WebSettingsCompat.getForceDarkStrategy(settings)); - } - realSettings.put("layoutAlgorithm", settings.getLayoutAlgorithm().name()); - realSettings.put("loadWithOverviewMode", settings.getLoadWithOverviewMode()); - realSettings.put("loadsImagesAutomatically", settings.getLoadsImagesAutomatically()); - realSettings.put("minimumLogicalFontSize", settings.getMinimumLogicalFontSize()); - if (WebViewFeature.isFeatureSupported(WebViewFeature.OFF_SCREEN_PRERASTER)) { - realSettings.put("offscreenPreRaster", WebSettingsCompat.getOffscreenPreRaster(settings)); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - realSettings.put("offscreenPreRaster", settings.getOffscreenPreRaster()); - } - realSettings.put("sansSerifFontFamily", settings.getSansSerifFontFamily()); - realSettings.put("serifFontFamily", settings.getSerifFontFamily()); - realSettings.put("standardFontFamily", settings.getStandardFontFamily()); - realSettings.put("saveFormData", settings.getSaveFormData()); - realSettings.put("supportMultipleWindows", settings.supportMultipleWindows()); - realSettings.put("overScrollMode", webView.getOverScrollMode()); - realSettings.put("scrollBarStyle", webView.getScrollBarStyle()); - realSettings.put("verticalScrollbarPosition", webView.getVerticalScrollbarPosition()); - realSettings.put("scrollBarDefaultDelayBeforeFade", webView.getScrollBarDefaultDelayBeforeFade()); - realSettings.put("scrollbarFadingEnabled", webView.isScrollbarFadingEnabled()); - realSettings.put("scrollBarFadeDuration", webView.getScrollBarFadeDuration()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - Map rendererPriorityPolicy = new HashMap<>(); - rendererPriorityPolicy.put("rendererRequestedPriority", webView.getRendererRequestedPriority()); - rendererPriorityPolicy.put("waivedWhenNotVisible", webView.getRendererPriorityWaivedWhenNotVisible()); - realSettings.put("rendererPriorityPolicy", rendererPriorityPolicy); - } - if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - realSettings.put("algorithmicDarkeningAllowed", WebSettingsCompat.isAlgorithmicDarkeningAllowed(settings)); - } - if (WebViewFeature.isFeatureSupported(WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY)) { - realSettings.put("enterpriseAuthenticationAppLinkPolicyEnabled", WebSettingsCompat.getEnterpriseAuthenticationAppLinkPolicyEnabled(settings)); - } - if (WebViewFeature.isFeatureSupported(WebViewFeature.REQUESTED_WITH_HEADER_ALLOW_LIST)) { - realSettings.put("requestedWithHeaderOriginAllowList", new ArrayList<>(WebSettingsCompat.getRequestedWithHeaderOriginAllowList(settings))); - } - } - return realSettings; - } - - private void setLayoutAlgorithm(String value) { - if (value != null) { - switch (value) { - case "NARROW_COLUMNS": - layoutAlgorithm = NARROW_COLUMNS; - case "NORMAL": - layoutAlgorithm = NORMAL; - case "TEXT_AUTOSIZING": - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING; - } else { - layoutAlgorithm = NORMAL; - } - break; - } - } - } - - private String getLayoutAlgorithm() { - if (layoutAlgorithm != null) { - switch (layoutAlgorithm) { - case NORMAL: - return "NORMAL"; - case TEXT_AUTOSIZING: - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - return "TEXT_AUTOSIZING"; - } else { - return "NORMAL"; - } - case NARROW_COLUMNS: - return "NARROW_COLUMNS"; - } - } - return null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InputAwareWebView.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InputAwareWebView.java deleted file mode 100755 index e4c5e96d72..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InputAwareWebView.java +++ /dev/null @@ -1,273 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview; - -import static android.content.Context.INPUT_METHOD_SERVICE; - -import android.content.Context; -import android.graphics.Rect; -import android.os.Build; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; -import android.view.inputmethod.InputMethodManager; -import android.webkit.WebView; -import android.widget.ListPopupWindow; - -import androidx.annotation.Nullable; - -/** - * A WebView subclass that mirrors the same implementation hacks that the system WebView does in - * order to correctly create an InputConnection. - * - * These hacks are only needed in Android versions below N and exist to create an InputConnection - * on the WebView's dedicated input, or IME, thread. The majority of this proxying logic is in - * https://github.com/flutter/plugins/blob/main/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java - */ -public class InputAwareWebView extends WebView { - private static final String LOG_TAG = "InputAwareWebView"; - @Nullable - public View containerView; - private View threadedInputConnectionProxyView; - private ThreadedInputConnectionProxyAdapterView proxyAdapterView; - private boolean useHybridComposition = false; - - public InputAwareWebView(Context context, @Nullable View containerView, Boolean useHybridComposition) { - super(context); - this.containerView = containerView; - this.useHybridComposition = useHybridComposition == null ? false : useHybridComposition; - } - - public InputAwareWebView(Context context, AttributeSet attrs) { - super(context, attrs); - this.containerView = null; - } - - public InputAwareWebView(Context context) { - super(context); - this.containerView = null; - } - - public InputAwareWebView(Context context, AttributeSet attrs, int defaultStyle) { - super(context, attrs, defaultStyle); - this.containerView = null; - } - - public void setContainerView(View containerView) { - this.containerView = containerView; - - if (proxyAdapterView == null) { - return; - } - - Log.w(LOG_TAG, "The containerView has changed while the proxyAdapterView exists."); - if (containerView != null) { - setInputConnectionTarget(proxyAdapterView); - } - } - - /** - * Set our proxy adapter view to use its cached input connection instead of creating new ones. - * - *

This is used to avoid losing our input connection when the virtual display is resized. - */ - public void lockInputConnection() { - if (proxyAdapterView == null) { - return; - } - - proxyAdapterView.setLocked(true); - } - - /** Sets the proxy adapter view back to its default behavior. */ - public void unlockInputConnection() { - if (proxyAdapterView == null) { - return; - } - - proxyAdapterView.setLocked(false); - } - - /** Restore the original InputConnection, if needed. */ - void dispose() { - if (useHybridComposition) { - return; - } - resetInputConnection(); - } - - /** - * Creates an InputConnection from the IME thread when needed. - * - *

We only need to create a {@link ThreadedInputConnectionProxyAdapterView} and create an - * InputConnectionProxy on the IME thread when WebView is doing the same thing. So we rely on the - * system calling this method for WebView's proxy view in order to know when we need to create our - * own. - * - *

This method would normally be called for any View that used the InputMethodManager. We rely - * on flutter/engine filtering the calls we receive down to the ones in our hierarchy and the - * system WebView in order to know whether or not the system WebView expects an InputConnection on - * the IME thread. - */ - @Override - public boolean checkInputConnectionProxy(final View view) { - if (useHybridComposition) { - return super.checkInputConnectionProxy(view); - } - // Check to see if the view param is WebView's ThreadedInputConnectionProxyView. - View previousProxy = threadedInputConnectionProxyView; - threadedInputConnectionProxyView = view; - if (previousProxy == view) { - // This isn't a new ThreadedInputConnectionProxyView. Ignore it. - return super.checkInputConnectionProxy(view); - } - if (containerView == null) { - Log.e( - LOG_TAG, - "Can't create a proxy view because there's no container view. Text input may not work."); - return super.checkInputConnectionProxy(view); - } - - // We've never seen this before, so we make the assumption that this is WebView's - // ThreadedInputConnectionProxyView. We are making the assumption that the only view that could - // possibly be interacting with the IMM here is WebView's ThreadedInputConnectionProxyView. - proxyAdapterView = - new ThreadedInputConnectionProxyAdapterView( - /*containerView=*/ containerView, - /*targetView=*/ view, - /*imeHandler=*/ view.getHandler()); - setInputConnectionTarget(/*targetView=*/ proxyAdapterView); - return super.checkInputConnectionProxy(view); - } - - /** - * Ensure that input creation happens back on {@link #containerView}'s thread once this view no - * longer has focus. - * - *

The logic in {@link #checkInputConnectionProxy} forces input creation to happen on Webview's - * thread for all connections. We undo it here so users will be able to go back to typing in - * Flutter UIs as expected. - */ - @Override - public void clearFocus() { - super.clearFocus(); - - if (useHybridComposition) { - return; - } - resetInputConnection(); - } - - /** - * Ensure that input creation happens back on {@link #containerView}. - * - *

The logic in {@link #checkInputConnectionProxy} forces input creation to happen on Webview's - * thread for all connections. We undo it here so users will be able to go back to typing in - * Flutter UIs as expected. - */ - private void resetInputConnection() { - if (proxyAdapterView == null) { - // No need to reset the InputConnection to the default thread if we've never changed it. - return; - } - if (containerView == null) { - Log.e(LOG_TAG, "Can't reset the input connection to the container view because there is none."); - return; - } - setInputConnectionTarget(/*targetView=*/ containerView); - } - - /** - * This is the crucial trick that gets the InputConnection creation to happen on the correct - * thread pre Android N. - * https://cs.chromium.org/chromium/src/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnectionFactory.java?l=169&rcl=f0698ee3e4483fad5b0c34159276f71cfaf81f3a - * - *

{@code targetView} should have a {@link View#getHandler} method with the thread that future - * InputConnections should be created on. - */ - private void setInputConnectionTarget(final View targetView) { - if (containerView == null) { - Log.e( - LOG_TAG, - "Can't set the input connection target because there is no containerView to use as a handler."); - return; - } - - targetView.requestFocus(); - containerView.post( - new Runnable() { - @Override - public void run() { - if (containerView == null) { - Log.e( - LOG_TAG, - "Can't set the input connection target because there is no containerView to use as a handler."); - return; - } - - InputMethodManager imm = - (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE); - // This is a hack to make InputMethodManager believe that the target view now has focus. - // As a result, InputMethodManager will think that targetView is focused, and will call - // getHandler() of the view when creating input connection. - - // Step 1: Set targetView as InputMethodManager#mNextServedView. This does not affect - // the real window focus. - targetView.onWindowFocusChanged(true); - - // Step 2: Have InputMethodManager focus in on targetView. As a result, IMM will call - // onCreateInputConnection() on targetView on the same thread as - // targetView.getHandler(). It will also call subsequent InputConnection methods on this - // thread. This is the IME thread in cases where targetView is our proxyAdapterView. - - // TODO (ALexVincent525): Currently only prompt has been tested, still needs more test cases. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - imm.isActive(containerView); - } - } - }); - } - - @Override - protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { - if (useHybridComposition) { - super.onFocusChanged(focused, direction, previouslyFocusedRect); - return; - } - // This works around a crash when old (<67.0.3367.0) Chromium versions are used. - - // Prior to Chromium 67.0.3367 the following sequence happens when a select drop down is shown - // on tablets: - // - // - WebView is calling ListPopupWindow#show - // - buildDropDown is invoked, which sets mDropDownList to a DropDownListView. - // - showAsDropDown is invoked - resulting in mDropDownList being added to the window and is - // also synchronously performing the following sequence: - // - WebView's focus change listener is loosing focus (as mDropDownList got it) - // - WebView is hiding all popups (as it lost focus) - // - WebView's SelectPopupDropDown#hide is invoked. - // - DropDownPopupWindow#dismiss is invoked setting mDropDownList to null. - // - mDropDownList#setSelection is invoked and is throwing a NullPointerException (as we just set mDropDownList to null). - // - // To workaround this, we drop the problematic focus lost call. - // See more details on: https://github.com/flutter/flutter/issues/54164 - // - // We don't do this after Android P as it shipped with a new enough WebView version, and it's - // better to not do this on all future Android versions in case DropDownListView's code changes. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P - && isCalledFromListPopupWindowShow() - && !focused) { - return; - } - super.onFocusChanged(focused, direction, previouslyFocusedRect); - } - - private boolean isCalledFromListPopupWindowShow() { - StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); - for (StackTraceElement stackTraceElement : stackTraceElements) { - if (stackTraceElement.getClassName().equals(ListPopupWindow.class.getCanonicalName()) - && stackTraceElement.getMethodName().equals("show")) { - return true; - } - } - return false; - } -} \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/ThreadedInputConnectionProxyAdapterView.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/ThreadedInputConnectionProxyAdapterView.java deleted file mode 100755 index 91a4546513..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/ThreadedInputConnectionProxyAdapterView.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview; - -import android.os.Handler; -import android.os.IBinder; -import android.view.View; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; - -/** - * A fake View only exposed to InputMethodManager. - * - * https://github.com/flutter/plugins/blob/main/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/ThreadedInputConnectionProxyAdapterView.java - */ -final class ThreadedInputConnectionProxyAdapterView extends View { - final Handler imeHandler; - final IBinder windowToken; - final View containerView; - final View rootView; - final View targetView; - - private boolean triggerDelayed = true; - private boolean isLocked = false; - private InputConnection cachedConnection; - - ThreadedInputConnectionProxyAdapterView(View containerView, View targetView, Handler imeHandler) { - super(containerView.getContext()); - this.imeHandler = imeHandler; - this.containerView = containerView; - this.targetView = targetView; - windowToken = containerView.getWindowToken(); - rootView = containerView.getRootView(); - setFocusable(true); - setFocusableInTouchMode(true); - setVisibility(VISIBLE); - } - - /** Returns whether or not this is currently asynchronously acquiring an input connection. */ - boolean isTriggerDelayed() { - return triggerDelayed; - } - - /** Sets whether or not this should use its previously cached input connection. */ - void setLocked(boolean locked) { - isLocked = locked; - } - - /** - * This is expected to be called on the IME thread. See the setup required for this in {@link - * InputAwareWebView#checkInputConnectionProxy(View)}. - * - *

Delegates to ThreadedInputConnectionProxyView to get WebView's input connection. - */ - @Override - public InputConnection onCreateInputConnection(final EditorInfo outAttrs) { - triggerDelayed = false; - InputConnection inputConnection = - (isLocked) ? cachedConnection : targetView.onCreateInputConnection(outAttrs); - triggerDelayed = true; - cachedConnection = inputConnection; - return inputConnection; - } - - @Override - public boolean checkInputConnectionProxy(View view) { - return true; - } - - @Override - public boolean hasWindowFocus() { - // None of our views here correctly report they have window focus because of how we're embedding - // the platform view inside of a virtual display. - return true; - } - - @Override - public View getRootView() { - return rootView; - } - - @Override - public boolean onCheckIsTextEditor() { - return true; - } - - @Override - public boolean isFocused() { - return true; - } - - @Override - public IBinder getWindowToken() { - return windowToken; - } - - @Override - public Handler getHandler() { - return imeHandler; - } -} \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageChannel.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageChannel.java deleted file mode 100644 index 54230d09c0..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageChannel.java +++ /dev/null @@ -1,166 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview.web_message; - -import android.webkit.ValueCallback; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.WebMessageCompat; -import androidx.webkit.WebMessagePortCompat; -import androidx.webkit.WebViewCompat; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.JavaScriptBridgeJS; -import com.pichillilorenzo.flutter_inappwebview_android.types.Disposable; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebMessageCompatExt; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebMessagePortCompatExt; -import com.pichillilorenzo.flutter_inappwebview_android.webview.InAppWebViewInterface; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebMessagePort; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.InAppWebView; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.flutter.plugin.common.MethodChannel; - -public class WebMessageChannel implements Disposable { - protected static final String LOG_TAG = "WebMessageChannel"; - public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_web_message_channel_"; - - @NonNull - public String id; - @Nullable - public WebMessageChannelChannelDelegate channelDelegate; - public final List compatPorts; - public final List ports; - @Nullable - public InAppWebViewInterface webView; - - public WebMessageChannel(@NonNull String id, @NonNull InAppWebViewInterface webView) { - this.id = id; - final MethodChannel channel = new MethodChannel(webView.getPlugin().messenger, METHOD_CHANNEL_NAME_PREFIX + id); - this.channelDelegate = new WebMessageChannelChannelDelegate(this, channel); - if (webView instanceof InAppWebView) { - this.compatPorts = new ArrayList<>(Arrays.asList(WebViewCompat.createWebMessageChannel((InAppWebView) webView))); - this.ports = new ArrayList<>(); - } else { - this.ports = Arrays.asList(new WebMessagePort("port1", this), new WebMessagePort("port2", this)); - this.compatPorts = new ArrayList<>(); - } - this.webView = webView; - } - - public void initJsInstance(InAppWebViewInterface webView, final ValueCallback callback) { - if (webView != null) { - final WebMessageChannel webMessageChannel = this; - webView.evaluateJavascript("(function() {" + - JavaScriptBridgeJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME() + "['" + webMessageChannel.id + "'] = new MessageChannel();" + - "})();", null, new ValueCallback() { - @Override - public void onReceiveValue(String value) { - callback.onReceiveValue(webMessageChannel); - } - }); - } else { - callback.onReceiveValue(this); - } - } - - public void setWebMessageCallbackForInAppWebView(final int index, @NonNull MethodChannel.Result result) { - if (webView != null && compatPorts.size() > 0 && - WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK)) { - final WebMessagePortCompat webMessagePort = compatPorts.get(index); - final WebMessageChannel webMessageChannel = this; - try { - webMessagePort.setWebMessageCallback(new WebMessagePortCompat.WebMessageCallbackCompat() { - @Override - public void onMessage(@NonNull WebMessagePortCompat port, @Nullable WebMessageCompat message) { - super.onMessage(port, message); - webMessageChannel.onMessage(index, message != null ? WebMessageCompatExt.fromMapWebMessageCompat(message) : null); - } - }); - result.success(true); - } catch (Exception e) { - result.error(LOG_TAG, e.getMessage(), null); - } - } else { - result.success(true); - } - } - - public void postMessageForInAppWebView(final Integer index, @NonNull WebMessageCompatExt message, @NonNull MethodChannel.Result result) { - if (webView != null && compatPorts.size() > 0 && - WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_POST_MESSAGE)) { - WebMessagePortCompat port = compatPorts.get(index); - List webMessagePorts = new ArrayList<>(); - List portsExt = message.getPorts(); - if (portsExt != null) { - for (WebMessagePortCompatExt portExt : portsExt) { - WebMessageChannel webMessageChannel = webView.getWebMessageChannels().get(portExt.getWebMessageChannelId()); - if (webMessageChannel != null) { - webMessagePorts.add(webMessageChannel.compatPorts.get(portExt.getIndex())); - } - } - } - Object data = message.getData(); - try { - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER) && data != null && - message.getType() == WebMessageCompat.TYPE_ARRAY_BUFFER) { - port.postMessage(new WebMessageCompat((byte[]) data, webMessagePorts.toArray(new WebMessagePortCompat[0]))); - } else { - port.postMessage(new WebMessageCompat(data != null ? data.toString() : null, webMessagePorts.toArray(new WebMessagePortCompat[0]))); - } - result.success(true); - } catch (Exception e) { - result.error(LOG_TAG, e.getMessage(), null); - } - } else { - result.success(true); - } - } - - public void closeForInAppWebView(Integer index, @NonNull MethodChannel.Result result) { - if (webView != null && compatPorts.size() > 0 && - WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_CLOSE)) { - WebMessagePortCompat port = compatPorts.get(index); - try { - port.close(); - result.success(true); - } catch (Exception e) { - result.error(LOG_TAG, e.getMessage(), null); - } - } else { - result.success(true); - } - } - - public void onMessage(int index, @Nullable WebMessageCompatExt message) { - if (channelDelegate != null) { - channelDelegate.onMessage(index, message); - } - } - - public Map toMap() { - Map webMessageChannelMap = new HashMap<>(); - webMessageChannelMap.put("id", id); - return webMessageChannelMap; - } - - public void dispose() { - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_CLOSE)) { - for (WebMessagePortCompat port : compatPorts) { - try { - port.close(); - } catch (Exception ignored) {} - } - } - if (channelDelegate != null) { - channelDelegate.dispose(); - channelDelegate = null; - } - compatPorts.clear(); - webView = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageChannelChannelDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageChannelChannelDelegate.java deleted file mode 100644 index f801a82d3e..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageChannelChannelDelegate.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview.web_message; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebMessageCompatExt; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.InAppWebView; - -import java.util.HashMap; -import java.util.Map; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class WebMessageChannelChannelDelegate extends ChannelDelegateImpl { - @Nullable - private WebMessageChannel webMessageChannel; - - public WebMessageChannelChannelDelegate(@NonNull WebMessageChannel webMessageChannel, @NonNull MethodChannel channel) { - super(channel); - this.webMessageChannel = webMessageChannel; - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - switch (call.method) { - case "setWebMessageCallback": - if (webMessageChannel != null && webMessageChannel.webView instanceof InAppWebView) { - final Integer index = (Integer) call.argument("index"); - webMessageChannel.setWebMessageCallbackForInAppWebView(index, result); - } else { - result.success(false); - } - break; - case "postMessage": - if (webMessageChannel != null && webMessageChannel.webView instanceof InAppWebView) { - final Integer index = (Integer) call.argument("index"); - WebMessageCompatExt message = WebMessageCompatExt.fromMap((Map) call.argument("message")); - webMessageChannel.postMessageForInAppWebView(index, message, result); - } else { - result.success(false); - } - break; - case "close": - if (webMessageChannel != null && webMessageChannel.webView instanceof InAppWebView) { - Integer index = (Integer) call.argument("index"); - webMessageChannel.closeForInAppWebView(index, result); - } else { - result.success(false); - } - break; - default: - result.notImplemented(); - } - } - - public void onMessage(int index, @Nullable WebMessageCompatExt message) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("index", index); - obj.put("message", message != null ? message.toMap() : null); - channel.invokeMethod("onMessage", obj); - } - - @Override - public void dispose() { - super.dispose(); - webMessageChannel = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageListener.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageListener.java deleted file mode 100644 index 164e3d3dbd..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageListener.java +++ /dev/null @@ -1,242 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview.web_message; - -import android.net.Uri; -import android.text.TextUtils; -import android.webkit.WebView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.webkit.JavaScriptReplyProxy; -import androidx.webkit.WebMessageCompat; -import androidx.webkit.WebViewCompat; -import androidx.webkit.WebViewFeature; - -import com.pichillilorenzo.flutter_inappwebview_android.Util; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.JavaScriptBridgeJS; -import com.pichillilorenzo.flutter_inappwebview_android.types.Disposable; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebMessageCompatExt; -import com.pichillilorenzo.flutter_inappwebview_android.webview.InAppWebViewInterface; -import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; -import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.InAppWebView; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.MethodChannel; - -public class WebMessageListener implements Disposable { - protected static final String LOG_TAG = "WebMessageListener"; - public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_web_message_listener_"; - - @NonNull - public String id; - public String jsObjectName; - public Set allowedOriginRules; - public WebViewCompat.WebMessageListener listener; - public JavaScriptReplyProxy replyProxy; - @Nullable - public InAppWebViewInterface webView; - @Nullable - public WebMessageListenerChannelDelegate channelDelegate; - - public WebMessageListener(@NonNull String id, - @NonNull InAppWebViewInterface webView, @NonNull BinaryMessenger messenger, - @NonNull String jsObjectName, @NonNull Set allowedOriginRules) { - this.id = id; - this.webView = webView; - this.jsObjectName = jsObjectName; - this.allowedOriginRules = allowedOriginRules; - final MethodChannel channel = new MethodChannel(messenger, METHOD_CHANNEL_NAME_PREFIX + this.id + "_" + this.jsObjectName); - this.channelDelegate = new WebMessageListenerChannelDelegate(this, channel); - - if (this.webView instanceof InAppWebView) { - this.listener = new WebViewCompat.WebMessageListener() { - @Override - public void onPostMessage(@NonNull WebView view, @NonNull WebMessageCompat message, @NonNull Uri sourceOrigin, - boolean isMainFrame, @NonNull JavaScriptReplyProxy javaScriptReplyProxy) { - replyProxy = javaScriptReplyProxy; - if (channelDelegate != null) { - channelDelegate.onPostMessage(WebMessageCompatExt.fromMapWebMessageCompat(message), - sourceOrigin.toString().equals("null") ? null : sourceOrigin.toString(), - isMainFrame); - } - } - }; - } - } - - public void initJsInstance() { - if (webView != null) { - String jsObjectNameEscaped = Util.replaceAll(jsObjectName, "\'", "\\'"); - List allowedOriginRulesStringList = new ArrayList<>(); - for (String allowedOriginRule : allowedOriginRules) { - if ("*".equals(allowedOriginRule)) { - allowedOriginRulesStringList.add("'*'"); - } else { - Uri rule = Uri.parse(allowedOriginRule); - String host = rule.getHost() != null ? "'" + Util.replaceAll(rule.getHost(), "\'", "\\'") + "'" : "null"; - allowedOriginRulesStringList.add("{scheme: '" + rule.getScheme() + "', host: " + host + ", port: " + (rule.getPort() != -1 ? rule.getPort() : "null") + "}"); - } - } - String allowedOriginRulesString = TextUtils.join(", ", allowedOriginRulesStringList); - - String source = "(function() {" + - " var allowedOriginRules = [" + allowedOriginRulesString + "];" + - " var isPageBlank = window.location.href === 'about:blank';" + - " var scheme = !isPageBlank ? window.location.protocol.replace(':', '') : null;" + - " var host = !isPageBlank ? window.location.hostname : null;" + - " var port = !isPageBlank ? window.location.port : null;" + - " if (window." + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "._isOriginAllowed(allowedOriginRules, scheme, host, port)) {" + - " window['" + jsObjectNameEscaped + "'] = new FlutterInAppWebViewWebMessageListener('" + jsObjectNameEscaped + "');" + - " }" + - "})();"; - webView.getUserContentController().addPluginScript(new PluginScript( - "WebMessageListener-" + jsObjectName, - source, - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - false, - webView.getCustomSettings().pluginScriptsOriginAllowList, - webView.getCustomSettings().pluginScriptsForMainFrameOnly - )); - } - } - - @Nullable - public static WebMessageListener fromMap(@NonNull InAppWebViewInterface webView, @NonNull BinaryMessenger messenger, @Nullable Map map) { - if (map == null) { - return null; - } - String id = (String) map.get("id"); - String jsObjectName = (String) map.get("jsObjectName"); - assert jsObjectName != null; - List allowedOriginRuleList = (List) map.get("allowedOriginRules"); - assert allowedOriginRuleList != null; - Set allowedOriginRules = new HashSet<>(allowedOriginRuleList); - return new WebMessageListener(id, webView, messenger, jsObjectName, allowedOriginRules); - } - - public void assertOriginRulesValid() throws Exception { - int index = 0; - for (String originRule : allowedOriginRules) { - if (originRule == null) { - throw new Exception("allowedOriginRules[" + index + "] is null"); - } - if (originRule.isEmpty()) { - throw new Exception("allowedOriginRules[" + index + "] is empty"); - } - if ("*".equals(originRule)) { - continue; - } - Uri url = Uri.parse(originRule); - String scheme = url.getScheme(); - String host = url.getHost(); - String path = url.getPath(); - int port = url.getPort(); - if (scheme == null) { - throw new Exception("allowedOriginRules " + originRule + " is invalid"); - } - if (("http".equals(scheme) || "https".equals(scheme)) && (host == null || host.isEmpty())) { - throw new Exception("allowedOriginRules " + originRule + " is invalid"); - } - if (!"http".equals(scheme) && !"https".equals(scheme) && (host != null || port != -1)) { - throw new Exception("allowedOriginRules " + originRule + " is invalid"); - } - if ((host == null || host.isEmpty()) && port != -1) { - throw new Exception("allowedOriginRules " + originRule + " is invalid"); - } - if (!path.isEmpty()) { - throw new Exception("allowedOriginRules " + originRule + " is invalid"); - } - if (host != null) { - int distance = host.indexOf("*"); - if (distance != 0 || (distance == 0 && !host.startsWith("*."))) { - throw new Exception("allowedOriginRules " + originRule + " is invalid"); - } - if (host.startsWith("[")) { - if (!host.endsWith("]")) { - throw new Exception("allowedOriginRules " + originRule + " is invalid"); - } - String ipv6 = host.substring(1, host.length() - 1); - if (!Util.isIPv6(ipv6)) { - throw new Exception("allowedOriginRules " + originRule + " is invalid"); - } - } - } - index++; - } - } - - public void postMessageForInAppWebView(WebMessageCompatExt message, @NonNull MethodChannel.Result result) { - if (replyProxy != null && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) { - Object data = message.getData(); - if (data != null) { - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER) && message.getType() == WebMessageCompat.TYPE_ARRAY_BUFFER) { - replyProxy.postMessage((byte[]) data); - } else { - replyProxy.postMessage(data.toString()); - } - } - } - result.success(true); - } - - public boolean isOriginAllowed(String scheme, String host, int port) { - for (String allowedOriginRule : allowedOriginRules) { - if ("*".equals(allowedOriginRule)) { - return true; - } - if (scheme == null || scheme.isEmpty()) { - continue; - } - if ((scheme == null || scheme.isEmpty()) && (host == null || host.isEmpty()) && (port == 0 || port == -1)) { - continue; - } - Uri rule = Uri.parse(allowedOriginRule); - int rulePort = rule.getPort() == -1 || rule.getPort() == 0 ? ("https".equals(rule.getScheme()) ? 443 : 80) : rule.getPort(); - int currentPort = port == 0 || port == -1 ? ("https".equals(scheme) ? 443 : 80) : port; - String IPv6 = null; - if (rule.getHost() != null && rule.getHost().startsWith("[")) { - try { - IPv6 = Util.normalizeIPv6(rule.getHost().substring(1, rule.getHost().length() - 1)); - } catch (Exception ignored) { - } - } - String hostIPv6 = null; - try { - hostIPv6 = Util.normalizeIPv6(host); - } catch (Exception ignored) { - } - - boolean schemeAllowed = rule.getScheme().equals(scheme); - - boolean hostAllowed = rule.getHost() == null || - rule.getHost().isEmpty() || - rule.getHost().equals(host) || - (rule.getHost().startsWith("*") && host != null && host.contains(rule.getHost().split("\\*")[1])) || - (hostIPv6 != null && IPv6 != null && hostIPv6.equals(IPv6)); - - boolean portAllowed = rulePort == currentPort; - - if (schemeAllowed && hostAllowed && portAllowed) { - return true; - } - } - return false; - } - - public void dispose() { - if (channelDelegate != null) { - channelDelegate.dispose(); - channelDelegate = null; - } - listener = null; - replyProxy = null; - webView = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageListenerChannelDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageListenerChannelDelegate.java deleted file mode 100644 index 92c7aaae92..0000000000 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageListenerChannelDelegate.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android.webview.web_message; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; -import com.pichillilorenzo.flutter_inappwebview_android.types.WebMessageCompatExt; -import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.InAppWebView; - -import java.util.HashMap; -import java.util.Map; - -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; - -public class WebMessageListenerChannelDelegate extends ChannelDelegateImpl { - @Nullable - private WebMessageListener webMessageListener; - - public WebMessageListenerChannelDelegate(@NonNull WebMessageListener webMessageListener, @NonNull MethodChannel channel) { - super(channel); - this.webMessageListener = webMessageListener; - } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - switch (call.method) { - case "postMessage": - if (webMessageListener != null && webMessageListener.webView instanceof InAppWebView) { - WebMessageCompatExt message = WebMessageCompatExt.fromMap((Map) call.argument("message")); - webMessageListener.postMessageForInAppWebView(message, result); - } else { - result.success(false); - } - break; - default: - result.notImplemented(); - } - } - - public void onPostMessage(@Nullable WebMessageCompatExt message, String sourceOrigin, boolean isMainFrame) { - MethodChannel channel = getChannel(); - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("message", message != null ? message.toMap() : null); - obj.put("sourceOrigin", sourceOrigin); - obj.put("isMainFrame", isMainFrame); - channel.invokeMethod("onPostMessage", obj); - } - - @Override - public void dispose() { - super.dispose(); - webMessageListener = null; - } -} diff --git a/flutter_inappwebview_android/android/src/main/res/drawable/floating_action_mode_shape.xml b/flutter_inappwebview_android/android/src/main/res/drawable/floating_action_mode_shape.xml deleted file mode 100644 index 9ad086b978..0000000000 --- a/flutter_inappwebview_android/android/src/main/res/drawable/floating_action_mode_shape.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/res/layout/activity_web_view.xml b/flutter_inappwebview_android/android/src/main/res/layout/activity_web_view.xml deleted file mode 100755 index bacc138847..0000000000 --- a/flutter_inappwebview_android/android/src/main/res/layout/activity_web_view.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - diff --git a/flutter_inappwebview_android/android/src/main/res/layout/chrome_custom_tabs_layout.xml b/flutter_inappwebview_android/android/src/main/res/layout/chrome_custom_tabs_layout.xml deleted file mode 100755 index f9504c9a46..0000000000 --- a/flutter_inappwebview_android/android/src/main/res/layout/chrome_custom_tabs_layout.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/flutter_inappwebview_android/android/src/main/res/layout/floating_action_mode.xml b/flutter_inappwebview_android/android/src/main/res/layout/floating_action_mode.xml deleted file mode 100644 index b58cc7cbc2..0000000000 --- a/flutter_inappwebview_android/android/src/main/res/layout/floating_action_mode.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/res/layout/floating_action_mode_item.xml b/flutter_inappwebview_android/android/src/main/res/layout/floating_action_mode_item.xml deleted file mode 100644 index 3ce3c11171..0000000000 --- a/flutter_inappwebview_android/android/src/main/res/layout/floating_action_mode_item.xml +++ /dev/null @@ -1,12 +0,0 @@ - - \ No newline at end of file diff --git a/flutter_inappwebview_android/android/src/main/res/menu/menu_main.xml b/flutter_inappwebview_android/android/src/main/res/menu/menu_main.xml deleted file mode 100755 index 2bff50bfe6..0000000000 --- a/flutter_inappwebview_android/android/src/main/res/menu/menu_main.xml +++ /dev/null @@ -1,49 +0,0 @@ - -

- - - - - - - - - - - - - - diff --git a/flutter_inappwebview_android/android/src/main/res/values/strings.xml b/flutter_inappwebview_android/android/src/main/res/values/strings.xml deleted file mode 100755 index 9301a93e2c..0000000000 --- a/flutter_inappwebview_android/android/src/main/res/values/strings.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - Go Back - Go Forward - Reload - Share - Close - Search - diff --git a/flutter_inappwebview_android/android/src/main/res/values/styles.xml b/flutter_inappwebview_android/android/src/main/res/values/styles.xml deleted file mode 100755 index 9665e05251..0000000000 --- a/flutter_inappwebview_android/android/src/main/res/values/styles.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - diff --git a/flutter_inappwebview_android/android/src/main/res/xml/provider_paths.xml b/flutter_inappwebview_android/android/src/main/res/xml/provider_paths.xml deleted file mode 100644 index ffa74ab562..0000000000 --- a/flutter_inappwebview_android/android/src/main/res/xml/provider_paths.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/flutter_inappwebview_android/build.yaml b/flutter_inappwebview_android/build.yaml deleted file mode 100644 index e2b3acf338..0000000000 --- a/flutter_inappwebview_android/build.yaml +++ /dev/null @@ -1,5 +0,0 @@ -targets: - $default: - sources: - exclude: - - example/**.dart diff --git a/flutter_inappwebview_android/example/.gitignore b/flutter_inappwebview_android/example/.gitignore deleted file mode 100644 index 24476c5d1e..0000000000 --- a/flutter_inappwebview_android/example/.gitignore +++ /dev/null @@ -1,44 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/flutter_inappwebview_android/example/README.md b/flutter_inappwebview_android/example/README.md deleted file mode 100644 index 833308e7f1..0000000000 --- a/flutter_inappwebview_android/example/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# flutter_inappwebview_android_example - -Demonstrates how to use the flutter_inappwebview_android plugin. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/flutter_inappwebview_android/example/analysis_options.yaml b/flutter_inappwebview_android/example/analysis_options.yaml deleted file mode 100644 index 0d2902135c..0000000000 --- a/flutter_inappwebview_android/example/analysis_options.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at https://dart.dev/lints. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/flutter_inappwebview_android/example/android/.gitignore b/flutter_inappwebview_android/example/android/.gitignore deleted file mode 100644 index 6f568019d3..0000000000 --- a/flutter_inappwebview_android/example/android/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties -**/*.keystore -**/*.jks diff --git a/flutter_inappwebview_android/example/android/app/build.gradle b/flutter_inappwebview_android/example/android/app/build.gradle deleted file mode 100644 index 910e846909..0000000000 --- a/flutter_inappwebview_android/example/android/app/build.gradle +++ /dev/null @@ -1,74 +0,0 @@ -plugins { - id "com.android.application" - id "kotlin-android" - id "dev.flutter.flutter-gradle-plugin" -} - -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -android { - namespace 'com.pichillilorenzo.flutter_inappwebview_android_example' - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - - compileSdkVersion flutter.compileSdkVersion - ndkVersion flutter.ndkVersion - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.pichillilorenzo.flutter_inappwebview_android_example" - minSdkVersion flutter.minSdkVersion - targetSdkVersion 36 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - multiDexEnabled true - } - - buildTypes { - release { - // only for com.pichillilorenzo.flutter_inappwebview_android.R.menu.menu_main - minifyEnabled false - shrinkResources false - - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } - - lint { - disable 'InvalidPackage' - } -} - -flutter { - source '../..' -} - -dependencies { - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test:runner:1.6.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' - implementation 'com.google.android.material:material:1.12.0' - implementation 'com.android.support:multidex:1.0.3' -} diff --git a/flutter_inappwebview_android/example/android/app/src/debug/AndroidManifest.xml b/flutter_inappwebview_android/example/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index 399f6981d5..0000000000 --- a/flutter_inappwebview_android/example/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/flutter_inappwebview_android/example/android/app/src/main/AndroidManifest.xml b/flutter_inappwebview_android/example/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 587125fec0..0000000000 --- a/flutter_inappwebview_android/example/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - diff --git a/flutter_inappwebview_android/example/android/app/src/main/java/com/pichillilorenzo/flutter_inappwebview_android_example/MainActivity.java b/flutter_inappwebview_android/example/android/app/src/main/java/com/pichillilorenzo/flutter_inappwebview_android_example/MainActivity.java deleted file mode 100644 index 8463e65902..0000000000 --- a/flutter_inappwebview_android/example/android/app/src/main/java/com/pichillilorenzo/flutter_inappwebview_android_example/MainActivity.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.pichillilorenzo.flutter_inappwebview_android_example; - -import io.flutter.embedding.android.FlutterActivity; - -public class MainActivity extends FlutterActivity { -} diff --git a/flutter_inappwebview_android/example/android/app/src/main/res/drawable-v21/launch_background.xml b/flutter_inappwebview_android/example/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f3f6..0000000000 --- a/flutter_inappwebview_android/example/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/flutter_inappwebview_android/example/android/app/src/main/res/drawable/launch_background.xml b/flutter_inappwebview_android/example/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f884..0000000000 --- a/flutter_inappwebview_android/example/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/flutter_inappwebview_android/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/flutter_inappwebview_android/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b7b..0000000000 Binary files a/flutter_inappwebview_android/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/flutter_inappwebview_android/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/flutter_inappwebview_android/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b79bb..0000000000 Binary files a/flutter_inappwebview_android/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/flutter_inappwebview_android/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/flutter_inappwebview_android/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 09d4391482..0000000000 Binary files a/flutter_inappwebview_android/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/flutter_inappwebview_android/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/flutter_inappwebview_android/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d34e..0000000000 Binary files a/flutter_inappwebview_android/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/flutter_inappwebview_android/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/flutter_inappwebview_android/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372eebd..0000000000 Binary files a/flutter_inappwebview_android/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/flutter_inappwebview_android/example/android/app/src/main/res/values-night/styles.xml b/flutter_inappwebview_android/example/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index 06952be745..0000000000 --- a/flutter_inappwebview_android/example/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/flutter_inappwebview_android/example/android/app/src/main/res/values/styles.xml b/flutter_inappwebview_android/example/android/app/src/main/res/values/styles.xml deleted file mode 100644 index cb1ef88056..0000000000 --- a/flutter_inappwebview_android/example/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/flutter_inappwebview_android/example/android/app/src/profile/AndroidManifest.xml b/flutter_inappwebview_android/example/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index 399f6981d5..0000000000 --- a/flutter_inappwebview_android/example/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/flutter_inappwebview_android/example/android/build.gradle b/flutter_inappwebview_android/example/android/build.gradle deleted file mode 100644 index bc157bd1a1..0000000000 --- a/flutter_inappwebview_android/example/android/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} diff --git a/flutter_inappwebview_android/example/android/gradle.properties b/flutter_inappwebview_android/example/android/gradle.properties deleted file mode 100644 index b9a9a24640..0000000000 --- a/flutter_inappwebview_android/example/android/gradle.properties +++ /dev/null @@ -1,6 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true -android.enableJetifier=true -android.defaults.buildfeatures.buildconfig=true -android.nonTransitiveRClass=false -android.nonFinalResIds=false diff --git a/flutter_inappwebview_android/example/android/gradle/wrapper/gradle-wrapper.properties b/flutter_inappwebview_android/example/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 8f3239ab68..0000000000 --- a/flutter_inappwebview_android/example/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip diff --git a/flutter_inappwebview_android/example/android/settings.gradle b/flutter_inappwebview_android/example/android/settings.gradle deleted file mode 100644 index c46f71ba7f..0000000000 --- a/flutter_inappwebview_android/example/android/settings.gradle +++ /dev/null @@ -1,25 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version '8.13.2' apply false - id "org.jetbrains.kotlin.android" version "2.2.20" apply false -} - -include ":app" \ No newline at end of file diff --git a/flutter_inappwebview_android/example/integration_test/plugin_integration_test.dart b/flutter_inappwebview_android/example/integration_test/plugin_integration_test.dart deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/flutter_inappwebview_android/example/lib/main.dart b/flutter_inappwebview_android/example/lib/main.dart deleted file mode 100644 index 5e541891cb..0000000000 --- a/flutter_inappwebview_android/example/lib/main.dart +++ /dev/null @@ -1,189 +0,0 @@ -import 'dart:async'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import 'package:flutter_inappwebview_android/flutter_inappwebview_android.dart'; -import 'package:url_launcher/url_launcher.dart'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - - await AndroidInAppWebViewController.static().setWebContentsDebuggingEnabled( - kDebugMode, - ); - - runApp(const MaterialApp(home: MyApp())); -} - -class MyApp extends StatefulWidget { - const MyApp({super.key}); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - final GlobalKey webViewKey = GlobalKey(); - - AndroidInAppWebViewController? webViewController; - InAppWebViewSettings settings = InAppWebViewSettings( - isInspectable: kDebugMode, - mediaPlaybackRequiresUserGesture: false, - allowsInlineMediaPlayback: true, - ); - - AndroidPullToRefreshController? pullToRefreshController; - String url = ""; - double progress = 0; - final urlController = TextEditingController(); - - @override - void initState() { - super.initState(); - - pullToRefreshController = AndroidPullToRefreshController( - AndroidPullToRefreshControllerCreationParams( - settings: PullToRefreshSettings(color: Colors.blue), - onRefresh: () async { - webViewController?.reload(); - }, - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text("Official InAppWebView website")), - body: SafeArea( - child: Column( - children: [ - TextField( - decoration: const InputDecoration(prefixIcon: Icon(Icons.search)), - controller: urlController, - keyboardType: TextInputType.url, - onSubmitted: (value) { - var url = WebUri(value); - if (url.scheme.isEmpty) { - url = WebUri("https://www.google.com/search?q=$value"); - } - webViewController?.loadUrl(urlRequest: URLRequest(url: url)); - }, - ), - Expanded( - child: Stack( - children: [ - AndroidInAppWebViewWidget( - AndroidInAppWebViewWidgetCreationParams( - key: webViewKey, - initialUrlRequest: URLRequest( - url: WebUri("https://inappwebview.dev/"), - ), - initialSettings: settings, - pullToRefreshController: pullToRefreshController, - onWebViewCreated: (controller) { - webViewController = - controller as AndroidInAppWebViewController; - }, - onLoadStart: (controller, url) { - setState(() { - this.url = url.toString(); - urlController.text = this.url; - }); - }, - onPermissionRequest: (controller, request) async { - return PermissionResponse( - resources: request.resources, - action: PermissionResponseAction.GRANT, - ); - }, - shouldOverrideUrlLoading: - (controller, navigationAction) async { - var uri = navigationAction.request.url!; - - if (![ - "http", - "https", - "file", - "chrome", - "data", - "javascript", - "about", - ].contains(uri.scheme)) { - if (await canLaunchUrl(uri)) { - // Launch the App - await launchUrl(uri); - // and cancel the request - return NavigationActionPolicy.CANCEL; - } - } - - return NavigationActionPolicy.ALLOW; - }, - onLoadStop: (controller, url) async { - pullToRefreshController?.endRefreshing(); - setState(() { - this.url = url.toString(); - urlController.text = this.url; - }); - }, - onReceivedError: (controller, request, error) { - pullToRefreshController?.endRefreshing(); - }, - onProgressChanged: (controller, progress) { - if (progress == 100) { - pullToRefreshController?.endRefreshing(); - } - setState(() { - this.progress = progress / 100; - urlController.text = url; - }); - }, - onUpdateVisitedHistory: (controller, url, isReload) { - setState(() { - this.url = url.toString(); - urlController.text = this.url; - }); - }, - onConsoleMessage: (controller, consoleMessage) { - if (kDebugMode) { - print(consoleMessage); - } - }, - ), - ).build(context), - progress < 1.0 - ? LinearProgressIndicator(value: progress) - : Container(), - ], - ), - ), - OverflowBar( - alignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - child: const Icon(Icons.arrow_back), - onPressed: () { - webViewController?.goBack(); - }, - ), - ElevatedButton( - child: const Icon(Icons.arrow_forward), - onPressed: () { - webViewController?.goForward(); - }, - ), - ElevatedButton( - child: const Icon(Icons.refresh), - onPressed: () { - webViewController?.reload(); - }, - ), - ], - ), - ], - ), - ), - ); - } -} diff --git a/flutter_inappwebview_android/example/pubspec.lock b/flutter_inappwebview_android/example/pubspec.lock deleted file mode 100644 index 6a87cace38..0000000000 --- a/flutter_inappwebview_android/example/pubspec.lock +++ /dev/null @@ -1,374 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" - url: "https://pub.dev" - source: hosted - version: "2.11.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - file: - dependency: transitive - description: - name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_driver: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_inappwebview_android: - dependency: "direct main" - description: - path: ".." - relative: true - source: path - version: "1.2.0-beta.3" - flutter_inappwebview_internal_annotations: - dependency: transitive - description: - path: "../../dev_packages/flutter_inappwebview_internal_annotations" - relative: true - source: path - version: "1.3.0" - flutter_inappwebview_platform_interface: - dependency: "direct main" - description: - path: "../../flutter_inappwebview_platform_interface" - relative: true - source: path - version: "1.4.0-beta.3" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 - url: "https://pub.dev" - source: hosted - version: "2.0.3" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - fuchsia_remote_debug_protocol: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - integration_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" - source: hosted - version: "11.0.2" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" - source: hosted - version: "3.0.10" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - lints: - dependency: transitive - description: - name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" - url: "https://pub.dev" - source: hosted - version: "1.17.0" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - platform: - dependency: transitive - description: - name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" - url: "https://pub.dev" - source: hosted - version: "3.1.5" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - process: - dependency: transitive - description: - name: process - sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" - url: "https://pub.dev" - source: hosted - version: "5.0.2" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_span: - dependency: transitive - description: - name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - sync_http: - dependency: transitive - description: - name: sync_http - sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" - url: "https://pub.dev" - source: hosted - version: "0.3.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test_api: - dependency: transitive - description: - name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 - url: "https://pub.dev" - source: hosted - version: "0.7.7" - url_launcher: - dependency: "direct main" - description: - name: url_launcher - sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.dev" - source: hosted - version: "6.3.2" - url_launcher_android: - dependency: transitive - description: - name: url_launcher_android - sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611" - url: "https://pub.dev" - source: hosted - version: "6.3.28" - url_launcher_ios: - dependency: transitive - description: - name: url_launcher_ios - sha256: cfde38aa257dae62ffe79c87fab20165dfdf6988c1d31b58ebf59b9106062aad - url: "https://pub.dev" - source: hosted - version: "6.3.6" - url_launcher_linux: - dependency: transitive - description: - name: url_launcher_linux - sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a - url: "https://pub.dev" - source: hosted - version: "3.2.2" - url_launcher_macos: - dependency: transitive - description: - name: url_launcher_macos - sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" - url: "https://pub.dev" - source: hosted - version: "3.2.5" - url_launcher_platform_interface: - dependency: transitive - description: - name: url_launcher_platform_interface - sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - url_launcher_web: - dependency: transitive - description: - name: url_launcher_web - sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f - url: "https://pub.dev" - source: hosted - version: "2.4.2" - url_launcher_windows: - dependency: transitive - description: - name: url_launcher_windows - sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" - url: "https://pub.dev" - source: hosted - version: "3.1.5" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" - source: hosted - version: "2.2.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" - url: "https://pub.dev" - source: hosted - version: "14.2.5" - web: - dependency: transitive - description: - name: web - sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - webdriver: - dependency: transitive - description: - name: webdriver - sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" - url: "https://pub.dev" - source: hosted - version: "3.0.3" -sdks: - dart: ">=3.10.0 <4.0.0" - flutter: ">=3.38.0" diff --git a/flutter_inappwebview_android/example/pubspec.yaml b/flutter_inappwebview_android/example/pubspec.yaml deleted file mode 100644 index 86b55bb691..0000000000 --- a/flutter_inappwebview_android/example/pubspec.yaml +++ /dev/null @@ -1,91 +0,0 @@ -name: flutter_inappwebview_android_example -description: Demonstrates how to use the flutter_inappwebview_android plugin. -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -environment: - sdk: ^3.8.0 - flutter: ">=3.32.0" - -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. -dependencies: - flutter: - sdk: flutter - - flutter_inappwebview_android: - # When depending on this package from a real application you should use: - # flutter_inappwebview_android: ^x.y.z - # See https://dart.dev/tools/pub/dependencies#version-constraints - # The example app is bundled with the plugin so we use a path dependency on - # the parent directory to use the current plugin's version. - path: ../ - - flutter_inappwebview_platform_interface: - path: ../../flutter_inappwebview_platform_interface - - url_launcher: ^6.1.0 - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 - -dev_dependencies: - integration_test: - sdk: flutter - flutter_test: - sdk: flutter - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^2.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/flutter_inappwebview_android/example/test/widget_test.dart b/flutter_inappwebview_android/example/test/widget_test.dart deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/flutter_inappwebview_android/lib/flutter_inappwebview_android.dart b/flutter_inappwebview_android/lib/flutter_inappwebview_android.dart deleted file mode 100644 index dd86c9e0d7..0000000000 --- a/flutter_inappwebview_android/lib/flutter_inappwebview_android.dart +++ /dev/null @@ -1,3 +0,0 @@ -library flutter_inappwebview_android; - -export 'src/main.dart'; diff --git a/flutter_inappwebview_android/lib/src/chrome_safari_browser/chrome_safari_browser.dart b/flutter_inappwebview_android/lib/src/chrome_safari_browser/chrome_safari_browser.dart deleted file mode 100755 index b857398efc..0000000000 --- a/flutter_inappwebview_android/lib/src/chrome_safari_browser/chrome_safari_browser.dart +++ /dev/null @@ -1,412 +0,0 @@ -import 'dart:async'; -import 'dart:collection'; -import 'dart:typed_data'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [AndroidChromeSafariBrowser]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformChromeSafariBrowserCreationParams] for -/// more information. -@immutable -class AndroidChromeSafariBrowserCreationParams - extends PlatformChromeSafariBrowserCreationParams { - /// Creates a new [AndroidChromeSafariBrowserCreationParams] instance. - const AndroidChromeSafariBrowserCreationParams(); - - /// Creates a [AndroidChromeSafariBrowserCreationParams] instance based on [PlatformChromeSafariBrowserCreationParams]. - factory AndroidChromeSafariBrowserCreationParams.fromPlatformChromeSafariBrowserCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformChromeSafariBrowserCreationParams params, - ) { - return AndroidChromeSafariBrowserCreationParams(); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser} -class AndroidChromeSafariBrowser extends PlatformChromeSafariBrowser - with ChannelController { - @override - final String id = IdGenerator.generate(); - - /// Constructs a [AndroidChromeSafariBrowser]. - AndroidChromeSafariBrowser(PlatformChromeSafariBrowserCreationParams params) - : super.implementation( - params is AndroidChromeSafariBrowserCreationParams - ? params - : AndroidChromeSafariBrowserCreationParams.fromPlatformChromeSafariBrowserCreationParams( - params, - ), - ); - - static final AndroidChromeSafariBrowser _staticValue = - AndroidChromeSafariBrowser(AndroidChromeSafariBrowserCreationParams()); - - /// Provide static access. - factory AndroidChromeSafariBrowser.static() { - return _staticValue; - } - - ChromeSafariBrowserActionButton? _actionButton; - Map _menuItems = new HashMap(); - ChromeSafariBrowserSecondaryToolbar? _secondaryToolbar; - bool _isOpened = false; - static const MethodChannel _staticChannel = const MethodChannel( - 'com.pichillilorenzo/flutter_chromesafaribrowser', - ); - - _init() { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_chromesafaribrowser_$id', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - id: id, - debugLoggingSettings: PlatformChromeSafariBrowser.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - _debugLog(call.method, call.arguments); - - switch (call.method) { - case "onServiceConnected": - eventHandler?.onServiceConnected(); - break; - case "onOpened": - eventHandler?.onOpened(); - break; - case "onCompletedInitialLoad": - final bool? didLoadSuccessfully = call.arguments["didLoadSuccessfully"]; - eventHandler?.onCompletedInitialLoad(didLoadSuccessfully); - break; - case "onNavigationEvent": - final navigationEvent = CustomTabsNavigationEventType.fromNativeValue( - call.arguments["navigationEvent"], - ); - eventHandler?.onNavigationEvent(navigationEvent); - break; - case "onRelationshipValidationResult": - final relation = CustomTabsRelationType.fromNativeValue( - call.arguments["relation"], - ); - final requestedOrigin = call.arguments["requestedOrigin"] != null - ? WebUri(call.arguments["requestedOrigin"]) - : null; - final bool result = call.arguments["result"]; - eventHandler?.onRelationshipValidationResult( - relation, - requestedOrigin, - result, - ); - break; - case "onClosed": - _isOpened = false; - final onClosed = eventHandler?.onClosed; - dispose(); - onClosed?.call(); - break; - case "onItemActionPerform": - String url = call.arguments["url"]; - String title = call.arguments["title"]; - int id = call.arguments["id"].toInt(); - if (this._actionButton?.id == id) { - if (this._actionButton?.action != null) { - this._actionButton?.action!(url, title); - } - if (this._actionButton?.onClick != null) { - this._actionButton?.onClick!(WebUri(url), title); - } - } else if (this._menuItems[id] != null) { - if (this._menuItems[id]?.action != null) { - this._menuItems[id]?.action!(url, title); - } - if (this._menuItems[id]?.onClick != null) { - this._menuItems[id]?.onClick!(WebUri(url), title); - } - } - break; - case "onSecondaryItemActionPerform": - final clickableIDs = this._secondaryToolbar?.clickableIDs; - if (clickableIDs != null) { - WebUri? url = call.arguments["url"] != null - ? WebUri(call.arguments["url"]) - : null; - String name = call.arguments["name"]; - for (final clickable in clickableIDs) { - var clickableFullname = clickable.id.name; - if (clickable.id.defType != null && - !clickableFullname.contains("/")) { - clickableFullname = "${clickable.id.defType}/$clickableFullname"; - } - if (clickable.id.defPackage != null && - !clickableFullname.contains(":")) { - clickableFullname = - "${clickable.id.defPackage}:$clickableFullname"; - } - if (clickableFullname == name) { - if (clickable.onClick != null) { - clickable.onClick!(url); - } - break; - } - } - } - break; - case "onMessageChannelReady": - eventHandler?.onMessageChannelReady(); - break; - case "onPostMessage": - final String message = call.arguments["message"]; - eventHandler?.onPostMessage(message); - break; - case "onVerticalScrollEvent": - final bool isDirectionUp = call.arguments["isDirectionUp"]; - eventHandler?.onVerticalScrollEvent(isDirectionUp); - break; - case "onGreatestScrollPercentageIncreased": - final int scrollPercentage = call.arguments["scrollPercentage"]; - eventHandler?.onGreatestScrollPercentageIncreased(scrollPercentage); - break; - case "onSessionEnded": - final bool didUserInteract = call.arguments["didUserInteract"]; - eventHandler?.onSessionEnded(didUserInteract); - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - } - - @override - Future open({ - WebUri? url, - Map? headers, - List? otherLikelyURLs, - WebUri? referrer, - @Deprecated('Use settings instead') - // ignore: deprecated_member_use_from_same_package - ChromeSafariBrowserClassOptions? options, - ChromeSafariBrowserSettings? settings, - }) async { - assert(!_isOpened, 'The browser is already opened.'); - _isOpened = true; - - if (Util.isIOS) { - assert(url != null, 'The specified URL must not be null on iOS.'); - assert( - ['http', 'https'].contains(url!.scheme), - 'The specified URL has an unsupported scheme. Only HTTP and HTTPS URLs are supported on iOS.', - ); - } - if (url != null) { - assert(url.toString().isNotEmpty, 'The specified URL must not be empty.'); - } - - _init(); - - List> menuItemList = []; - _menuItems.forEach((key, value) { - menuItemList.add(value.toMap()); - }); - - var initialSettings = - settings?.toMap() ?? - options?.toMap() ?? - ChromeSafariBrowserSettings().toMap(); - - Map args = {}; - args.putIfAbsent('id', () => id); - args.putIfAbsent('url', () => url?.toString()); - args.putIfAbsent('headers', () => headers); - args.putIfAbsent( - 'otherLikelyURLs', - () => otherLikelyURLs?.map((e) => e.toString()).toList(), - ); - args.putIfAbsent('referrer', () => referrer?.toString()); - args.putIfAbsent('settings', () => initialSettings); - args.putIfAbsent('actionButton', () => _actionButton?.toMap()); - args.putIfAbsent('secondaryToolbar', () => _secondaryToolbar?.toMap()); - args.putIfAbsent('menuItemList', () => menuItemList); - await _staticChannel.invokeMethod('open', args); - } - - @override - Future launchUrl({ - required WebUri url, - Map? headers, - List? otherLikelyURLs, - WebUri? referrer, - }) async { - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - args.putIfAbsent('headers', () => headers); - args.putIfAbsent( - 'otherLikelyURLs', - () => otherLikelyURLs?.map((e) => e.toString()).toList(), - ); - args.putIfAbsent('referrer', () => referrer?.toString()); - await channel?.invokeMethod("launchUrl", args); - } - - @override - Future mayLaunchUrl({ - WebUri? url, - List? otherLikelyURLs, - }) async { - Map args = {}; - args.putIfAbsent('url', () => url?.toString()); - args.putIfAbsent( - 'otherLikelyURLs', - () => otherLikelyURLs?.map((e) => e.toString()).toList(), - ); - return await channel?.invokeMethod("mayLaunchUrl", args) ?? false; - } - - @override - Future validateRelationship({ - required CustomTabsRelationType relation, - required WebUri origin, - }) async { - Map args = {}; - args.putIfAbsent('relation', () => relation.toNativeValue()); - args.putIfAbsent('origin', () => origin.toString()); - return await channel?.invokeMethod("validateRelationship", args) ?? - false; - } - - @override - Future close() async { - Map args = {}; - await channel?.invokeMethod("close", args); - } - - @override - void setActionButton(ChromeSafariBrowserActionButton actionButton) { - this._actionButton = actionButton; - } - - @override - Future updateActionButton({ - required Uint8List icon, - required String description, - }) async { - Map args = {}; - args.putIfAbsent('icon', () => icon); - args.putIfAbsent('description', () => description); - await channel?.invokeMethod("updateActionButton", args); - _actionButton?.icon = icon; - _actionButton?.description = description; - } - - @override - void setSecondaryToolbar( - ChromeSafariBrowserSecondaryToolbar secondaryToolbar, - ) { - this._secondaryToolbar = secondaryToolbar; - } - - @override - Future updateSecondaryToolbar( - ChromeSafariBrowserSecondaryToolbar secondaryToolbar, - ) async { - Map args = {}; - args.putIfAbsent('secondaryToolbar', () => secondaryToolbar.toMap()); - await channel?.invokeMethod("updateSecondaryToolbar", args); - this._secondaryToolbar = secondaryToolbar; - } - - @override - void addMenuItem(ChromeSafariBrowserMenuItem menuItem) { - this._menuItems[menuItem.id] = menuItem; - } - - @override - void addMenuItems(List menuItems) { - menuItems.forEach((menuItem) { - this._menuItems[menuItem.id] = menuItem; - }); - } - - @override - Future requestPostMessageChannel({ - required WebUri sourceOrigin, - WebUri? targetOrigin, - }) async { - Map args = {}; - args.putIfAbsent("sourceOrigin", () => sourceOrigin.toString()); - args.putIfAbsent("targetOrigin", () => targetOrigin.toString()); - return await channel?.invokeMethod( - "requestPostMessageChannel", - args, - ) ?? - false; - } - - @override - Future postMessage(String message) async { - Map args = {}; - args.putIfAbsent("message", () => message); - return CustomTabsPostMessageResultType.fromNativeValue( - await channel?.invokeMethod("postMessage", args), - ) ?? - CustomTabsPostMessageResultType.FAILURE_MESSAGING_ERROR; - } - - @override - Future isEngagementSignalsApiAvailable() async { - Map args = {}; - return await channel?.invokeMethod( - "isEngagementSignalsApiAvailable", - args, - ) ?? - false; - } - - @override - Future isAvailable() async { - Map args = {}; - return await _staticChannel.invokeMethod("isAvailable", args) ?? - false; - } - - @override - Future getMaxToolbarItems() async { - Map args = {}; - return await _staticChannel.invokeMethod("getMaxToolbarItems", args) ?? - 0; - } - - @override - Future getPackageName({ - List? packages, - bool ignoreDefault = false, - }) async { - Map args = {}; - args.putIfAbsent("packages", () => packages); - args.putIfAbsent("ignoreDefault", () => ignoreDefault); - return await _staticChannel.invokeMethod("getPackageName", args); - } - - @override - bool isOpened() { - return _isOpened; - } - - @override - @mustCallSuper - void dispose() { - super.dispose(); - disposeChannel(); - } -} diff --git a/flutter_inappwebview_android/lib/src/chrome_safari_browser/main.dart b/flutter_inappwebview_android/lib/src/chrome_safari_browser/main.dart deleted file mode 100644 index 9a6238b706..0000000000 --- a/flutter_inappwebview_android/lib/src/chrome_safari_browser/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'chrome_safari_browser.dart'; diff --git a/flutter_inappwebview_android/lib/src/cookie_manager.dart b/flutter_inappwebview_android/lib/src/cookie_manager.dart deleted file mode 100755 index 4535167727..0000000000 --- a/flutter_inappwebview_android/lib/src/cookie_manager.dart +++ /dev/null @@ -1,249 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [AndroidCookieManager]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformCookieManagerCreationParams] for -/// more information. -@immutable -class AndroidCookieManagerCreationParams - extends PlatformCookieManagerCreationParams { - /// Creates a new [AndroidCookieManagerCreationParams] instance. - const AndroidCookieManagerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformCookieManagerCreationParams params, - ) : super(); - - /// Creates a [AndroidCookieManagerCreationParams] instance based on [PlatformCookieManagerCreationParams]. - factory AndroidCookieManagerCreationParams.fromPlatformCookieManagerCreationParams( - PlatformCookieManagerCreationParams params, - ) { - return AndroidCookieManagerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager} -class AndroidCookieManager extends PlatformCookieManager - with ChannelController { - /// Creates a new [AndroidCookieManager]. - AndroidCookieManager(PlatformCookieManagerCreationParams params) - : super.implementation( - params is AndroidCookieManagerCreationParams - ? params - : AndroidCookieManagerCreationParams.fromPlatformCookieManagerCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_cookiemanager', - ); - handler = handleMethod; - initMethodCallHandler(); - } - - static final AndroidCookieManager _staticValue = AndroidCookieManager( - AndroidCookieManagerCreationParams(PlatformCookieManagerCreationParams()), - ); - - factory AndroidCookieManager.static() { - return _staticValue; - } - - static AndroidCookieManager? _instance; - - ///Gets the [AndroidCookieManager] shared instance. - static AndroidCookieManager instance() { - return (_instance != null) ? _instance! : _init(); - } - - static AndroidCookieManager _init() { - _instance = AndroidCookieManager( - AndroidCookieManagerCreationParams( - const PlatformCookieManagerCreationParams(), - ), - ); - return _instance!; - } - - Future _handleMethod(MethodCall call) async {} - - @override - Future setCookie({ - required WebUri url, - required String name, - required String value, - String path = "/", - String? domain, - int? expiresDate, - int? maxAge, - bool? isSecure, - bool? isHttpOnly, - HTTPCookieSameSitePolicy? sameSite, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - assert(url.toString().isNotEmpty); - assert(name.isNotEmpty); - assert(path.isNotEmpty); - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - args.putIfAbsent('name', () => name); - args.putIfAbsent('value', () => value); - args.putIfAbsent('domain', () => domain); - args.putIfAbsent('path', () => path); - args.putIfAbsent('expiresDate', () => expiresDate?.toString()); - args.putIfAbsent('maxAge', () => maxAge); - args.putIfAbsent('isSecure', () => isSecure); - args.putIfAbsent('isHttpOnly', () => isHttpOnly); - args.putIfAbsent('sameSite', () => sameSite?.toNativeValue()); - - return await channel?.invokeMethod('setCookie', args) ?? false; - } - - @override - Future> getCookies({ - required WebUri url, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - assert(url.toString().isNotEmpty); - - List cookies = []; - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - List cookieListMap = - await channel?.invokeMethod('getCookies', args) ?? []; - cookieListMap = cookieListMap.cast>(); - - cookieListMap.forEach((cookieMap) { - cookies.add( - Cookie( - name: cookieMap["name"], - value: cookieMap["value"], - expiresDate: cookieMap["expiresDate"], - isSessionOnly: cookieMap["isSessionOnly"], - domain: cookieMap["domain"], - sameSite: HTTPCookieSameSitePolicy.fromNativeValue( - cookieMap["sameSite"], - ), - isSecure: cookieMap["isSecure"], - isHttpOnly: cookieMap["isHttpOnly"], - path: cookieMap["path"], - ), - ); - }); - return cookies; - } - - @override - Future getCookie({ - required WebUri url, - required String name, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - assert(url.toString().isNotEmpty); - assert(name.isNotEmpty); - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - List cookies = - await channel?.invokeMethod('getCookies', args) ?? []; - cookies = cookies.cast>(); - for (var i = 0; i < cookies.length; i++) { - cookies[i] = cookies[i].cast(); - if (cookies[i]["name"] == name) - return Cookie( - name: cookies[i]["name"], - value: cookies[i]["value"], - expiresDate: cookies[i]["expiresDate"], - isSessionOnly: cookies[i]["isSessionOnly"], - domain: cookies[i]["domain"], - sameSite: HTTPCookieSameSitePolicy.fromNativeValue( - cookies[i]["sameSite"], - ), - isSecure: cookies[i]["isSecure"], - isHttpOnly: cookies[i]["isHttpOnly"], - path: cookies[i]["path"], - ); - } - return null; - } - - @override - Future deleteCookie({ - required WebUri url, - required String name, - String path = "/", - String? domain, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - assert(url.toString().isNotEmpty); - assert(name.isNotEmpty); - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - args.putIfAbsent('name', () => name); - args.putIfAbsent('domain', () => domain); - args.putIfAbsent('path', () => path); - return await channel?.invokeMethod('deleteCookie', args) ?? false; - } - - @override - Future deleteCookies({ - required WebUri url, - String path = "/", - String? domain, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - assert(url.toString().isNotEmpty); - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - args.putIfAbsent('domain', () => domain); - args.putIfAbsent('path', () => path); - return await channel?.invokeMethod('deleteCookies', args) ?? false; - } - - @override - Future deleteAllCookies() async { - Map args = {}; - return await channel?.invokeMethod('deleteAllCookies', args) ?? false; - } - - @override - Future removeSessionCookies() async { - Map args = {}; - return await channel?.invokeMethod('removeSessionCookies', args) ?? - false; - } - - @override - Future flush() async { - Map args = {}; - await channel?.invokeMethod('flush', args); - } - - @override - void dispose() { - // empty - } -} - -extension InternalCookieManager on AndroidCookieManager { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_android/lib/src/find_interaction/find_interaction_controller.dart b/flutter_inappwebview_android/lib/src/find_interaction/find_interaction_controller.dart deleted file mode 100644 index 2689590496..0000000000 --- a/flutter_inappwebview_android/lib/src/find_interaction/find_interaction_controller.dart +++ /dev/null @@ -1,146 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [AndroidFindInteractionController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformFindInteractionControllerCreationParams] for -/// more information. -@immutable -class AndroidFindInteractionControllerCreationParams - extends PlatformFindInteractionControllerCreationParams { - /// Creates a new [AndroidFindInteractionControllerCreationParams] instance. - const AndroidFindInteractionControllerCreationParams({ - super.onFindResultReceived, - }); - - /// Creates a [AndroidFindInteractionControllerCreationParams] instance based on [PlatformFindInteractionControllerCreationParams]. - factory AndroidFindInteractionControllerCreationParams.fromPlatformFindInteractionControllerCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformFindInteractionControllerCreationParams params, - ) { - return AndroidFindInteractionControllerCreationParams( - onFindResultReceived: params.onFindResultReceived, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController} -class AndroidFindInteractionController extends PlatformFindInteractionController - with ChannelController { - /// Constructs a [AndroidFindInteractionController]. - AndroidFindInteractionController( - PlatformFindInteractionControllerCreationParams params, - ) : super.implementation( - params is AndroidFindInteractionControllerCreationParams - ? params - : AndroidFindInteractionControllerCreationParams.fromPlatformFindInteractionControllerCreationParams( - params, - ), - ); - - static final AndroidFindInteractionController _staticValue = - AndroidFindInteractionController( - AndroidFindInteractionControllerCreationParams(), - ); - - /// Provide static access. - factory AndroidFindInteractionController.static() { - return _staticValue; - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - debugLoggingSettings: - PlatformFindInteractionController.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - _debugLog(call.method, call.arguments); - - switch (call.method) { - case "onFindResultReceived": - if (onFindResultReceived != null) { - int activeMatchOrdinal = call.arguments["activeMatchOrdinal"]; - int numberOfMatches = call.arguments["numberOfMatches"]; - bool isDoneCounting = call.arguments["isDoneCounting"]; - onFindResultReceived!( - this, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findAll} - Future findAll({String? find}) async { - Map args = {}; - args.putIfAbsent('find', () => find); - await channel?.invokeMethod('findAll', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findNext} - Future findNext({bool forward = true}) async { - Map args = {}; - args.putIfAbsent('forward', () => forward); - await channel?.invokeMethod('findNext', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.clearMatches} - Future clearMatches() async { - Map args = {}; - await channel?.invokeMethod('clearMatches', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.setSearchText} - Future setSearchText(String? searchText) async { - Map args = {}; - args.putIfAbsent('searchText', () => searchText); - await channel?.invokeMethod('setSearchText', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getSearchText} - Future getSearchText() async { - Map args = {}; - return await channel?.invokeMethod('getSearchText', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getActiveFindSession} - Future getActiveFindSession() async { - Map args = {}; - Map? result = (await channel?.invokeMethod( - 'getActiveFindSession', - args, - ))?.cast(); - return FindSession.fromMap(result); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.dispose} - @override - void dispose({bool isKeepAlive = false}) { - disposeChannel(removeMethodCallHandler: !isKeepAlive); - } -} - -extension InternalFindInteractionController - on AndroidFindInteractionController { - void init(dynamic id) { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_find_interaction_$id', - ); - handler = _handleMethod; - initMethodCallHandler(); - } -} diff --git a/flutter_inappwebview_android/lib/src/find_interaction/main.dart b/flutter_inappwebview_android/lib/src/find_interaction/main.dart deleted file mode 100644 index a7adaacf7b..0000000000 --- a/flutter_inappwebview_android/lib/src/find_interaction/main.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'find_interaction_controller.dart' - hide InternalFindInteractionController; diff --git a/flutter_inappwebview_android/lib/src/http_auth_credentials_database.dart b/flutter_inappwebview_android/lib/src/http_auth_credentials_database.dart deleted file mode 100755 index 80e2649cfa..0000000000 --- a/flutter_inappwebview_android/lib/src/http_auth_credentials_database.dart +++ /dev/null @@ -1,177 +0,0 @@ -import 'dart:async'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [AndroidHttpAuthCredentialDatabase]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformHttpAuthCredentialDatabaseCreationParams] for -/// more information. -@immutable -class AndroidHttpAuthCredentialDatabaseCreationParams - extends PlatformHttpAuthCredentialDatabaseCreationParams { - /// Creates a new [AndroidHttpAuthCredentialDatabaseCreationParams] instance. - const AndroidHttpAuthCredentialDatabaseCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) : super(); - - /// Creates a [AndroidHttpAuthCredentialDatabaseCreationParams] instance based on [PlatformHttpAuthCredentialDatabaseCreationParams]. - factory AndroidHttpAuthCredentialDatabaseCreationParams.fromPlatformHttpAuthCredentialDatabaseCreationParams( - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) { - return AndroidHttpAuthCredentialDatabaseCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase} -class AndroidHttpAuthCredentialDatabase - extends PlatformHttpAuthCredentialDatabase - with ChannelController { - /// Creates a new [AndroidHttpAuthCredentialDatabase]. - AndroidHttpAuthCredentialDatabase( - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) : super.implementation( - params is AndroidHttpAuthCredentialDatabaseCreationParams - ? params - : AndroidHttpAuthCredentialDatabaseCreationParams.fromPlatformHttpAuthCredentialDatabaseCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_credential_database', - ); - handler = handleMethod; - initMethodCallHandler(); - } - - static AndroidHttpAuthCredentialDatabase? _instance; - - ///Gets the database shared instance. - static AndroidHttpAuthCredentialDatabase instance() { - return (_instance != null) ? _instance! : _init(); - } - - static AndroidHttpAuthCredentialDatabase _init() { - _instance = AndroidHttpAuthCredentialDatabase( - AndroidHttpAuthCredentialDatabaseCreationParams( - const PlatformHttpAuthCredentialDatabaseCreationParams(), - ), - ); - return _instance!; - } - - static final AndroidHttpAuthCredentialDatabase _staticValue = - AndroidHttpAuthCredentialDatabase( - AndroidHttpAuthCredentialDatabaseCreationParams( - const PlatformHttpAuthCredentialDatabaseCreationParams(), - ), - ); - - factory AndroidHttpAuthCredentialDatabase.static() { - return _staticValue; - } - - Future _handleMethod(MethodCall call) async {} - - @override - Future> - getAllAuthCredentials() async { - Map args = {}; - List allCredentials = - await channel?.invokeMethod('getAllAuthCredentials', args) ?? []; - - List result = []; - - for (Map map in allCredentials) { - var element = URLProtectionSpaceHttpAuthCredentials.fromMap( - map.cast(), - ); - if (element != null) { - result.add(element); - } - } - return result; - } - - @override - Future> getHttpAuthCredentials({ - required URLProtectionSpace protectionSpace, - }) async { - Map args = {}; - args.putIfAbsent("host", () => protectionSpace.host); - args.putIfAbsent("protocol", () => protectionSpace.protocol); - args.putIfAbsent("realm", () => protectionSpace.realm); - args.putIfAbsent("port", () => protectionSpace.port); - List credentialList = - await channel?.invokeMethod('getHttpAuthCredentials', args) ?? []; - List credentials = []; - for (Map map in credentialList) { - var credential = URLCredential.fromMap(map.cast()); - if (credential != null) { - credentials.add(credential); - } - } - return credentials; - } - - @override - Future setHttpAuthCredential({ - required URLProtectionSpace protectionSpace, - required URLCredential credential, - }) async { - Map args = {}; - args.putIfAbsent("host", () => protectionSpace.host); - args.putIfAbsent("protocol", () => protectionSpace.protocol); - args.putIfAbsent("realm", () => protectionSpace.realm); - args.putIfAbsent("port", () => protectionSpace.port); - args.putIfAbsent("username", () => credential.username); - args.putIfAbsent("password", () => credential.password); - await channel?.invokeMethod('setHttpAuthCredential', args); - } - - @override - Future removeHttpAuthCredential({ - required URLProtectionSpace protectionSpace, - required URLCredential credential, - }) async { - Map args = {}; - args.putIfAbsent("host", () => protectionSpace.host); - args.putIfAbsent("protocol", () => protectionSpace.protocol); - args.putIfAbsent("realm", () => protectionSpace.realm); - args.putIfAbsent("port", () => protectionSpace.port); - args.putIfAbsent("username", () => credential.username); - args.putIfAbsent("password", () => credential.password); - await channel?.invokeMethod('removeHttpAuthCredential', args); - } - - @override - Future removeHttpAuthCredentials({ - required URLProtectionSpace protectionSpace, - }) async { - Map args = {}; - args.putIfAbsent("host", () => protectionSpace.host); - args.putIfAbsent("protocol", () => protectionSpace.protocol); - args.putIfAbsent("realm", () => protectionSpace.realm); - args.putIfAbsent("port", () => protectionSpace.port); - await channel?.invokeMethod('removeHttpAuthCredentials', args); - } - - @override - Future clearAllAuthCredentials() async { - Map args = {}; - await channel?.invokeMethod('clearAllAuthCredentials', args); - } - - @override - void dispose() { - // empty - } -} - -extension InternalHttpAuthCredentialDatabase - on AndroidHttpAuthCredentialDatabase { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_android/lib/src/in_app_browser/in_app_browser.dart b/flutter_inappwebview_android/lib/src/in_app_browser/in_app_browser.dart deleted file mode 100755 index afd3529120..0000000000 --- a/flutter_inappwebview_android/lib/src/in_app_browser/in_app_browser.dart +++ /dev/null @@ -1,404 +0,0 @@ -import 'dart:async'; -import 'dart:collection'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../find_interaction/find_interaction_controller.dart'; -import '../in_app_webview/in_app_webview_controller.dart'; -import '../pull_to_refresh/pull_to_refresh_controller.dart'; - -/// Object specifying creation parameters for creating a [AndroidInAppBrowser]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformInAppBrowserCreationParams] for -/// more information. -class AndroidInAppBrowserCreationParams - extends PlatformInAppBrowserCreationParams { - /// Creates a new [AndroidInAppBrowserCreationParams] instance. - AndroidInAppBrowserCreationParams({ - super.contextMenu, - this.pullToRefreshController, - this.findInteractionController, - super.initialUserScripts, - super.windowId, - }); - - /// Creates a [AndroidInAppBrowserCreationParams] instance based on [PlatformInAppBrowserCreationParams]. - factory AndroidInAppBrowserCreationParams.fromPlatformInAppBrowserCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformInAppBrowserCreationParams params, - ) { - return AndroidInAppBrowserCreationParams( - contextMenu: params.contextMenu, - pullToRefreshController: - params.pullToRefreshController as AndroidPullToRefreshController?, - findInteractionController: - params.findInteractionController as AndroidFindInteractionController?, - initialUserScripts: params.initialUserScripts, - windowId: params.windowId, - ); - } - - @override - final AndroidFindInteractionController? findInteractionController; - - @override - final AndroidPullToRefreshController? pullToRefreshController; -} - -///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser} -class AndroidInAppBrowser extends PlatformInAppBrowser with ChannelController { - @override - final String id = IdGenerator.generate(); - - /// Constructs a [AndroidInAppBrowser]. - AndroidInAppBrowser(PlatformInAppBrowserCreationParams params) - : super.implementation( - params is AndroidInAppBrowserCreationParams - ? params - : AndroidInAppBrowserCreationParams.fromPlatformInAppBrowserCreationParams( - params, - ), - ) { - _contextMenu = params.contextMenu; - } - - static final AndroidInAppBrowser _staticValue = AndroidInAppBrowser( - AndroidInAppBrowserCreationParams(), - ); - - /// Provide static access. - factory AndroidInAppBrowser.static() { - return _staticValue; - } - - AndroidInAppBrowserCreationParams get _androidParams => - params as AndroidInAppBrowserCreationParams; - - static const MethodChannel _staticChannel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappbrowser', - ); - - ContextMenu? _contextMenu; - - @override - ContextMenu? get contextMenu => _contextMenu; - - Map _menuItems = HashMap(); - bool _isOpened = false; - AndroidInAppWebViewController? _webViewController; - - @override - AndroidInAppWebViewController? get webViewController { - return _isOpened ? _webViewController : null; - } - - _init() { - channel = MethodChannel('com.pichillilorenzo/flutter_inappbrowser_$id'); - handler = _handleMethod; - initMethodCallHandler(); - - _webViewController = AndroidInAppWebViewController.fromInAppBrowser( - AndroidInAppWebViewControllerCreationParams(id: id), - channel!, - this, - this.initialUserScripts, - ); - _androidParams.pullToRefreshController?.init(id); - _androidParams.findInteractionController?.init(id); - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - id: id, - debugLoggingSettings: PlatformInAppBrowser.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onBrowserCreated": - _debugLog(call.method, call.arguments); - eventHandler?.onBrowserCreated(); - break; - case "onMenuItemClicked": - _debugLog(call.method, call.arguments); - int id = call.arguments["id"].toInt(); - if (this._menuItems[id] != null) { - if (this._menuItems[id]?.onClick != null) { - this._menuItems[id]?.onClick!(); - } - } - break; - case "onExit": - _debugLog(call.method, call.arguments); - _isOpened = false; - final onExit = eventHandler?.onExit; - dispose(); - onExit?.call(); - break; - default: - return _webViewController?.handleMethod(call); - } - } - - Map _prepareOpenRequest({ - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) { - assert(!_isOpened, 'The browser is already opened.'); - _isOpened = true; - _init(); - - var initialSettings = - settings?.toMap() ?? - options?.toMap() ?? - InAppBrowserClassSettings().toMap(); - - Map pullToRefreshSettings = - pullToRefreshController?.settings.toMap() ?? - pullToRefreshController?.options.toMap() ?? - PullToRefreshSettings(enabled: false).toMap(); - - List> menuItemList = []; - _menuItems.forEach((key, value) { - menuItemList.add(value.toMap()); - }); - - Map args = {}; - args.putIfAbsent('id', () => id); - args.putIfAbsent('settings', () => initialSettings); - args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {}); - args.putIfAbsent('windowId', () => windowId); - args.putIfAbsent( - 'initialUserScripts', - () => initialUserScripts?.map((e) => e.toMap()).toList() ?? [], - ); - args.putIfAbsent('pullToRefreshSettings', () => pullToRefreshSettings); - args.putIfAbsent('menuItems', () => menuItemList); - return args; - } - - @override - Future openUrlRequest({ - required URLRequest urlRequest, - // ignore: deprecated_member_use_from_same_package - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) async { - assert(urlRequest.url != null && urlRequest.url.toString().isNotEmpty); - - Map args = _prepareOpenRequest( - options: options, - settings: settings, - ); - args.putIfAbsent('urlRequest', () => urlRequest.toMap()); - await _staticChannel.invokeMethod('open', args); - } - - @override - Future openFile({ - required String assetFilePath, - // ignore: deprecated_member_use_from_same_package - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) async { - assert(assetFilePath.isNotEmpty); - - Map args = _prepareOpenRequest( - options: options, - settings: settings, - ); - args.putIfAbsent('assetFilePath', () => assetFilePath); - await _staticChannel.invokeMethod('open', args); - } - - @override - Future openData({ - required String data, - String mimeType = "text/html", - String encoding = "utf8", - WebUri? baseUrl, - @Deprecated("Use historyUrl instead") Uri? androidHistoryUrl, - WebUri? historyUrl, - // ignore: deprecated_member_use_from_same_package - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) async { - Map args = _prepareOpenRequest( - options: options, - settings: settings, - ); - args.putIfAbsent('data', () => data); - args.putIfAbsent('mimeType', () => mimeType); - args.putIfAbsent('encoding', () => encoding); - args.putIfAbsent('baseUrl', () => baseUrl?.toString() ?? "about:blank"); - args.putIfAbsent( - 'historyUrl', - () => (historyUrl ?? androidHistoryUrl)?.toString() ?? "about:blank", - ); - await _staticChannel.invokeMethod('open', args); - } - - @override - Future openWithSystemBrowser({required WebUri url}) async { - assert(url.toString().isNotEmpty); - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - return await _staticChannel.invokeMethod('openWithSystemBrowser', args); - } - - @override - void addMenuItem(InAppBrowserMenuItem menuItem) { - _menuItems[menuItem.id] = menuItem; - } - - @override - void addMenuItems(List menuItems) { - menuItems.forEach((menuItem) { - _menuItems[menuItem.id] = menuItem; - }); - } - - @override - bool removeMenuItem(InAppBrowserMenuItem menuItem) { - return _menuItems.remove(menuItem.id) != null; - } - - @override - void removeMenuItems(List menuItems) { - for (final menuItem in menuItems) { - removeMenuItem(menuItem); - } - } - - @override - void removeAllMenuItem() { - _menuItems.clear(); - } - - @override - bool hasMenuItem(InAppBrowserMenuItem menuItem) { - return _menuItems.containsKey(menuItem.id); - } - - @override - Future show() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - await channel?.invokeMethod('show', args); - } - - @override - Future hide() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - await channel?.invokeMethod('hide', args); - } - - @override - Future close() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - await channel?.invokeMethod('close', args); - } - - @override - Future isHidden() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - return await channel?.invokeMethod('isHidden', args) ?? false; - } - - @override - @Deprecated('Use setSettings instead') - Future setOptions({required InAppBrowserClassOptions options}) async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - args.putIfAbsent('settings', () => options.toMap()); - await channel?.invokeMethod('setSettings', args); - } - - @override - @Deprecated('Use getSettings instead') - Future getOptions() async { - assert(_isOpened, 'The browser is not opened.'); - Map args = {}; - - Map? options = await channel?.invokeMethod( - 'getSettings', - args, - ); - if (options != null) { - options = options.cast(); - return InAppBrowserClassOptions.fromMap(options as Map); - } - - return null; - } - - @override - Future setSettings({ - required InAppBrowserClassSettings settings, - }) async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - args.putIfAbsent('settings', () => settings.toMap()); - await channel?.invokeMethod('setSettings', args); - } - - @override - Future getSettings() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - - Map? settings = await channel?.invokeMethod( - 'getSettings', - args, - ); - if (settings != null) { - settings = settings.cast(); - return InAppBrowserClassSettings.fromMap( - settings as Map, - ); - } - - return null; - } - - @override - bool isOpened() { - return this._isOpened; - } - - @override - @mustCallSuper - void dispose() { - super.dispose(); - disposeChannel(); - _webViewController?.dispose(); - _webViewController = null; - pullToRefreshController?.dispose(); - findInteractionController?.dispose(); - } -} - -extension InternalInAppBrowser on AndroidInAppBrowser { - void setContextMenu(ContextMenu? contextMenu) { - _contextMenu = contextMenu; - } -} diff --git a/flutter_inappwebview_android/lib/src/in_app_browser/main.dart b/flutter_inappwebview_android/lib/src/in_app_browser/main.dart deleted file mode 100644 index e11eb8b182..0000000000 --- a/flutter_inappwebview_android/lib/src/in_app_browser/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'in_app_browser.dart' hide InternalInAppBrowser; diff --git a/flutter_inappwebview_android/lib/src/in_app_webview/_static_channel.dart b/flutter_inappwebview_android/lib/src/in_app_webview/_static_channel.dart deleted file mode 100644 index a02f01ece1..0000000000 --- a/flutter_inappwebview_android/lib/src/in_app_webview/_static_channel.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:flutter/services.dart'; - -const IN_APP_WEBVIEW_STATIC_CHANNEL = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_manager', -); diff --git a/flutter_inappwebview_android/lib/src/in_app_webview/headless_in_app_webview.dart b/flutter_inappwebview_android/lib/src/in_app_webview/headless_in_app_webview.dart deleted file mode 100644 index 5bccad47f5..0000000000 --- a/flutter_inappwebview_android/lib/src/in_app_webview/headless_in_app_webview.dart +++ /dev/null @@ -1,470 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../find_interaction/find_interaction_controller.dart'; -import '../pull_to_refresh/pull_to_refresh_controller.dart'; -import 'in_app_webview_controller.dart'; - -/// Object specifying creation parameters for creating a [AndroidHeadlessInAppWebView]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformHeadlessInAppWebViewCreationParams] for -/// more information. -@immutable -class AndroidHeadlessInAppWebViewCreationParams - extends PlatformHeadlessInAppWebViewCreationParams { - /// Creates a new [AndroidHeadlessInAppWebViewCreationParams] instance. - AndroidHeadlessInAppWebViewCreationParams({ - super.controllerFromPlatform, - super.initialSize, - super.windowId, - super.onWebViewCreated, - super.onLoadStart, - super.onLoadStop, - @Deprecated('Use onReceivedError instead') super.onLoadError, - super.onReceivedError, - @Deprecated("Use onReceivedHttpError instead") super.onLoadHttpError, - super.onReceivedHttpError, - super.onProgressChanged, - super.onConsoleMessage, - super.shouldOverrideUrlLoading, - super.onLoadResource, - super.onScrollChanged, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStart, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStartRequest, - super.onDownloadStarting, - @Deprecated('Use onLoadResourceWithCustomScheme instead') - super.onLoadResourceCustomScheme, - super.onLoadResourceWithCustomScheme, - super.onCreateWindow, - super.onCloseWindow, - super.onJsAlert, - super.onJsConfirm, - super.onJsPrompt, - super.onReceivedHttpAuthRequest, - super.onReceivedServerTrustAuthRequest, - super.onReceivedClientCertRequest, - @Deprecated('Use FindInteractionController.onFindResultReceived instead') - super.onFindResultReceived, - super.shouldInterceptAjaxRequest, - super.onAjaxReadyStateChange, - super.onAjaxProgress, - super.shouldInterceptFetchRequest, - super.onUpdateVisitedHistory, - @Deprecated("Use onPrintRequest instead") super.onPrint, - super.onPrintRequest, - super.onLongPressHitTestResult, - super.onEnterFullscreen, - super.onExitFullscreen, - super.onPageCommitVisible, - super.onTitleChanged, - super.onWindowFocus, - super.onWindowBlur, - super.onOverScrolled, - super.onZoomScaleChanged, - @Deprecated('Use onSafeBrowsingHit instead') super.androidOnSafeBrowsingHit, - super.onSafeBrowsingHit, - @Deprecated('Use onPermissionRequest instead') - super.androidOnPermissionRequest, - super.onPermissionRequest, - @Deprecated('Use onGeolocationPermissionsShowPrompt instead') - super.androidOnGeolocationPermissionsShowPrompt, - super.onGeolocationPermissionsShowPrompt, - @Deprecated('Use onGeolocationPermissionsHidePrompt instead') - super.androidOnGeolocationPermissionsHidePrompt, - super.onGeolocationPermissionsHidePrompt, - @Deprecated('Use shouldInterceptRequest instead') - super.androidShouldInterceptRequest, - super.shouldInterceptRequest, - @Deprecated('Use onRenderProcessGone instead') - super.androidOnRenderProcessGone, - super.onRenderProcessGone, - @Deprecated('Use onRenderProcessResponsive instead') - super.androidOnRenderProcessResponsive, - super.onRenderProcessResponsive, - @Deprecated('Use onRenderProcessUnresponsive instead') - super.androidOnRenderProcessUnresponsive, - super.onRenderProcessUnresponsive, - @Deprecated('Use onFormResubmission instead') - super.androidOnFormResubmission, - super.onFormResubmission, - @Deprecated('Use onZoomScaleChanged instead') super.androidOnScaleChanged, - @Deprecated('Use onReceivedIcon instead') super.androidOnReceivedIcon, - super.onReceivedIcon, - @Deprecated('Use onReceivedTouchIconUrl instead') - super.androidOnReceivedTouchIconUrl, - super.onReceivedTouchIconUrl, - @Deprecated('Use onJsBeforeUnload instead') super.androidOnJsBeforeUnload, - super.onJsBeforeUnload, - @Deprecated('Use onReceivedLoginRequest instead') - super.androidOnReceivedLoginRequest, - super.onReceivedLoginRequest, - super.onPermissionRequestCanceled, - super.onRequestFocus, - @Deprecated('Use onWebContentProcessDidTerminate instead') - super.iosOnWebContentProcessDidTerminate, - super.onWebContentProcessDidTerminate, - @Deprecated( - 'Use onDidReceiveServerRedirectForProvisionalNavigation instead', - ) - super.iosOnDidReceiveServerRedirectForProvisionalNavigation, - super.onDidReceiveServerRedirectForProvisionalNavigation, - @Deprecated('Use onNavigationResponse instead') - super.iosOnNavigationResponse, - super.onNavigationResponse, - @Deprecated('Use shouldAllowDeprecatedTLS instead') - super.iosShouldAllowDeprecatedTLS, - super.shouldAllowDeprecatedTLS, - super.onCameraCaptureStateChanged, - super.onMicrophoneCaptureStateChanged, - super.onContentSizeChanged, - super.initialUrlRequest, - super.initialFile, - super.initialData, - @Deprecated('Use initialSettings instead') super.initialOptions, - super.initialSettings, - super.contextMenu, - super.initialUserScripts, - this.pullToRefreshController, - this.findInteractionController, - }); - - /// Creates a [AndroidHeadlessInAppWebViewCreationParams] instance based on [PlatformHeadlessInAppWebViewCreationParams]. - AndroidHeadlessInAppWebViewCreationParams.fromPlatformHeadlessInAppWebViewCreationParams( - PlatformHeadlessInAppWebViewCreationParams params, - ) : this( - controllerFromPlatform: params.controllerFromPlatform, - initialSize: params.initialSize, - windowId: params.windowId, - onWebViewCreated: params.onWebViewCreated, - onLoadStart: params.onLoadStart, - onLoadStop: params.onLoadStop, - onLoadError: params.onLoadError, - onReceivedError: params.onReceivedError, - onLoadHttpError: params.onLoadHttpError, - onReceivedHttpError: params.onReceivedHttpError, - onProgressChanged: params.onProgressChanged, - onConsoleMessage: params.onConsoleMessage, - shouldOverrideUrlLoading: params.shouldOverrideUrlLoading, - onLoadResource: params.onLoadResource, - onScrollChanged: params.onScrollChanged, - onDownloadStart: params.onDownloadStart, - onDownloadStartRequest: params.onDownloadStartRequest, - onDownloadStarting: params.onDownloadStarting, - onLoadResourceCustomScheme: params.onLoadResourceCustomScheme, - onLoadResourceWithCustomScheme: params.onLoadResourceWithCustomScheme, - onCreateWindow: params.onCreateWindow, - onCloseWindow: params.onCloseWindow, - onJsAlert: params.onJsAlert, - onJsConfirm: params.onJsConfirm, - onJsPrompt: params.onJsPrompt, - onReceivedHttpAuthRequest: params.onReceivedHttpAuthRequest, - onReceivedServerTrustAuthRequest: - params.onReceivedServerTrustAuthRequest, - onReceivedClientCertRequest: params.onReceivedClientCertRequest, - onFindResultReceived: params.onFindResultReceived, - shouldInterceptAjaxRequest: params.shouldInterceptAjaxRequest, - onAjaxReadyStateChange: params.onAjaxReadyStateChange, - onAjaxProgress: params.onAjaxProgress, - shouldInterceptFetchRequest: params.shouldInterceptFetchRequest, - onUpdateVisitedHistory: params.onUpdateVisitedHistory, - onPrint: params.onPrint, - onPrintRequest: params.onPrintRequest, - onLongPressHitTestResult: params.onLongPressHitTestResult, - onEnterFullscreen: params.onEnterFullscreen, - onExitFullscreen: params.onExitFullscreen, - onPageCommitVisible: params.onPageCommitVisible, - onTitleChanged: params.onTitleChanged, - onWindowFocus: params.onWindowFocus, - onWindowBlur: params.onWindowBlur, - onOverScrolled: params.onOverScrolled, - onZoomScaleChanged: params.onZoomScaleChanged, - androidOnSafeBrowsingHit: params.androidOnSafeBrowsingHit, - onSafeBrowsingHit: params.onSafeBrowsingHit, - androidOnPermissionRequest: params.androidOnPermissionRequest, - onPermissionRequest: params.onPermissionRequest, - androidOnGeolocationPermissionsShowPrompt: - params.androidOnGeolocationPermissionsShowPrompt, - onGeolocationPermissionsShowPrompt: - params.onGeolocationPermissionsShowPrompt, - androidOnGeolocationPermissionsHidePrompt: - params.androidOnGeolocationPermissionsHidePrompt, - onGeolocationPermissionsHidePrompt: - params.onGeolocationPermissionsHidePrompt, - androidShouldInterceptRequest: params.androidShouldInterceptRequest, - shouldInterceptRequest: params.shouldInterceptRequest, - androidOnRenderProcessGone: params.androidOnRenderProcessGone, - onRenderProcessGone: params.onRenderProcessGone, - androidOnRenderProcessResponsive: - params.androidOnRenderProcessResponsive, - onRenderProcessResponsive: params.onRenderProcessResponsive, - androidOnRenderProcessUnresponsive: - params.androidOnRenderProcessUnresponsive, - onRenderProcessUnresponsive: params.onRenderProcessUnresponsive, - androidOnFormResubmission: params.androidOnFormResubmission, - onFormResubmission: params.onFormResubmission, - androidOnScaleChanged: params.androidOnScaleChanged, - androidOnReceivedIcon: params.androidOnReceivedIcon, - onReceivedIcon: params.onReceivedIcon, - androidOnReceivedTouchIconUrl: params.androidOnReceivedTouchIconUrl, - onReceivedTouchIconUrl: params.onReceivedTouchIconUrl, - androidOnJsBeforeUnload: params.androidOnJsBeforeUnload, - onJsBeforeUnload: params.onJsBeforeUnload, - androidOnReceivedLoginRequest: params.androidOnReceivedLoginRequest, - onReceivedLoginRequest: params.onReceivedLoginRequest, - onPermissionRequestCanceled: params.onPermissionRequestCanceled, - onRequestFocus: params.onRequestFocus, - iosOnWebContentProcessDidTerminate: - params.iosOnWebContentProcessDidTerminate, - onWebContentProcessDidTerminate: params.onWebContentProcessDidTerminate, - iosOnDidReceiveServerRedirectForProvisionalNavigation: - params.iosOnDidReceiveServerRedirectForProvisionalNavigation, - onDidReceiveServerRedirectForProvisionalNavigation: - params.onDidReceiveServerRedirectForProvisionalNavigation, - iosOnNavigationResponse: params.iosOnNavigationResponse, - onNavigationResponse: params.onNavigationResponse, - iosShouldAllowDeprecatedTLS: params.iosShouldAllowDeprecatedTLS, - shouldAllowDeprecatedTLS: params.shouldAllowDeprecatedTLS, - onCameraCaptureStateChanged: params.onCameraCaptureStateChanged, - onMicrophoneCaptureStateChanged: params.onMicrophoneCaptureStateChanged, - onContentSizeChanged: params.onContentSizeChanged, - initialUrlRequest: params.initialUrlRequest, - initialFile: params.initialFile, - initialData: params.initialData, - initialOptions: params.initialOptions, - initialSettings: params.initialSettings, - contextMenu: params.contextMenu, - initialUserScripts: params.initialUserScripts, - pullToRefreshController: - params.pullToRefreshController as AndroidPullToRefreshController?, - findInteractionController: - params.findInteractionController - as AndroidFindInteractionController?, - ); - - @override - final AndroidFindInteractionController? findInteractionController; - - @override - final AndroidPullToRefreshController? pullToRefreshController; -} - -///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView} -class AndroidHeadlessInAppWebView extends PlatformHeadlessInAppWebView - with ChannelController { - @override - late final String id; - - bool _started = false; - bool _running = false; - - static const MethodChannel _sharedChannel = const MethodChannel( - 'com.pichillilorenzo/flutter_headless_inappwebview', - ); - - AndroidInAppWebViewController? _webViewController; - - /// Constructs a [AndroidHeadlessInAppWebView]. - AndroidHeadlessInAppWebView(PlatformHeadlessInAppWebViewCreationParams params) - : super.implementation( - params is AndroidHeadlessInAppWebViewCreationParams - ? params - : AndroidHeadlessInAppWebViewCreationParams.fromPlatformHeadlessInAppWebViewCreationParams( - params, - ), - ) { - id = IdGenerator.generate(); - } - - static final AndroidHeadlessInAppWebView _staticValue = - AndroidHeadlessInAppWebView(AndroidHeadlessInAppWebViewCreationParams()); - - factory AndroidHeadlessInAppWebView.static() { - return _staticValue; - } - - @override - AndroidInAppWebViewController? get webViewController => _webViewController; - - dynamic _controllerFromPlatform; - - AndroidHeadlessInAppWebViewCreationParams get _androidParams => - params as AndroidHeadlessInAppWebViewCreationParams; - - _init() { - _webViewController = AndroidInAppWebViewController( - AndroidInAppWebViewControllerCreationParams( - id: id, - webviewParams: params, - ), - ); - _controllerFromPlatform = - params.controllerFromPlatform?.call(_webViewController!) ?? - _webViewController!; - _androidParams.pullToRefreshController?.init(id); - _androidParams.findInteractionController?.init(id); - channel = MethodChannel( - 'com.pichillilorenzo/flutter_headless_inappwebview_$id', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onWebViewCreated": - if (params.onWebViewCreated != null && _webViewController != null) { - params.onWebViewCreated!(_controllerFromPlatform); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - Future run() async { - if (_started) { - return; - } - _started = true; - _init(); - - final initialSettings = params.initialSettings ?? InAppWebViewSettings(); - _inferInitialSettings(initialSettings); - - Map settingsMap = - (params.initialSettings != null ? initialSettings.toMap() : null) ?? - params.initialOptions?.toMap() ?? - initialSettings.toMap(); - - Map pullToRefreshSettings = - _androidParams.pullToRefreshController?.params.settings.toMap() ?? - _androidParams.pullToRefreshController?.params.options.toMap() ?? - PullToRefreshSettings(enabled: false).toMap(); - - Map args = {}; - args.putIfAbsent('id', () => id); - args.putIfAbsent( - 'params', - () => { - 'initialUrlRequest': params.initialUrlRequest?.toMap(), - 'initialFile': params.initialFile, - 'initialData': params.initialData?.toMap(), - 'initialSettings': settingsMap, - 'contextMenu': params.contextMenu?.toMap() ?? {}, - 'windowId': params.windowId, - 'initialUserScripts': - params.initialUserScripts?.map((e) => e.toMap()).toList() ?? [], - 'pullToRefreshSettings': pullToRefreshSettings, - 'initialSize': params.initialSize.toMap(), - }, - ); - await _sharedChannel.invokeMethod('run', args); - _running = true; - } - - void _inferInitialSettings(InAppWebViewSettings settings) { - if (params.shouldOverrideUrlLoading != null && - settings.useShouldOverrideUrlLoading == null) { - settings.useShouldOverrideUrlLoading = true; - } - if (params.onLoadResource != null && settings.useOnLoadResource == null) { - settings.useOnLoadResource = true; - } - if ((params.onDownloadStartRequest != null || - params.onDownloadStarting != null) && - settings.useOnDownloadStart == null) { - settings.useOnDownloadStart = true; - } - if ((params.shouldInterceptAjaxRequest != null || - params.onAjaxProgress != null || - params.onAjaxReadyStateChange != null)) { - if (settings.useShouldInterceptAjaxRequest == null) { - settings.useShouldInterceptAjaxRequest = true; - } - if (params.onAjaxReadyStateChange != null && - settings.useOnAjaxReadyStateChange == null) { - settings.useOnAjaxReadyStateChange = true; - } - if (params.onAjaxProgress != null && settings.useOnAjaxProgress == null) { - settings.useOnAjaxProgress = true; - } - } - if (params.shouldInterceptFetchRequest != null && - settings.useShouldInterceptFetchRequest == null) { - settings.useShouldInterceptFetchRequest = true; - } - if (params.shouldInterceptRequest != null && - settings.useShouldInterceptRequest == null) { - settings.useShouldInterceptRequest = true; - } - if (params.onRenderProcessGone != null && - settings.useOnRenderProcessGone == null) { - settings.useOnRenderProcessGone = true; - } - if (params.onNavigationResponse != null && - settings.useOnNavigationResponse == null) { - settings.useOnNavigationResponse = true; - } - if (params.onShowFileChooser != null && - settings.useOnShowFileChooser == null) { - settings.useOnShowFileChooser = true; - } - } - - @override - bool isRunning() { - return _running; - } - - @override - Future setSize(Size size) async { - if (!_running) { - return; - } - - Map args = {}; - args.putIfAbsent('size', () => size.toMap()); - await channel?.invokeMethod('setSize', args); - } - - @override - Future getSize() async { - if (!_running) { - return null; - } - - Map args = {}; - Map sizeMap = (await channel?.invokeMethod( - 'getSize', - args, - ))?.cast(); - return MapSize.fromMap(sizeMap); - } - - @override - Future dispose() async { - if (!_running) { - return; - } - Map args = {}; - await channel?.invokeMethod('dispose', args); - disposeChannel(); - _started = false; - _running = false; - _webViewController?.dispose(); - _webViewController = null; - _controllerFromPlatform = null; - _androidParams.pullToRefreshController?.dispose(); - _androidParams.findInteractionController?.dispose(); - } -} - -extension InternalHeadlessInAppWebView on AndroidHeadlessInAppWebView { - Future internalDispose() async { - _started = false; - _running = false; - } -} diff --git a/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview.dart b/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview.dart deleted file mode 100755 index d23fd9c5e5..0000000000 --- a/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview.dart +++ /dev/null @@ -1,503 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../find_interaction/find_interaction_controller.dart'; -import '../pull_to_refresh/pull_to_refresh_controller.dart'; -import 'headless_in_app_webview.dart'; -import 'in_app_webview_controller.dart'; - -/// Object specifying creation parameters for creating a [PlatformInAppWebViewWidget]. -/// -/// Platform specific implementations can add additional fields by extending -/// this class. -class AndroidInAppWebViewWidgetCreationParams - extends PlatformInAppWebViewWidgetCreationParams { - AndroidInAppWebViewWidgetCreationParams({ - super.controllerFromPlatform, - super.key, - super.layoutDirection, - super.gestureRecognizers, - super.headlessWebView, - super.keepAlive, - super.preventGestureDelay, - super.windowId, - super.onWebViewCreated, - super.onLoadStart, - super.onLoadStop, - @Deprecated('Use onReceivedError instead') super.onLoadError, - super.onReceivedError, - @Deprecated("Use onReceivedHttpError instead") super.onLoadHttpError, - super.onReceivedHttpError, - super.onProgressChanged, - super.onConsoleMessage, - super.shouldOverrideUrlLoading, - super.onLoadResource, - super.onScrollChanged, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStart, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStartRequest, - super.onDownloadStarting, - @Deprecated('Use onLoadResourceWithCustomScheme instead') - super.onLoadResourceCustomScheme, - super.onLoadResourceWithCustomScheme, - super.onCreateWindow, - super.onCloseWindow, - super.onJsAlert, - super.onJsConfirm, - super.onJsPrompt, - super.onReceivedHttpAuthRequest, - super.onReceivedServerTrustAuthRequest, - super.onReceivedClientCertRequest, - @Deprecated('Use FindInteractionController.onFindResultReceived instead') - super.onFindResultReceived, - super.shouldInterceptAjaxRequest, - super.onAjaxReadyStateChange, - super.onAjaxProgress, - super.shouldInterceptFetchRequest, - super.onUpdateVisitedHistory, - @Deprecated("Use onPrintRequest instead") super.onPrint, - super.onPrintRequest, - super.onLongPressHitTestResult, - super.onEnterFullscreen, - super.onExitFullscreen, - super.onPageCommitVisible, - super.onTitleChanged, - super.onWindowFocus, - super.onWindowBlur, - super.onOverScrolled, - super.onZoomScaleChanged, - @Deprecated('Use onSafeBrowsingHit instead') super.androidOnSafeBrowsingHit, - super.onSafeBrowsingHit, - @Deprecated('Use onPermissionRequest instead') - super.androidOnPermissionRequest, - super.onPermissionRequest, - @Deprecated('Use onGeolocationPermissionsShowPrompt instead') - super.androidOnGeolocationPermissionsShowPrompt, - super.onGeolocationPermissionsShowPrompt, - @Deprecated('Use onGeolocationPermissionsHidePrompt instead') - super.androidOnGeolocationPermissionsHidePrompt, - super.onGeolocationPermissionsHidePrompt, - @Deprecated('Use shouldInterceptRequest instead') - super.androidShouldInterceptRequest, - super.shouldInterceptRequest, - @Deprecated('Use onRenderProcessGone instead') - super.androidOnRenderProcessGone, - super.onRenderProcessGone, - @Deprecated('Use onRenderProcessResponsive instead') - super.androidOnRenderProcessResponsive, - super.onRenderProcessResponsive, - @Deprecated('Use onRenderProcessUnresponsive instead') - super.androidOnRenderProcessUnresponsive, - super.onRenderProcessUnresponsive, - @Deprecated('Use onFormResubmission instead') - super.androidOnFormResubmission, - super.onFormResubmission, - @Deprecated('Use onZoomScaleChanged instead') super.androidOnScaleChanged, - @Deprecated('Use onReceivedIcon instead') super.androidOnReceivedIcon, - super.onReceivedIcon, - @Deprecated('Use onReceivedTouchIconUrl instead') - super.androidOnReceivedTouchIconUrl, - super.onReceivedTouchIconUrl, - @Deprecated('Use onJsBeforeUnload instead') super.androidOnJsBeforeUnload, - super.onJsBeforeUnload, - @Deprecated('Use onReceivedLoginRequest instead') - super.androidOnReceivedLoginRequest, - super.onReceivedLoginRequest, - super.onPermissionRequestCanceled, - super.onRequestFocus, - @Deprecated('Use onWebContentProcessDidTerminate instead') - super.iosOnWebContentProcessDidTerminate, - super.onWebContentProcessDidTerminate, - @Deprecated( - 'Use onDidReceiveServerRedirectForProvisionalNavigation instead', - ) - super.iosOnDidReceiveServerRedirectForProvisionalNavigation, - super.onDidReceiveServerRedirectForProvisionalNavigation, - @Deprecated('Use onNavigationResponse instead') - super.iosOnNavigationResponse, - super.onNavigationResponse, - @Deprecated('Use shouldAllowDeprecatedTLS instead') - super.iosShouldAllowDeprecatedTLS, - super.shouldAllowDeprecatedTLS, - super.onCameraCaptureStateChanged, - super.onMicrophoneCaptureStateChanged, - super.onContentSizeChanged, - super.onShowFileChooser, - super.initialUrlRequest, - super.initialFile, - super.initialData, - @Deprecated('Use initialSettings instead') super.initialOptions, - super.initialSettings, - super.contextMenu, - super.initialUserScripts, - this.pullToRefreshController, - this.findInteractionController, - }); - - /// Constructs a [AndroidInAppWebViewWidgetCreationParams] using a - /// [PlatformInAppWebViewWidgetCreationParams]. - AndroidInAppWebViewWidgetCreationParams.fromPlatformInAppWebViewWidgetCreationParams( - PlatformInAppWebViewWidgetCreationParams params, - ) : this( - controllerFromPlatform: params.controllerFromPlatform, - key: params.key, - layoutDirection: params.layoutDirection, - gestureRecognizers: params.gestureRecognizers, - headlessWebView: params.headlessWebView, - keepAlive: params.keepAlive, - preventGestureDelay: params.preventGestureDelay, - windowId: params.windowId, - onWebViewCreated: params.onWebViewCreated, - onLoadStart: params.onLoadStart, - onLoadStop: params.onLoadStop, - onLoadError: params.onLoadError, - onReceivedError: params.onReceivedError, - onLoadHttpError: params.onLoadHttpError, - onReceivedHttpError: params.onReceivedHttpError, - onProgressChanged: params.onProgressChanged, - onConsoleMessage: params.onConsoleMessage, - shouldOverrideUrlLoading: params.shouldOverrideUrlLoading, - onLoadResource: params.onLoadResource, - onScrollChanged: params.onScrollChanged, - onDownloadStart: params.onDownloadStart, - onDownloadStartRequest: params.onDownloadStartRequest, - onDownloadStarting: params.onDownloadStarting, - onLoadResourceCustomScheme: params.onLoadResourceCustomScheme, - onLoadResourceWithCustomScheme: params.onLoadResourceWithCustomScheme, - onCreateWindow: params.onCreateWindow, - onCloseWindow: params.onCloseWindow, - onJsAlert: params.onJsAlert, - onJsConfirm: params.onJsConfirm, - onJsPrompt: params.onJsPrompt, - onReceivedHttpAuthRequest: params.onReceivedHttpAuthRequest, - onReceivedServerTrustAuthRequest: - params.onReceivedServerTrustAuthRequest, - onReceivedClientCertRequest: params.onReceivedClientCertRequest, - onFindResultReceived: params.onFindResultReceived, - shouldInterceptAjaxRequest: params.shouldInterceptAjaxRequest, - onAjaxReadyStateChange: params.onAjaxReadyStateChange, - onAjaxProgress: params.onAjaxProgress, - shouldInterceptFetchRequest: params.shouldInterceptFetchRequest, - onUpdateVisitedHistory: params.onUpdateVisitedHistory, - onPrint: params.onPrint, - onPrintRequest: params.onPrintRequest, - onLongPressHitTestResult: params.onLongPressHitTestResult, - onEnterFullscreen: params.onEnterFullscreen, - onExitFullscreen: params.onExitFullscreen, - onPageCommitVisible: params.onPageCommitVisible, - onTitleChanged: params.onTitleChanged, - onWindowFocus: params.onWindowFocus, - onWindowBlur: params.onWindowBlur, - onOverScrolled: params.onOverScrolled, - onZoomScaleChanged: params.onZoomScaleChanged, - androidOnSafeBrowsingHit: params.androidOnSafeBrowsingHit, - onSafeBrowsingHit: params.onSafeBrowsingHit, - androidOnPermissionRequest: params.androidOnPermissionRequest, - onPermissionRequest: params.onPermissionRequest, - androidOnGeolocationPermissionsShowPrompt: - params.androidOnGeolocationPermissionsShowPrompt, - onGeolocationPermissionsShowPrompt: - params.onGeolocationPermissionsShowPrompt, - androidOnGeolocationPermissionsHidePrompt: - params.androidOnGeolocationPermissionsHidePrompt, - onGeolocationPermissionsHidePrompt: - params.onGeolocationPermissionsHidePrompt, - androidShouldInterceptRequest: params.androidShouldInterceptRequest, - shouldInterceptRequest: params.shouldInterceptRequest, - androidOnRenderProcessGone: params.androidOnRenderProcessGone, - onRenderProcessGone: params.onRenderProcessGone, - androidOnRenderProcessResponsive: - params.androidOnRenderProcessResponsive, - onRenderProcessResponsive: params.onRenderProcessResponsive, - androidOnRenderProcessUnresponsive: - params.androidOnRenderProcessUnresponsive, - onRenderProcessUnresponsive: params.onRenderProcessUnresponsive, - androidOnFormResubmission: params.androidOnFormResubmission, - onFormResubmission: params.onFormResubmission, - androidOnScaleChanged: params.androidOnScaleChanged, - androidOnReceivedIcon: params.androidOnReceivedIcon, - onReceivedIcon: params.onReceivedIcon, - androidOnReceivedTouchIconUrl: params.androidOnReceivedTouchIconUrl, - onReceivedTouchIconUrl: params.onReceivedTouchIconUrl, - androidOnJsBeforeUnload: params.androidOnJsBeforeUnload, - onJsBeforeUnload: params.onJsBeforeUnload, - androidOnReceivedLoginRequest: params.androidOnReceivedLoginRequest, - onReceivedLoginRequest: params.onReceivedLoginRequest, - onPermissionRequestCanceled: params.onPermissionRequestCanceled, - onRequestFocus: params.onRequestFocus, - iosOnWebContentProcessDidTerminate: - params.iosOnWebContentProcessDidTerminate, - onWebContentProcessDidTerminate: params.onWebContentProcessDidTerminate, - iosOnDidReceiveServerRedirectForProvisionalNavigation: - params.iosOnDidReceiveServerRedirectForProvisionalNavigation, - onDidReceiveServerRedirectForProvisionalNavigation: - params.onDidReceiveServerRedirectForProvisionalNavigation, - iosOnNavigationResponse: params.iosOnNavigationResponse, - onNavigationResponse: params.onNavigationResponse, - iosShouldAllowDeprecatedTLS: params.iosShouldAllowDeprecatedTLS, - shouldAllowDeprecatedTLS: params.shouldAllowDeprecatedTLS, - onCameraCaptureStateChanged: params.onCameraCaptureStateChanged, - onMicrophoneCaptureStateChanged: params.onMicrophoneCaptureStateChanged, - onContentSizeChanged: params.onContentSizeChanged, - onShowFileChooser: params.onShowFileChooser, - initialUrlRequest: params.initialUrlRequest, - initialFile: params.initialFile, - initialData: params.initialData, - initialOptions: params.initialOptions, - initialSettings: params.initialSettings, - contextMenu: params.contextMenu, - initialUserScripts: params.initialUserScripts, - pullToRefreshController: - params.pullToRefreshController as AndroidPullToRefreshController?, - findInteractionController: - params.findInteractionController - as AndroidFindInteractionController?, - ); - - @override - final AndroidFindInteractionController? findInteractionController; - - @override - final AndroidPullToRefreshController? pullToRefreshController; -} - -///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewWidget} -class AndroidInAppWebViewWidget extends PlatformInAppWebViewWidget { - /// Constructs a [AndroidInAppWebViewWidget]. - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewWidget} - AndroidInAppWebViewWidget(PlatformInAppWebViewWidgetCreationParams params) - : super.implementation( - params is AndroidInAppWebViewWidgetCreationParams - ? params - : AndroidInAppWebViewWidgetCreationParams.fromPlatformInAppWebViewWidgetCreationParams( - params, - ), - ); - - AndroidInAppWebViewWidgetCreationParams get _androidParams => - params as AndroidInAppWebViewWidgetCreationParams; - - AndroidInAppWebViewController? _controller; - - AndroidHeadlessInAppWebView? get _androidHeadlessInAppWebView => - params.headlessWebView as AndroidHeadlessInAppWebView?; - - static final AndroidInAppWebViewWidget _staticValue = - AndroidInAppWebViewWidget(AndroidInAppWebViewWidgetCreationParams()); - - factory AndroidInAppWebViewWidget.static() { - return _staticValue; - } - - @override - Widget build(BuildContext context) { - final initialSettings = params.initialSettings ?? InAppWebViewSettings(); - _inferInitialSettings(initialSettings); - - Map settingsMap = - (params.initialSettings != null ? initialSettings.toMap() : null) ?? - // ignore: deprecated_member_use_from_same_package - params.initialOptions?.toMap() ?? - initialSettings.toMap(); - - Map pullToRefreshSettings = - params.pullToRefreshController?.params.settings.toMap() ?? - // ignore: deprecated_member_use_from_same_package - params.pullToRefreshController?.params.options.toMap() ?? - PullToRefreshSettings(enabled: false).toMap(); - - if ((params.headlessWebView?.isRunning() ?? false) && - params.keepAlive != null) { - final headlessId = params.headlessWebView?.id; - if (headlessId != null) { - // force keep alive id to match headless webview id - params.keepAlive?.id = headlessId; - } - } - - var useHybridComposition = - (params.initialSettings != null - ? initialSettings.useHybridComposition - : params.initialOptions?.android.useHybridComposition) ?? - true; - - return PlatformViewLink( - key: params.key, - viewType: 'com.pichillilorenzo/flutter_inappwebview', - surfaceFactory: - (BuildContext context, PlatformViewController controller) { - return AndroidViewSurface( - controller: controller as AndroidViewController, - gestureRecognizers: - params.gestureRecognizers ?? - const >{}, - hitTestBehavior: PlatformViewHitTestBehavior.opaque, - ); - }, - onCreatePlatformView: (PlatformViewCreationParams params) { - return _createAndroidViewController( - hybridComposition: useHybridComposition, - id: params.id, - viewType: 'com.pichillilorenzo/flutter_inappwebview', - layoutDirection: - this.params.layoutDirection ?? - Directionality.maybeOf(context) ?? - TextDirection.rtl, - creationParams: { - 'initialUrlRequest': this.params.initialUrlRequest?.toMap(), - 'initialFile': this.params.initialFile, - 'initialData': this.params.initialData?.toMap(), - 'initialSettings': settingsMap, - 'contextMenu': this.params.contextMenu?.toMap() ?? {}, - 'windowId': this.params.windowId, - 'headlessWebViewId': - this.params.headlessWebView?.isRunning() ?? false - ? this.params.headlessWebView?.id - : null, - 'initialUserScripts': - this.params.initialUserScripts - ?.map((e) => e.toMap()) - .toList() ?? - [], - 'pullToRefreshSettings': pullToRefreshSettings, - 'keepAliveId': this.params.keepAlive?.id, - }, - ) - ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) - ..addOnPlatformViewCreatedListener((id) => _onPlatformViewCreated(id)) - ..create(); - }, - ); - } - - AndroidViewController _createAndroidViewController({ - required bool hybridComposition, - required int id, - required String viewType, - required TextDirection layoutDirection, - required Map creationParams, - }) { - if (hybridComposition) { - return PlatformViewsService.initExpensiveAndroidView( - id: id, - viewType: viewType, - layoutDirection: layoutDirection, - creationParams: creationParams, - creationParamsCodec: const StandardMessageCodec(), - ); - } - return PlatformViewsService.initSurfaceAndroidView( - id: id, - viewType: viewType, - layoutDirection: layoutDirection, - creationParams: creationParams, - creationParamsCodec: const StandardMessageCodec(), - ); - } - - void _onPlatformViewCreated(int id) { - dynamic viewId = id; - if (params.headlessWebView?.isRunning() ?? false) { - viewId = params.headlessWebView?.id; - } - viewId = params.keepAlive?.id ?? viewId ?? id; - _androidHeadlessInAppWebView?.internalDispose(); - _controller = AndroidInAppWebViewController( - PlatformInAppWebViewControllerCreationParams( - id: viewId, - webviewParams: params, - ), - ); - _androidParams.pullToRefreshController?.init(viewId); - _androidParams.findInteractionController?.init(viewId); - debugLog( - className: runtimeType.toString(), - id: viewId?.toString(), - debugLoggingSettings: PlatformInAppWebViewController.debugLoggingSettings, - method: "onWebViewCreated", - args: [], - ); - if (params.onWebViewCreated != null) { - params.onWebViewCreated!( - params.controllerFromPlatform?.call(_controller!) ?? _controller!, - ); - } - } - - void _inferInitialSettings(InAppWebViewSettings settings) { - if (params.shouldOverrideUrlLoading != null && - settings.useShouldOverrideUrlLoading == null) { - settings.useShouldOverrideUrlLoading = true; - } - if (params.onLoadResource != null && settings.useOnLoadResource == null) { - settings.useOnLoadResource = true; - } - if ((params.onDownloadStartRequest != null || - params.onDownloadStarting != null) && - settings.useOnDownloadStart == null) { - settings.useOnDownloadStart = true; - } - if ((params.shouldInterceptAjaxRequest != null || - params.onAjaxProgress != null || - params.onAjaxReadyStateChange != null)) { - if (settings.useShouldInterceptAjaxRequest == null) { - settings.useShouldInterceptAjaxRequest = true; - } - if (params.onAjaxReadyStateChange != null && - settings.useOnAjaxReadyStateChange == null) { - settings.useOnAjaxReadyStateChange = true; - } - if (params.onAjaxProgress != null && settings.useOnAjaxProgress == null) { - settings.useOnAjaxProgress = true; - } - } - if (params.shouldInterceptFetchRequest != null && - settings.useShouldInterceptFetchRequest == null) { - settings.useShouldInterceptFetchRequest = true; - } - if (params.shouldInterceptRequest != null && - settings.useShouldInterceptRequest == null) { - settings.useShouldInterceptRequest = true; - } - if (params.onRenderProcessGone != null && - settings.useOnRenderProcessGone == null) { - settings.useOnRenderProcessGone = true; - } - if (params.onNavigationResponse != null && - settings.useOnNavigationResponse == null) { - settings.useOnNavigationResponse = true; - } - if (params.onShowFileChooser != null && - settings.useOnShowFileChooser == null) { - settings.useOnShowFileChooser = true; - } - } - - @override - void dispose() { - dynamic viewId = _controller?.getViewId(); - debugLog( - className: runtimeType.toString(), - id: viewId?.toString(), - debugLoggingSettings: PlatformInAppWebViewController.debugLoggingSettings, - method: "dispose", - args: [], - ); - final isKeepAlive = params.keepAlive != null; - _controller?.dispose(isKeepAlive: isKeepAlive); - _controller = null; - params.pullToRefreshController?.dispose(isKeepAlive: isKeepAlive); - params.findInteractionController?.dispose(isKeepAlive: isKeepAlive); - } - - @override - T controllerFromPlatform(PlatformInAppWebViewController controller) { - // unused - throw UnimplementedError(); - } -} diff --git a/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart deleted file mode 100644 index ec10256857..0000000000 --- a/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart +++ /dev/null @@ -1,3231 +0,0 @@ -import 'dart:collection'; -import 'dart:convert'; -import 'dart:core'; -import 'dart:developer' as developer; -import 'dart:io'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../in_app_browser/in_app_browser.dart'; -import '../print_job/main.dart'; -import '../web_message/main.dart'; -import '../web_storage/web_storage.dart'; -import '_static_channel.dart'; -import 'headless_in_app_webview.dart'; - -/// Object specifying creation parameters for creating a [AndroidInAppWebViewController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformInAppWebViewControllerCreationParams] for -/// more information. -@immutable -class AndroidInAppWebViewControllerCreationParams - extends PlatformInAppWebViewControllerCreationParams { - /// Creates a new [AndroidInAppWebViewControllerCreationParams] instance. - const AndroidInAppWebViewControllerCreationParams({ - required super.id, - super.webviewParams, - }); - - /// Creates a [AndroidInAppWebViewControllerCreationParams] instance based on [PlatformInAppWebViewControllerCreationParams]. - factory AndroidInAppWebViewControllerCreationParams.fromPlatformInAppWebViewControllerCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformInAppWebViewControllerCreationParams params, - ) { - return AndroidInAppWebViewControllerCreationParams( - id: params.id, - webviewParams: params.webviewParams, - ); - } -} - -///Controls a WebView, such as an [InAppWebView] widget instance, a [AndroidHeadlessInAppWebView] instance or [AndroidInAppBrowser] WebView instance. -/// -///If you are using the [InAppWebView] widget, an [InAppWebViewController] instance can be obtained by setting the [InAppWebView.onWebViewCreated] -///callback. Instead, if you are using an [AndroidInAppBrowser] instance, you can get it through the [AndroidInAppBrowser.webViewController] attribute. -class AndroidInAppWebViewController extends PlatformInAppWebViewController - with ChannelController { - static final MethodChannel _staticChannel = IN_APP_WEBVIEW_STATIC_CHANNEL; - - // List of properties to be saved and restored for keep alive feature - Map _javaScriptHandlersMap = HashMap(); - Map> _userScripts = { - UserScriptInjectionTime.AT_DOCUMENT_START: [], - UserScriptInjectionTime.AT_DOCUMENT_END: [], - }; - Set _webMessageListenerObjNames = Set(); - Map _injectedScriptsFromURL = {}; - Set _webMessageChannels = Set(); - Set _webMessageListeners = Set(); - - // static map that contains the properties to be saved and restored for keep alive feature - static final Map - _keepAliveMap = {}; - - AndroidInAppBrowser? _inAppBrowser; - - PlatformInAppBrowserEvents? get _inAppBrowserEventHandler => - _inAppBrowser?.eventHandler; - - dynamic _controllerFromPlatform; - - @override - late AndroidWebStorage webStorage; - - AndroidInAppWebViewController( - PlatformInAppWebViewControllerCreationParams params, - ) : super.implementation( - params is AndroidInAppWebViewControllerCreationParams - ? params - : AndroidInAppWebViewControllerCreationParams.fromPlatformInAppWebViewControllerCreationParams( - params, - ), - ) { - channel = MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id'); - handler = handleMethod; - initMethodCallHandler(); - - final initialUserScripts = webviewParams?.initialUserScripts; - if (initialUserScripts != null) { - for (final userScript in initialUserScripts) { - if (userScript.injectionTime == - UserScriptInjectionTime.AT_DOCUMENT_START) { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.add( - userScript, - ); - } else { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.add( - userScript, - ); - } - } - } - - this._init(params); - } - - static final AndroidInAppWebViewController _staticValue = - AndroidInAppWebViewController( - AndroidInAppWebViewControllerCreationParams(id: null), - ); - - factory AndroidInAppWebViewController.static() { - return _staticValue; - } - - AndroidInAppWebViewController.fromInAppBrowser( - PlatformInAppWebViewControllerCreationParams params, - MethodChannel channel, - AndroidInAppBrowser inAppBrowser, - UnmodifiableListView? initialUserScripts, - ) : super.implementation( - params is AndroidInAppWebViewControllerCreationParams - ? params - : AndroidInAppWebViewControllerCreationParams.fromPlatformInAppWebViewControllerCreationParams( - params, - ), - ) { - this.channel = channel; - this._inAppBrowser = inAppBrowser; - - if (initialUserScripts != null) { - for (final userScript in initialUserScripts) { - if (userScript.injectionTime == - UserScriptInjectionTime.AT_DOCUMENT_START) { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.add( - userScript, - ); - } else { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.add( - userScript, - ); - } - } - } - this._init(params); - } - - void _init(PlatformInAppWebViewControllerCreationParams params) { - _controllerFromPlatform = - params.webviewParams?.controllerFromPlatform?.call(this) ?? this; - - webStorage = AndroidWebStorage( - AndroidWebStorageCreationParams( - localStorage: AndroidLocalStorage.defaultStorage(controller: this), - sessionStorage: AndroidSessionStorage.defaultStorage(controller: this), - ), - ); - - if (params.webviewParams is PlatformInAppWebViewWidgetCreationParams) { - final keepAlive = - (params.webviewParams as PlatformInAppWebViewWidgetCreationParams) - .keepAlive; - if (keepAlive != null) { - InAppWebViewControllerKeepAliveProps? props = _keepAliveMap[keepAlive]; - if (props == null) { - // save controller properties to restore it later - _keepAliveMap[keepAlive] = InAppWebViewControllerKeepAliveProps( - injectedScriptsFromURL: _injectedScriptsFromURL, - javaScriptHandlersMap: _javaScriptHandlersMap, - userScripts: _userScripts, - webMessageListenerObjNames: _webMessageListenerObjNames, - webMessageChannels: _webMessageChannels, - webMessageListeners: _webMessageListeners, - ); - } else { - // restore controller properties - _injectedScriptsFromURL = props.injectedScriptsFromURL; - _javaScriptHandlersMap = props.javaScriptHandlersMap; - _userScripts = props.userScripts; - _webMessageListenerObjNames = props.webMessageListenerObjNames; - _webMessageChannels = - props.webMessageChannels as Set; - _webMessageListeners = - props.webMessageListeners as Set; - } - } - } - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - name: _inAppBrowser == null - ? "WebView" - : _inAppBrowser.runtimeType.toString(), - id: (getViewId() ?? _inAppBrowser?.id).toString(), - debugLoggingSettings: PlatformInAppWebViewController.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - if (PlatformInAppWebViewController.debugLoggingSettings.enabled && - call.method != "onCallJsHandler") { - _debugLog(call.method, call.arguments); - } - - switch (call.method) { - case "onLoadStart": - _injectedScriptsFromURL.clear(); - if ((webviewParams != null && webviewParams!.onLoadStart != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - if (webviewParams != null && webviewParams!.onLoadStart != null) - webviewParams!.onLoadStart!(_controllerFromPlatform, uri); - else - _inAppBrowserEventHandler!.onLoadStart(uri); - } - break; - case "onLoadStop": - if ((webviewParams != null && webviewParams!.onLoadStop != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - if (webviewParams != null && webviewParams!.onLoadStop != null) - webviewParams!.onLoadStop!(_controllerFromPlatform, uri); - else - _inAppBrowserEventHandler!.onLoadStop(uri); - } - break; - case "onReceivedError": - if ((webviewParams != null && - (webviewParams!.onReceivedError != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadError != null)) || - _inAppBrowserEventHandler != null) { - WebResourceRequest request = WebResourceRequest.fromMap( - call.arguments["request"].cast(), - )!; - WebResourceError error = WebResourceError.fromMap( - call.arguments["error"].cast(), - )!; - var isForMainFrame = request.isForMainFrame ?? false; - - if (webviewParams != null) { - if (webviewParams!.onReceivedError != null) - webviewParams!.onReceivedError!( - _controllerFromPlatform, - request, - error, - ); - else if (isForMainFrame) { - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadError!( - _controllerFromPlatform, - request.url, - error.type.toNativeValue() ?? -1, - error.description, - ); - } - } else { - if (isForMainFrame) { - _inAppBrowserEventHandler!.onLoadError( - request.url, - error.type.toNativeValue() ?? -1, - error.description, - ); - } - _inAppBrowserEventHandler!.onReceivedError(request, error); - } - } - break; - case "onReceivedHttpError": - if ((webviewParams != null && - (webviewParams!.onReceivedHttpError != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadHttpError != null)) || - _inAppBrowserEventHandler != null) { - WebResourceRequest request = WebResourceRequest.fromMap( - call.arguments["request"].cast(), - )!; - WebResourceResponse errorResponse = WebResourceResponse.fromMap( - call.arguments["errorResponse"].cast(), - )!; - var isForMainFrame = request.isForMainFrame ?? false; - - if (webviewParams != null) { - if (webviewParams!.onReceivedHttpError != null) - webviewParams!.onReceivedHttpError!( - _controllerFromPlatform, - request, - errorResponse, - ); - else if (isForMainFrame) { - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadHttpError!( - _controllerFromPlatform, - request.url, - errorResponse.statusCode ?? -1, - errorResponse.reasonPhrase ?? '', - ); - } - } else { - if (isForMainFrame) { - _inAppBrowserEventHandler!.onLoadHttpError( - request.url, - errorResponse.statusCode ?? -1, - errorResponse.reasonPhrase ?? '', - ); - } - _inAppBrowserEventHandler!.onReceivedHttpError( - request, - errorResponse, - ); - } - } - break; - case "onProgressChanged": - if ((webviewParams != null && - webviewParams!.onProgressChanged != null) || - _inAppBrowserEventHandler != null) { - int progress = call.arguments["progress"]; - if (webviewParams != null && webviewParams!.onProgressChanged != null) - webviewParams!.onProgressChanged!( - _controllerFromPlatform, - progress, - ); - else - _inAppBrowserEventHandler!.onProgressChanged(progress); - } - break; - case "shouldOverrideUrlLoading": - if ((webviewParams != null && - webviewParams!.shouldOverrideUrlLoading != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - NavigationAction navigationAction = NavigationAction.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.shouldOverrideUrlLoading != null) - return (await webviewParams!.shouldOverrideUrlLoading!( - _controllerFromPlatform, - navigationAction, - ))?.toNativeValue(); - return (await _inAppBrowserEventHandler!.shouldOverrideUrlLoading( - navigationAction, - ))?.toNativeValue(); - } - break; - case "onConsoleMessage": - if ((webviewParams != null && - webviewParams!.onConsoleMessage != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - ConsoleMessage consoleMessage = ConsoleMessage.fromMap(arguments)!; - if (webviewParams != null && webviewParams!.onConsoleMessage != null) - webviewParams!.onConsoleMessage!( - _controllerFromPlatform, - consoleMessage, - ); - else - _inAppBrowserEventHandler!.onConsoleMessage(consoleMessage); - } - break; - case "onScrollChanged": - if ((webviewParams != null && webviewParams!.onScrollChanged != null) || - _inAppBrowserEventHandler != null) { - int x = call.arguments["x"]; - int y = call.arguments["y"]; - if (webviewParams != null && webviewParams!.onScrollChanged != null) - webviewParams!.onScrollChanged!(_controllerFromPlatform, x, y); - else - _inAppBrowserEventHandler!.onScrollChanged(x, y); - } - break; - case "onDownloadStarting": - if ((webviewParams != null && - (webviewParams!.onDownloadStart != null || - webviewParams!.onDownloadStartRequest != null || - webviewParams!.onDownloadStarting != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - DownloadStartRequest downloadStartRequest = - DownloadStartRequest.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.onDownloadStarting != null) - return (await webviewParams!.onDownloadStarting!( - _controllerFromPlatform, - downloadStartRequest, - ))?.toMap(); - else if (webviewParams!.onDownloadStartRequest != null) - webviewParams!.onDownloadStartRequest!( - _controllerFromPlatform, - downloadStartRequest, - ); - else { - webviewParams!.onDownloadStart!( - _controllerFromPlatform, - downloadStartRequest.url, - ); - } - } else { - _inAppBrowserEventHandler!.onDownloadStart( - downloadStartRequest.url, - ); - _inAppBrowserEventHandler!.onDownloadStartRequest( - downloadStartRequest, - ); - return (await _inAppBrowserEventHandler!.onDownloadStarting( - downloadStartRequest, - ))?.toMap(); - } - } - break; - case "onLoadResourceWithCustomScheme": - if ((webviewParams != null && - (webviewParams!.onLoadResourceWithCustomScheme != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadResourceCustomScheme != null)) || - _inAppBrowserEventHandler != null) { - Map requestMap = call.arguments["request"] - .cast(); - WebResourceRequest request = WebResourceRequest.fromMap(requestMap)!; - - if (webviewParams != null) { - if (webviewParams!.onLoadResourceWithCustomScheme != null) - return (await webviewParams!.onLoadResourceWithCustomScheme!( - _controllerFromPlatform, - request, - ))?.toMap(); - else { - return (await params - .webviewParams! - // ignore: deprecated_member_use_from_same_package - .onLoadResourceCustomScheme!( - _controllerFromPlatform, - request.url, - )) - ?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler! - .onLoadResourceWithCustomScheme(request)) ?? - (await _inAppBrowserEventHandler! - .onLoadResourceCustomScheme(request.url))) - ?.toMap(); - } - } - break; - case "onCreateWindow": - if ((webviewParams != null && webviewParams!.onCreateWindow != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - CreateWindowAction createWindowAction = CreateWindowAction.fromMap( - arguments, - )!; - - if (webviewParams != null && webviewParams!.onCreateWindow != null) - return await webviewParams!.onCreateWindow!( - _controllerFromPlatform, - createWindowAction, - ); - else - return await _inAppBrowserEventHandler!.onCreateWindow( - createWindowAction, - ); - } - break; - case "onCloseWindow": - if (webviewParams != null && webviewParams!.onCloseWindow != null) - webviewParams!.onCloseWindow!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onCloseWindow(); - break; - case "onTitleChanged": - if ((webviewParams != null && webviewParams!.onTitleChanged != null) || - _inAppBrowserEventHandler != null) { - String? title = call.arguments["title"]; - if (webviewParams != null && webviewParams!.onTitleChanged != null) - webviewParams!.onTitleChanged!(_controllerFromPlatform, title); - else - _inAppBrowserEventHandler!.onTitleChanged(title); - } - break; - case "onGeolocationPermissionsShowPrompt": - if ((webviewParams != null && - (webviewParams!.onGeolocationPermissionsShowPrompt != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnGeolocationPermissionsShowPrompt != - null)) || - _inAppBrowserEventHandler != null) { - String origin = call.arguments["origin"]; - - if (webviewParams != null) { - if (webviewParams!.onGeolocationPermissionsShowPrompt != null) - return (await webviewParams!.onGeolocationPermissionsShowPrompt!( - _controllerFromPlatform, - origin, - ))?.toMap(); - else { - return (await params - .webviewParams! - // ignore: deprecated_member_use_from_same_package - .androidOnGeolocationPermissionsShowPrompt!( - _controllerFromPlatform, - origin, - )) - ?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler! - .onGeolocationPermissionsShowPrompt(origin)) ?? - (await _inAppBrowserEventHandler! - .androidOnGeolocationPermissionsShowPrompt(origin))) - ?.toMap(); - } - } - break; - case "onGeolocationPermissionsHidePrompt": - if (webviewParams != null && - (webviewParams!.onGeolocationPermissionsHidePrompt != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnGeolocationPermissionsHidePrompt != - null)) { - if (webviewParams!.onGeolocationPermissionsHidePrompt != null) - webviewParams!.onGeolocationPermissionsHidePrompt!( - _controllerFromPlatform, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnGeolocationPermissionsHidePrompt!( - _controllerFromPlatform, - ); - } - } else if (_inAppBrowserEventHandler != null) { - _inAppBrowserEventHandler!.onGeolocationPermissionsHidePrompt(); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler! - .androidOnGeolocationPermissionsHidePrompt(); - } - break; - case "shouldInterceptRequest": - if ((webviewParams != null && - (webviewParams!.shouldInterceptRequest != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidShouldInterceptRequest != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - WebResourceRequest request = WebResourceRequest.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.shouldInterceptRequest != null) - return (await webviewParams!.shouldInterceptRequest!( - _controllerFromPlatform, - request, - ))?.toMap(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidShouldInterceptRequest!( - _controllerFromPlatform, - request, - ))?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler!.shouldInterceptRequest( - request, - )) ?? - (await _inAppBrowserEventHandler! - .androidShouldInterceptRequest(request))) - ?.toMap(); - } - } - break; - case "onRenderProcessUnresponsive": - if ((webviewParams != null && - (webviewParams!.onRenderProcessUnresponsive != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnRenderProcessUnresponsive != - null)) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - - if (webviewParams != null) { - if (webviewParams!.onRenderProcessUnresponsive != null) - return (await webviewParams!.onRenderProcessUnresponsive!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidOnRenderProcessUnresponsive!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - } - } else { - return ((await _inAppBrowserEventHandler! - .onRenderProcessUnresponsive(uri)) ?? - (await _inAppBrowserEventHandler! - .androidOnRenderProcessUnresponsive(uri))) - ?.toNativeValue(); - } - } - break; - case "onRenderProcessResponsive": - if ((webviewParams != null && - (webviewParams!.onRenderProcessResponsive != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnRenderProcessResponsive != null)) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - - if (webviewParams != null) { - if (webviewParams!.onRenderProcessResponsive != null) - return (await webviewParams!.onRenderProcessResponsive!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidOnRenderProcessResponsive!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - } - } else { - return ((await _inAppBrowserEventHandler!.onRenderProcessResponsive( - uri, - )) ?? - (await _inAppBrowserEventHandler! - .androidOnRenderProcessResponsive(uri))) - ?.toNativeValue(); - } - } - break; - case "onRenderProcessGone": - if ((webviewParams != null && - (webviewParams!.onRenderProcessGone != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnRenderProcessGone != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - RenderProcessGoneDetail detail = RenderProcessGoneDetail.fromMap( - arguments, - )!; - - if (webviewParams != null) { - if (webviewParams!.onRenderProcessGone != null) - webviewParams!.onRenderProcessGone!( - _controllerFromPlatform, - detail, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnRenderProcessGone!( - _controllerFromPlatform, - detail, - ); - } - } else if (_inAppBrowserEventHandler != null) { - _inAppBrowserEventHandler!.onRenderProcessGone(detail); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.androidOnRenderProcessGone(detail); - } - } - break; - case "onFormResubmission": - if ((webviewParams != null && - (webviewParams!.onFormResubmission != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnFormResubmission != null)) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - - if (webviewParams != null) { - if (webviewParams!.onFormResubmission != null) - return (await webviewParams!.onFormResubmission!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidOnFormResubmission!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - } - } else { - return ((await _inAppBrowserEventHandler!.onFormResubmission( - uri, - )) ?? - // ignore: deprecated_member_use_from_same_package - (await _inAppBrowserEventHandler!.androidOnFormResubmission( - uri, - ))) - ?.toNativeValue(); - } - } - break; - case "onZoomScaleChanged": - if ((webviewParams != null && - // ignore: deprecated_member_use_from_same_package - (webviewParams!.androidOnScaleChanged != null || - webviewParams!.onZoomScaleChanged != null)) || - _inAppBrowserEventHandler != null) { - double oldScale = call.arguments["oldScale"]; - double newScale = call.arguments["newScale"]; - - if (webviewParams != null) { - if (webviewParams!.onZoomScaleChanged != null) - webviewParams!.onZoomScaleChanged!( - _controllerFromPlatform, - oldScale, - newScale, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnScaleChanged!( - _controllerFromPlatform, - oldScale, - newScale, - ); - } - } else { - _inAppBrowserEventHandler!.onZoomScaleChanged(oldScale, newScale); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.androidOnScaleChanged( - oldScale, - newScale, - ); - } - } - break; - case "onReceivedIcon": - if ((webviewParams != null && - (webviewParams!.onReceivedIcon != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedIcon != null)) || - _inAppBrowserEventHandler != null) { - Uint8List icon = Uint8List.fromList( - call.arguments["icon"].cast(), - ); - - if (webviewParams != null) { - if (webviewParams!.onReceivedIcon != null) - webviewParams!.onReceivedIcon!(_controllerFromPlatform, icon); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedIcon!( - _controllerFromPlatform, - icon, - ); - } - } else { - _inAppBrowserEventHandler!.onReceivedIcon(icon); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.androidOnReceivedIcon(icon); - } - } - break; - case "onReceivedTouchIconUrl": - if ((webviewParams != null && - (webviewParams!.onReceivedTouchIconUrl != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedTouchIconUrl != null)) || - _inAppBrowserEventHandler != null) { - String url = call.arguments["url"]; - bool precomposed = call.arguments["precomposed"]; - WebUri uri = WebUri(url); - - if (webviewParams != null) { - if (webviewParams!.onReceivedTouchIconUrl != null) - webviewParams!.onReceivedTouchIconUrl!( - _controllerFromPlatform, - uri, - precomposed, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedTouchIconUrl!( - _controllerFromPlatform, - uri, - precomposed, - ); - } - } else { - _inAppBrowserEventHandler!.onReceivedTouchIconUrl(uri, precomposed); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.androidOnReceivedTouchIconUrl( - uri, - precomposed, - ); - } - } - break; - case "onJsAlert": - if ((webviewParams != null && webviewParams!.onJsAlert != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsAlertRequest jsAlertRequest = JsAlertRequest.fromMap(arguments)!; - - if (webviewParams != null && webviewParams!.onJsAlert != null) - return (await webviewParams!.onJsAlert!( - _controllerFromPlatform, - jsAlertRequest, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onJsAlert( - jsAlertRequest, - ))?.toMap(); - } - break; - case "onJsConfirm": - if ((webviewParams != null && webviewParams!.onJsConfirm != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsConfirmRequest jsConfirmRequest = JsConfirmRequest.fromMap( - arguments, - )!; - - if (webviewParams != null && webviewParams!.onJsConfirm != null) - return (await webviewParams!.onJsConfirm!( - _controllerFromPlatform, - jsConfirmRequest, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onJsConfirm( - jsConfirmRequest, - ))?.toMap(); - } - break; - case "onJsPrompt": - if ((webviewParams != null && webviewParams!.onJsPrompt != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsPromptRequest jsPromptRequest = JsPromptRequest.fromMap(arguments)!; - - if (webviewParams != null && webviewParams!.onJsPrompt != null) - return (await webviewParams!.onJsPrompt!( - _controllerFromPlatform, - jsPromptRequest, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onJsPrompt( - jsPromptRequest, - ))?.toMap(); - } - break; - case "onJsBeforeUnload": - if ((webviewParams != null && - (webviewParams!.onJsBeforeUnload != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnJsBeforeUnload != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsBeforeUnloadRequest jsBeforeUnloadRequest = - JsBeforeUnloadRequest.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.onJsBeforeUnload != null) - return (await webviewParams!.onJsBeforeUnload!( - _controllerFromPlatform, - jsBeforeUnloadRequest, - ))?.toMap(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidOnJsBeforeUnload!( - _controllerFromPlatform, - jsBeforeUnloadRequest, - ))?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler!.onJsBeforeUnload( - jsBeforeUnloadRequest, - )) ?? - (await _inAppBrowserEventHandler!.androidOnJsBeforeUnload( - jsBeforeUnloadRequest, - ))) - ?.toMap(); - } - } - break; - case "onSafeBrowsingHit": - if ((webviewParams != null && - (webviewParams!.onSafeBrowsingHit != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnSafeBrowsingHit != null)) || - _inAppBrowserEventHandler != null) { - String url = call.arguments["url"]; - SafeBrowsingThreat? threatType = SafeBrowsingThreat.fromNativeValue( - call.arguments["threatType"], - ); - WebUri uri = WebUri(url); - - if (webviewParams != null) { - if (webviewParams!.onSafeBrowsingHit != null) - return (await webviewParams!.onSafeBrowsingHit!( - _controllerFromPlatform, - uri, - threatType, - ))?.toMap(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidOnSafeBrowsingHit!( - _controllerFromPlatform, - uri, - threatType, - ))?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler!.onSafeBrowsingHit( - uri, - threatType, - )) ?? - (await _inAppBrowserEventHandler!.androidOnSafeBrowsingHit( - uri, - threatType, - ))) - ?.toMap(); - } - } - break; - case "onReceivedLoginRequest": - if ((webviewParams != null && - (webviewParams!.onReceivedLoginRequest != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedLoginRequest != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - LoginRequest loginRequest = LoginRequest.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.onReceivedLoginRequest != null) - webviewParams!.onReceivedLoginRequest!( - _controllerFromPlatform, - loginRequest, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedLoginRequest!( - _controllerFromPlatform, - loginRequest, - ); - } - } else { - _inAppBrowserEventHandler!.onReceivedLoginRequest(loginRequest); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.androidOnReceivedLoginRequest( - loginRequest, - ); - } - } - break; - case "onPermissionRequestCanceled": - if ((webviewParams != null && - webviewParams!.onPermissionRequestCanceled != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - PermissionRequest permissionRequest = PermissionRequest.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.onPermissionRequestCanceled != null) - webviewParams!.onPermissionRequestCanceled!( - _controllerFromPlatform, - permissionRequest, - ); - else - _inAppBrowserEventHandler!.onPermissionRequestCanceled( - permissionRequest, - ); - } - break; - case "onRequestFocus": - if ((webviewParams != null && webviewParams!.onRequestFocus != null) || - _inAppBrowserEventHandler != null) { - if (webviewParams != null && webviewParams!.onRequestFocus != null) - webviewParams!.onRequestFocus!(_controllerFromPlatform); - else - _inAppBrowserEventHandler!.onRequestFocus(); - } - break; - case "onReceivedHttpAuthRequest": - if ((webviewParams != null && - webviewParams!.onReceivedHttpAuthRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - HttpAuthenticationChallenge challenge = - HttpAuthenticationChallenge.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onReceivedHttpAuthRequest != null) - return (await webviewParams!.onReceivedHttpAuthRequest!( - _controllerFromPlatform, - challenge, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onReceivedHttpAuthRequest( - challenge, - ))?.toMap(); - } - break; - case "onReceivedServerTrustAuthRequest": - if ((webviewParams != null && - webviewParams!.onReceivedServerTrustAuthRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - ServerTrustChallenge challenge = ServerTrustChallenge.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.onReceivedServerTrustAuthRequest != null) - return (await webviewParams!.onReceivedServerTrustAuthRequest!( - _controllerFromPlatform, - challenge, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler! - .onReceivedServerTrustAuthRequest(challenge)) - ?.toMap(); - } - break; - case "onReceivedClientCertRequest": - if ((webviewParams != null && - webviewParams!.onReceivedClientCertRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - ClientCertChallenge challenge = ClientCertChallenge.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.onReceivedClientCertRequest != null) - return (await webviewParams!.onReceivedClientCertRequest!( - _controllerFromPlatform, - challenge, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler! - .onReceivedClientCertRequest(challenge)) - ?.toMap(); - } - break; - case "onFindResultReceived": - if ((webviewParams != null && - (webviewParams!.onFindResultReceived != null || - (webviewParams!.findInteractionController != null && - webviewParams! - .findInteractionController! - .params - .onFindResultReceived != - null))) || - _inAppBrowserEventHandler != null) { - int activeMatchOrdinal = call.arguments["activeMatchOrdinal"]; - int numberOfMatches = call.arguments["numberOfMatches"]; - bool isDoneCounting = call.arguments["isDoneCounting"]; - if (webviewParams != null) { - if (webviewParams!.findInteractionController != null && - webviewParams! - .findInteractionController! - .params - .onFindResultReceived != - null) - webviewParams! - .findInteractionController! - .params - .onFindResultReceived!( - webviewParams!.findInteractionController!, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - else - webviewParams!.onFindResultReceived!( - _controllerFromPlatform, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - } else { - if (_inAppBrowser!.findInteractionController != null && - _inAppBrowser! - .findInteractionController! - .onFindResultReceived != - null) - _inAppBrowser!.findInteractionController!.onFindResultReceived!( - webviewParams!.findInteractionController!, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - else - _inAppBrowserEventHandler!.onFindResultReceived( - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - } - } - break; - case "onPermissionRequest": - if ((webviewParams != null && - (webviewParams!.onPermissionRequest != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnPermissionRequest != null)) || - _inAppBrowserEventHandler != null) { - String origin = call.arguments["origin"]; - List resources = call.arguments["resources"].cast(); - - Map arguments = call.arguments - .cast(); - PermissionRequest permissionRequest = PermissionRequest.fromMap( - arguments, - )!; - - if (webviewParams != null) { - if (webviewParams!.onPermissionRequest != null) - return (await webviewParams!.onPermissionRequest!( - _controllerFromPlatform, - permissionRequest, - ))?.toMap(); - else { - return (await webviewParams!.androidOnPermissionRequest!( - _controllerFromPlatform, - origin, - resources, - ))?.toMap(); - } - } else { - return (await _inAppBrowserEventHandler!.onPermissionRequest( - permissionRequest, - ))?.toMap() ?? - (await _inAppBrowserEventHandler!.androidOnPermissionRequest( - origin, - resources, - ))?.toMap(); - } - } - break; - case "onUpdateVisitedHistory": - if ((webviewParams != null && - webviewParams!.onUpdateVisitedHistory != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - bool? isReload = call.arguments["isReload"]; - WebUri? uri = url != null ? WebUri(url) : null; - if (webviewParams != null && - webviewParams!.onUpdateVisitedHistory != null) - webviewParams!.onUpdateVisitedHistory!( - _controllerFromPlatform, - uri, - isReload, - ); - else - _inAppBrowserEventHandler!.onUpdateVisitedHistory(uri, isReload); - } - break; - case "onWebContentProcessDidTerminate": - if (webviewParams != null && - (webviewParams!.onWebContentProcessDidTerminate != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.iosOnWebContentProcessDidTerminate != null)) { - if (webviewParams!.onWebContentProcessDidTerminate != null) - webviewParams!.onWebContentProcessDidTerminate!( - _controllerFromPlatform, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.iosOnWebContentProcessDidTerminate!( - _controllerFromPlatform, - ); - } - } else if (_inAppBrowserEventHandler != null) { - _inAppBrowserEventHandler!.onWebContentProcessDidTerminate(); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.iosOnWebContentProcessDidTerminate(); - } - break; - case "onPageCommitVisible": - if ((webviewParams != null && - webviewParams!.onPageCommitVisible != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - if (webviewParams != null && - webviewParams!.onPageCommitVisible != null) - webviewParams!.onPageCommitVisible!(_controllerFromPlatform, uri); - else - _inAppBrowserEventHandler!.onPageCommitVisible(uri); - } - break; - case "onDidReceiveServerRedirectForProvisionalNavigation": - if (webviewParams != null && - (webviewParams! - .onDidReceiveServerRedirectForProvisionalNavigation != - null || - params - .webviewParams! - // ignore: deprecated_member_use_from_same_package - .iosOnDidReceiveServerRedirectForProvisionalNavigation != - null)) { - if (webviewParams! - .onDidReceiveServerRedirectForProvisionalNavigation != - null) - webviewParams!.onDidReceiveServerRedirectForProvisionalNavigation!( - _controllerFromPlatform, - ); - else { - params - .webviewParams! - // ignore: deprecated_member_use_from_same_package - .iosOnDidReceiveServerRedirectForProvisionalNavigation!( - _controllerFromPlatform, - ); - } - } else if (_inAppBrowserEventHandler != null) { - _inAppBrowserEventHandler! - .onDidReceiveServerRedirectForProvisionalNavigation(); - _inAppBrowserEventHandler! - .iosOnDidReceiveServerRedirectForProvisionalNavigation(); - } - break; - case "onNavigationResponse": - if ((webviewParams != null && - (webviewParams!.onNavigationResponse != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.iosOnNavigationResponse != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - // ignore: deprecated_member_use_from_same_package - IOSWKNavigationResponse iosOnNavigationResponse = - // ignore: deprecated_member_use_from_same_package - IOSWKNavigationResponse.fromMap(arguments)!; - - NavigationResponse navigationResponse = NavigationResponse.fromMap( - arguments, - )!; - - if (webviewParams != null) { - if (webviewParams!.onNavigationResponse != null) - return (await webviewParams!.onNavigationResponse!( - _controllerFromPlatform, - navigationResponse, - ))?.toNativeValue(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.iosOnNavigationResponse!( - _controllerFromPlatform, - iosOnNavigationResponse, - ))?.toNativeValue(); - } - } else { - return (await _inAppBrowserEventHandler!.onNavigationResponse( - navigationResponse, - ))?.toNativeValue() ?? - (await _inAppBrowserEventHandler!.iosOnNavigationResponse( - iosOnNavigationResponse, - ))?.toNativeValue(); - } - } - break; - case "shouldAllowDeprecatedTLS": - if ((webviewParams != null && - (webviewParams!.shouldAllowDeprecatedTLS != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.iosShouldAllowDeprecatedTLS != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - URLAuthenticationChallenge challenge = - URLAuthenticationChallenge.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.shouldAllowDeprecatedTLS != null) - return (await webviewParams!.shouldAllowDeprecatedTLS!( - _controllerFromPlatform, - challenge, - ))?.toNativeValue(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.iosShouldAllowDeprecatedTLS!( - _controllerFromPlatform, - challenge, - ))?.toNativeValue(); - } - } else { - return (await _inAppBrowserEventHandler!.shouldAllowDeprecatedTLS( - challenge, - ))?.toNativeValue() ?? - // ignore: deprecated_member_use_from_same_package - (await _inAppBrowserEventHandler!.iosShouldAllowDeprecatedTLS( - challenge, - ))?.toNativeValue(); - } - } - break; - case "onLongPressHitTestResult": - if ((webviewParams != null && - webviewParams!.onLongPressHitTestResult != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - InAppWebViewHitTestResult hitTestResult = - InAppWebViewHitTestResult.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onLongPressHitTestResult != null) - webviewParams!.onLongPressHitTestResult!( - _controllerFromPlatform, - hitTestResult, - ); - else - _inAppBrowserEventHandler!.onLongPressHitTestResult(hitTestResult); - } - break; - case "onCreateContextMenu": - ContextMenu? contextMenu; - if (webviewParams != null && webviewParams!.contextMenu != null) { - contextMenu = webviewParams!.contextMenu; - } else if (_inAppBrowserEventHandler != null && - _inAppBrowser!.contextMenu != null) { - contextMenu = _inAppBrowser!.contextMenu; - } - - if (contextMenu != null && contextMenu.onCreateContextMenu != null) { - Map arguments = call.arguments - .cast(); - InAppWebViewHitTestResult hitTestResult = - InAppWebViewHitTestResult.fromMap(arguments)!; - - contextMenu.onCreateContextMenu!(hitTestResult); - } - break; - case "onHideContextMenu": - ContextMenu? contextMenu; - if (webviewParams != null && webviewParams!.contextMenu != null) { - contextMenu = webviewParams!.contextMenu; - } else if (_inAppBrowserEventHandler != null && - _inAppBrowser!.contextMenu != null) { - contextMenu = _inAppBrowser!.contextMenu; - } - - if (contextMenu != null && contextMenu.onHideContextMenu != null) { - contextMenu.onHideContextMenu!(); - } - break; - case "onContextMenuActionItemClicked": - ContextMenu? contextMenu; - if (webviewParams != null && webviewParams!.contextMenu != null) { - contextMenu = webviewParams!.contextMenu; - } else if (_inAppBrowserEventHandler != null && - _inAppBrowser!.contextMenu != null) { - contextMenu = _inAppBrowser!.contextMenu; - } - - if (contextMenu != null) { - int? androidId = call.arguments["androidId"]; - String? iosId = call.arguments["iosId"]; - dynamic id = call.arguments["id"]; - String title = call.arguments["title"]; - - ContextMenuItem menuItemClicked = ContextMenuItem( - id: id, - // ignore: deprecated_member_use_from_same_package - androidId: androidId, - // ignore: deprecated_member_use_from_same_package - iosId: iosId, - title: title, - action: null, - ); - - for (var menuItem in contextMenu.menuItems) { - if (menuItem.id == id) { - menuItemClicked = menuItem; - if (menuItem.action != null) { - menuItem.action!(); - } - break; - } - } - - if (contextMenu.onContextMenuActionItemClicked != null) { - contextMenu.onContextMenuActionItemClicked!(menuItemClicked); - } - } - break; - case "onEnterFullscreen": - if (webviewParams != null && webviewParams!.onEnterFullscreen != null) - webviewParams!.onEnterFullscreen!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onEnterFullscreen(); - break; - case "onExitFullscreen": - if (webviewParams != null && webviewParams!.onExitFullscreen != null) - webviewParams!.onExitFullscreen!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onExitFullscreen(); - break; - case "onOverScrolled": - if ((webviewParams != null && webviewParams!.onOverScrolled != null) || - _inAppBrowserEventHandler != null) { - int x = call.arguments["x"]; - int y = call.arguments["y"]; - bool clampedX = call.arguments["clampedX"]; - bool clampedY = call.arguments["clampedY"]; - - if (webviewParams != null && webviewParams!.onOverScrolled != null) - webviewParams!.onOverScrolled!( - _controllerFromPlatform, - x, - y, - clampedX, - clampedY, - ); - else - _inAppBrowserEventHandler!.onOverScrolled(x, y, clampedX, clampedY); - } - break; - case "onWindowFocus": - if (webviewParams != null && webviewParams!.onWindowFocus != null) - webviewParams!.onWindowFocus!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onWindowFocus(); - break; - case "onWindowBlur": - if (webviewParams != null && webviewParams!.onWindowBlur != null) - webviewParams!.onWindowBlur!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onWindowBlur(); - break; - case "onPrintRequest": - if ((webviewParams != null && - (webviewParams!.onPrintRequest != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onPrint != null)) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - String? printJobId = call.arguments["printJobId"]; - WebUri? uri = url != null ? WebUri(url) : null; - AndroidPrintJobController? printJob = printJobId != null - ? AndroidPrintJobController( - AndroidPrintJobControllerCreationParams(id: printJobId), - ) - : null; - - if (webviewParams != null) { - if (webviewParams!.onPrintRequest != null) - return await webviewParams!.onPrintRequest!( - _controllerFromPlatform, - uri, - printJob, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.onPrint!(_controllerFromPlatform, uri); - return false; - } - } else { - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.onPrint(uri); - return await _inAppBrowserEventHandler!.onPrintRequest( - uri, - printJob, - ); - } - } - break; - case "onInjectedScriptLoaded": - String id = call.arguments[0]; - var onLoadCallback = _injectedScriptsFromURL[id]?.onLoad; - if ((webviewParams != null || _inAppBrowserEventHandler != null) && - onLoadCallback != null) { - onLoadCallback(); - } - break; - case "onInjectedScriptError": - String id = call.arguments[0]; - var onErrorCallback = _injectedScriptsFromURL[id]?.onError; - if ((webviewParams != null || _inAppBrowserEventHandler != null) && - onErrorCallback != null) { - onErrorCallback(); - } - break; - case "onCameraCaptureStateChanged": - if ((webviewParams != null && - webviewParams!.onCameraCaptureStateChanged != null) || - _inAppBrowserEventHandler != null) { - var oldState = MediaCaptureState.fromNativeValue( - call.arguments["oldState"], - ); - var newState = MediaCaptureState.fromNativeValue( - call.arguments["newState"], - ); - - if (webviewParams != null && - webviewParams!.onCameraCaptureStateChanged != null) - webviewParams!.onCameraCaptureStateChanged!( - _controllerFromPlatform, - oldState, - newState, - ); - else - _inAppBrowserEventHandler!.onCameraCaptureStateChanged( - oldState, - newState, - ); - } - break; - case "onMicrophoneCaptureStateChanged": - if ((webviewParams != null && - webviewParams!.onMicrophoneCaptureStateChanged != null) || - _inAppBrowserEventHandler != null) { - var oldState = MediaCaptureState.fromNativeValue( - call.arguments["oldState"], - ); - var newState = MediaCaptureState.fromNativeValue( - call.arguments["newState"], - ); - - if (webviewParams != null && - webviewParams!.onMicrophoneCaptureStateChanged != null) - webviewParams!.onMicrophoneCaptureStateChanged!( - _controllerFromPlatform, - oldState, - newState, - ); - else - _inAppBrowserEventHandler!.onMicrophoneCaptureStateChanged( - oldState, - newState, - ); - } - break; - case "onContentSizeChanged": - if ((webviewParams != null && - webviewParams!.onContentSizeChanged != null) || - _inAppBrowserEventHandler != null) { - var oldContentSize = MapSize.fromMap( - call.arguments["oldContentSize"]?.cast(), - )!; - var newContentSize = MapSize.fromMap( - call.arguments["newContentSize"]?.cast(), - )!; - - if (webviewParams != null && - webviewParams!.onContentSizeChanged != null) - webviewParams!.onContentSizeChanged!( - _controllerFromPlatform, - oldContentSize, - newContentSize, - ); - else - _inAppBrowserEventHandler!.onContentSizeChanged( - oldContentSize, - newContentSize, - ); - } - break; - case "onShowFileChooser": - if ((webviewParams != null && - webviewParams!.onShowFileChooser != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - ShowFileChooserRequest request = ShowFileChooserRequest.fromMap( - arguments, - )!; - - if (webviewParams != null && webviewParams!.onShowFileChooser != null) - return (await webviewParams!.onShowFileChooser!( - _controllerFromPlatform, - request, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onShowFileChooser( - request, - ))?.toMap(); - } - break; - case "onCallJsHandler": - String handlerName = call.arguments["handlerName"]; - Map handlerDataMap = call.arguments["data"] - .cast(); - // decode args to json - handlerDataMap["args"] = jsonDecode(handlerDataMap["args"]); - final handlerData = JavaScriptHandlerFunctionData.fromMap( - handlerDataMap, - )!; - - _debugLog(handlerName, handlerData); - - switch (handlerName) { - case "onLoadResource": - if ((webviewParams != null && - webviewParams!.onLoadResource != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - arguments["startTime"] = arguments["startTime"] is int - ? arguments["startTime"].toDouble() - : arguments["startTime"]; - arguments["duration"] = arguments["duration"] is int - ? arguments["duration"].toDouble() - : arguments["duration"]; - - var response = LoadedResource.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onLoadResource != null) - webviewParams!.onLoadResource!( - _controllerFromPlatform, - response, - ); - else - _inAppBrowserEventHandler!.onLoadResource(response); - } - return null; - case "shouldInterceptAjaxRequest": - if ((webviewParams != null && - webviewParams!.shouldInterceptAjaxRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - AjaxRequest request = AjaxRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.shouldInterceptAjaxRequest != null) - return jsonEncode( - await params.webviewParams!.shouldInterceptAjaxRequest!( - _controllerFromPlatform, - request, - ), - ); - else - return jsonEncode( - await _inAppBrowserEventHandler!.shouldInterceptAjaxRequest( - request, - ), - ); - } - return null; - case "onAjaxReadyStateChange": - if ((webviewParams != null && - webviewParams!.onAjaxReadyStateChange != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - AjaxRequest request = AjaxRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onAjaxReadyStateChange != null) - return jsonEncode( - (await webviewParams!.onAjaxReadyStateChange!( - _controllerFromPlatform, - request, - ))?.toNativeValue(), - ); - else - return jsonEncode( - (await _inAppBrowserEventHandler!.onAjaxReadyStateChange( - request, - ))?.toNativeValue(), - ); - } - return null; - case "onAjaxProgress": - if ((webviewParams != null && - webviewParams!.onAjaxProgress != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - AjaxRequest request = AjaxRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onAjaxProgress != null) - return jsonEncode( - (await webviewParams!.onAjaxProgress!( - _controllerFromPlatform, - request, - ))?.toNativeValue(), - ); - else - return jsonEncode( - (await _inAppBrowserEventHandler!.onAjaxProgress( - request, - ))?.toNativeValue(), - ); - } - return null; - case "shouldInterceptFetchRequest": - if ((webviewParams != null && - webviewParams!.shouldInterceptFetchRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - FetchRequest request = FetchRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.shouldInterceptFetchRequest != null) - return jsonEncode( - await webviewParams!.shouldInterceptFetchRequest!( - _controllerFromPlatform, - request, - ), - ); - else - return jsonEncode( - await _inAppBrowserEventHandler!.shouldInterceptFetchRequest( - request, - ), - ); - } - return null; - case "onWindowFocus": - if (webviewParams != null && webviewParams!.onWindowFocus != null) - webviewParams!.onWindowFocus!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onWindowFocus(); - return null; - case "onWindowBlur": - if (webviewParams != null && webviewParams!.onWindowBlur != null) - webviewParams!.onWindowBlur!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onWindowBlur(); - return null; - case "onInjectedScriptLoaded": - String id = handlerData.args[0]; - var onLoadCallback = _injectedScriptsFromURL[id]?.onLoad; - if ((webviewParams != null || _inAppBrowserEventHandler != null) && - onLoadCallback != null) { - onLoadCallback(); - } - return null; - case "onInjectedScriptError": - String id = handlerData.args[0]; - var onErrorCallback = _injectedScriptsFromURL[id]?.onError; - if ((webviewParams != null || _inAppBrowserEventHandler != null) && - onErrorCallback != null) { - onErrorCallback(); - } - return null; - } - - if (_javaScriptHandlersMap.containsKey(handlerName)) { - // convert result to json - try { - var jsHandlerResult = null; - if (_javaScriptHandlersMap[handlerName] - is JavaScriptHandlerCallback) { - jsHandlerResult = - await (_javaScriptHandlersMap[handlerName] - as JavaScriptHandlerCallback)(handlerData.args); - } else if (_javaScriptHandlersMap[handlerName] - is JavaScriptHandlerFunction) { - jsHandlerResult = - await (_javaScriptHandlersMap[handlerName] - as JavaScriptHandlerFunction)(handlerData); - } else { - jsHandlerResult = await _javaScriptHandlersMap[handlerName]!(); - } - return jsonEncode(jsHandlerResult); - } catch (error, stacktrace) { - developer.log( - error.toString() + '\n' + stacktrace.toString(), - name: 'JavaScript Handler "$handlerName"', - ); - throw Exception(error.toString().replaceFirst('Exception: ', '')); - } - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - Future getUrl() async { - Map args = {}; - String? url = await channel?.invokeMethod('getUrl', args); - return url != null ? WebUri(url) : null; - } - - @override - Future getTitle() async { - Map args = {}; - return await channel?.invokeMethod('getTitle', args); - } - - @override - Future getProgress() async { - Map args = {}; - return await channel?.invokeMethod('getProgress', args); - } - - @override - Future getHtml() async { - String? html; - - InAppWebViewSettings? settings = await getSettings(); - if (settings != null && settings.javaScriptEnabled == true) { - html = await evaluateJavascript( - source: "window.document.getElementsByTagName('html')[0].outerHTML;", - ); - if (html != null && html.isNotEmpty) return html; - } - - var webviewUrl = await getUrl(); - if (webviewUrl == null) { - return html; - } - - if (webviewUrl.isScheme("file")) { - var assetPathSplit = webviewUrl.toString().split("/flutter_assets/"); - var assetPath = assetPathSplit[assetPathSplit.length - 1]; - try { - var bytes = await rootBundle.load(assetPath); - html = utf8.decode(bytes.buffer.asUint8List()); - } catch (e) {} - } else { - try { - HttpClient client = HttpClient(); - var htmlRequest = await client.getUrl(webviewUrl); - html = await (await htmlRequest.close()) - .transform(Utf8Decoder()) - .join(); - } catch (e) { - developer.log(e.toString(), name: this.runtimeType.toString()); - } - } - - return html; - } - - @override - Future> getFavicons() async { - List favicons = []; - - var webviewUrl = await getUrl(); - - if (webviewUrl == null) { - return favicons; - } - - String? manifestUrl; - - var html = await getHtml(); - if (html == null || html.isEmpty) { - return favicons; - } - var assetPathBase; - - if (webviewUrl.isScheme("file")) { - var assetPathSplit = webviewUrl.toString().split("/flutter_assets/"); - assetPathBase = assetPathSplit[0] + "/flutter_assets/"; - } - - InAppWebViewSettings? settings = await getSettings(); - if (settings != null && settings.javaScriptEnabled == true) { - List> links = - (await evaluateJavascript( - source: """ -(function() { - var linkNodes = document.head.getElementsByTagName("link"); - var links = []; - for (var i = 0; i < linkNodes.length; i++) { - var linkNode = linkNodes[i]; - if (linkNode.rel === 'manifest') { - links.push( - { - rel: linkNode.rel, - href: linkNode.href, - sizes: null - } - ); - } else if (linkNode.rel != null && linkNode.rel.indexOf('icon') >= 0) { - links.push( - { - rel: linkNode.rel, - href: linkNode.href, - sizes: linkNode.sizes != null && linkNode.sizes.value != "" ? linkNode.sizes.value : null - } - ); - } - } - return links; -})(); -""", - ))?.cast>() ?? - []; - for (var link in links) { - if (link["rel"] == "manifest") { - manifestUrl = link["href"]; - if (!_isUrlAbsolute(manifestUrl!)) { - if (manifestUrl.startsWith("/")) { - manifestUrl = manifestUrl.substring(1); - } - manifestUrl = - ((assetPathBase == null) - ? webviewUrl.scheme + "://" + webviewUrl.host + "/" - : assetPathBase) + - manifestUrl; - } - continue; - } - favicons.addAll( - _createFavicons( - webviewUrl, - assetPathBase, - link["href"], - link["rel"], - link["sizes"], - false, - ), - ); - } - } - - // try to get /favicon.ico - try { - HttpClient client = HttpClient(); - var faviconUrl = - webviewUrl.scheme + "://" + webviewUrl.host + "/favicon.ico"; - var faviconUri = WebUri(faviconUrl); - var headRequest = await client.headUrl(faviconUri); - var headResponse = await headRequest.close(); - if (headResponse.statusCode == 200) { - favicons.add(Favicon(url: faviconUri, rel: "shortcut icon")); - } - } catch (e) { - developer.log( - "/favicon.ico file not found: " + e.toString(), - name: this.runtimeType.toString(), - ); - } - - // try to get the manifest file - HttpClientRequest? manifestRequest; - HttpClientResponse? manifestResponse; - bool manifestFound = false; - if (manifestUrl == null) { - manifestUrl = - webviewUrl.scheme + "://" + webviewUrl.host + "/manifest.json"; - } - try { - HttpClient client = HttpClient(); - manifestRequest = await client.getUrl(Uri.parse(manifestUrl)); - manifestResponse = await manifestRequest.close(); - manifestFound = - manifestResponse.statusCode == 200 && - manifestResponse.headers.contentType?.mimeType == "application/json"; - } catch (e) { - developer.log( - "Manifest file not found: " + e.toString(), - name: runtimeType.toString(), - ); - } - - if (manifestFound) { - try { - Map manifest = json.decode( - await manifestResponse!.transform(Utf8Decoder()).join(), - ); - if (manifest.containsKey("icons")) { - for (Map icon in manifest["icons"]) { - favicons.addAll( - _createFavicons( - webviewUrl, - assetPathBase, - icon["src"], - icon["rel"], - icon["sizes"], - true, - ), - ); - } - } - } catch (e) { - developer.log( - "Cannot get favicons from Manifest file. It might not have a valid format: " + - e.toString(), - error: e, - name: runtimeType.toString(), - ); - } - } - - return favicons; - } - - bool _isUrlAbsolute(String url) { - return url.startsWith("http://") || url.startsWith("https://"); - } - - List _createFavicons( - WebUri url, - String? assetPathBase, - String urlIcon, - String? rel, - String? sizes, - bool isManifest, - ) { - List favicons = []; - - List urlSplit = urlIcon.split("/"); - if (!_isUrlAbsolute(urlIcon)) { - if (urlIcon.startsWith("/")) { - urlIcon = urlIcon.substring(1); - } - urlIcon = - ((assetPathBase == null) - ? url.scheme + "://" + url.host + "/" - : assetPathBase) + - urlIcon; - } - if (isManifest) { - rel = (sizes != null) - ? urlSplit[urlSplit.length - 1] - .replaceFirst("-" + sizes, "") - .split(" ")[0] - .split(".")[0] - : null; - } - if (sizes != null && sizes.isNotEmpty && sizes != "any") { - List sizesSplit = sizes.split(" "); - for (String size in sizesSplit) { - int width = int.parse(size.split("x")[0]); - int height = int.parse(size.split("x")[1]); - favicons.add( - Favicon(url: WebUri(urlIcon), rel: rel, width: width, height: height), - ); - } - } else { - favicons.add( - Favicon(url: WebUri(urlIcon), rel: rel, width: null, height: null), - ); - } - - return favicons; - } - - @override - Future loadUrl({ - required URLRequest urlRequest, - @Deprecated('Use allowingReadAccessTo instead') - Uri? iosAllowingReadAccessTo, - WebUri? allowingReadAccessTo, - }) async { - assert(urlRequest.url != null && urlRequest.url.toString().isNotEmpty); - assert( - allowingReadAccessTo == null || allowingReadAccessTo.isScheme("file"), - ); - assert( - iosAllowingReadAccessTo == null || - iosAllowingReadAccessTo.isScheme("file"), - ); - - Map args = {}; - args.putIfAbsent('urlRequest', () => urlRequest.toMap()); - args.putIfAbsent( - 'allowingReadAccessTo', - () => - allowingReadAccessTo?.toString() ?? - iosAllowingReadAccessTo?.toString(), - ); - await channel?.invokeMethod('loadUrl', args); - } - - @override - Future postUrl({ - required WebUri url, - required Uint8List postData, - }) async { - assert(url.toString().isNotEmpty); - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - args.putIfAbsent('postData', () => postData); - await channel?.invokeMethod('postUrl', args); - } - - @override - Future loadData({ - required String data, - String mimeType = "text/html", - String encoding = "utf8", - WebUri? baseUrl, - @Deprecated('Use historyUrl instead') Uri? androidHistoryUrl, - WebUri? historyUrl, - @Deprecated('Use allowingReadAccessTo instead') - Uri? iosAllowingReadAccessTo, - WebUri? allowingReadAccessTo, - }) async { - assert( - allowingReadAccessTo == null || allowingReadAccessTo.isScheme("file"), - ); - assert( - iosAllowingReadAccessTo == null || - iosAllowingReadAccessTo.isScheme("file"), - ); - - Map args = {}; - args.putIfAbsent('data', () => data); - args.putIfAbsent('mimeType', () => mimeType); - args.putIfAbsent('encoding', () => encoding); - args.putIfAbsent('baseUrl', () => baseUrl?.toString() ?? "about:blank"); - args.putIfAbsent( - 'historyUrl', - () => - historyUrl?.toString() ?? - androidHistoryUrl?.toString() ?? - "about:blank", - ); - args.putIfAbsent( - 'allowingReadAccessTo', - () => - allowingReadAccessTo?.toString() ?? - iosAllowingReadAccessTo?.toString(), - ); - await channel?.invokeMethod('loadData', args); - } - - @override - Future loadFile({required String assetFilePath}) async { - assert(assetFilePath.isNotEmpty); - Map args = {}; - args.putIfAbsent('assetFilePath', () => assetFilePath); - await channel?.invokeMethod('loadFile', args); - } - - @override - Future reload() async { - Map args = {}; - await channel?.invokeMethod('reload', args); - } - - @override - Future goBack() async { - Map args = {}; - await channel?.invokeMethod('goBack', args); - } - - @override - Future canGoBack() async { - Map args = {}; - return await channel?.invokeMethod('canGoBack', args) ?? false; - } - - @override - Future goForward() async { - Map args = {}; - await channel?.invokeMethod('goForward', args); - } - - @override - Future canGoForward() async { - Map args = {}; - return await channel?.invokeMethod('canGoForward', args) ?? false; - } - - @override - Future goBackOrForward({required int steps}) async { - Map args = {}; - args.putIfAbsent('steps', () => steps); - await channel?.invokeMethod('goBackOrForward', args); - } - - @override - Future canGoBackOrForward({required int steps}) async { - Map args = {}; - args.putIfAbsent('steps', () => steps); - return await channel?.invokeMethod('canGoBackOrForward', args) ?? - false; - } - - @override - Future goTo({required WebHistoryItem historyItem}) async { - var steps = historyItem.offset; - if (steps != null) { - await goBackOrForward(steps: steps); - } - } - - @override - Future isLoading() async { - Map args = {}; - return await channel?.invokeMethod('isLoading', args) ?? false; - } - - @override - Future stopLoading() async { - Map args = {}; - await channel?.invokeMethod('stopLoading', args); - } - - @override - Future evaluateJavascript({ - required String source, - ContentWorld? contentWorld, - }) async { - Map args = {}; - args.putIfAbsent('source', () => source); - args.putIfAbsent('contentWorld', () => contentWorld?.toMap()); - var data = await channel?.invokeMethod('evaluateJavascript', args); - if (data != null) { - try { - // try to json decode the data coming from JavaScript - // otherwise return it as it is. - data = json.decode(data); - } catch (e) {} - } - return data; - } - - @override - Future injectJavascriptFileFromUrl({ - required WebUri urlFile, - ScriptHtmlTagAttributes? scriptHtmlTagAttributes, - }) async { - assert(urlFile.toString().isNotEmpty); - var id = scriptHtmlTagAttributes?.id; - if (scriptHtmlTagAttributes != null && id != null) { - _injectedScriptsFromURL[id] = scriptHtmlTagAttributes; - } - Map args = {}; - args.putIfAbsent('urlFile', () => urlFile.toString()); - args.putIfAbsent( - 'scriptHtmlTagAttributes', - () => scriptHtmlTagAttributes?.toMap(), - ); - await channel?.invokeMethod('injectJavascriptFileFromUrl', args); - } - - @override - Future injectJavascriptFileFromAsset({ - required String assetFilePath, - }) async { - String source = await rootBundle.loadString(assetFilePath); - return await evaluateJavascript(source: source); - } - - @override - Future injectCSSCode({required String source}) async { - Map args = {}; - args.putIfAbsent('source', () => source); - await channel?.invokeMethod('injectCSSCode', args); - } - - @override - Future injectCSSFileFromUrl({ - required WebUri urlFile, - CSSLinkHtmlTagAttributes? cssLinkHtmlTagAttributes, - }) async { - assert(urlFile.toString().isNotEmpty); - Map args = {}; - args.putIfAbsent('urlFile', () => urlFile.toString()); - args.putIfAbsent( - 'cssLinkHtmlTagAttributes', - () => cssLinkHtmlTagAttributes?.toMap(), - ); - await channel?.invokeMethod('injectCSSFileFromUrl', args); - } - - @override - Future injectCSSFileFromAsset({required String assetFilePath}) async { - String source = await rootBundle.loadString(assetFilePath); - await injectCSSCode(source: source); - } - - @override - void addJavaScriptHandler({ - required String handlerName, - required Function callback, - }) { - assert( - !kJavaScriptHandlerForbiddenNames.contains(handlerName), - '"$handlerName" is a forbidden name!', - ); - this._javaScriptHandlersMap[handlerName] = (callback); - } - - @override - Function? removeJavaScriptHandler({required String handlerName}) { - return this._javaScriptHandlersMap.remove(handlerName); - } - - @override - bool hasJavaScriptHandler({required String handlerName}) { - return this._javaScriptHandlersMap.containsKey(handlerName); - } - - @override - Future takeScreenshot({ - ScreenshotConfiguration? screenshotConfiguration, - }) async { - Map args = {}; - args.putIfAbsent( - 'screenshotConfiguration', - () => screenshotConfiguration?.toMap(), - ); - return await channel?.invokeMethod('takeScreenshot', args); - } - - @override - @Deprecated('Use setSettings instead') - Future setOptions({required InAppWebViewGroupOptions options}) async { - InAppWebViewSettings settings = - InAppWebViewSettings.fromMap(options.toMap()) ?? InAppWebViewSettings(); - await setSettings(settings: settings); - } - - @override - @Deprecated('Use getSettings instead') - Future getOptions() async { - InAppWebViewSettings? settings = await getSettings(); - - Map? options = settings?.toMap(); - if (options != null) { - options = options.cast(); - return InAppWebViewGroupOptions.fromMap(options as Map); - } - - return null; - } - - @override - Future setSettings({required InAppWebViewSettings settings}) async { - Map args = {}; - - args.putIfAbsent('settings', () => settings.toMap()); - await channel?.invokeMethod('setSettings', args); - } - - @override - Future getSettings() async { - Map args = {}; - - Map? settings = await channel?.invokeMethod( - 'getSettings', - args, - ); - if (settings != null) { - settings = settings.cast(); - return InAppWebViewSettings.fromMap(settings as Map); - } - - return null; - } - - @override - Future getCopyBackForwardList() async { - Map args = {}; - Map? result = (await channel?.invokeMethod( - 'getCopyBackForwardList', - args, - ))?.cast(); - return WebHistory.fromMap(result); - } - - @override - @Deprecated("Use InAppWebViewController.clearAllCache instead") - Future clearCache() async { - Map args = {}; - await channel?.invokeMethod('clearCache', args); - } - - @override - @Deprecated("Use FindInteractionController.findAll instead") - Future findAllAsync({required String find}) async { - Map args = {}; - args.putIfAbsent('find', () => find); - await channel?.invokeMethod('findAll', args); - } - - @override - @Deprecated("Use FindInteractionController.findNext instead") - Future findNext({required bool forward}) async { - Map args = {}; - args.putIfAbsent('forward', () => forward); - await channel?.invokeMethod('findNext', args); - } - - @override - @Deprecated("Use FindInteractionController.clearMatches instead") - Future clearMatches() async { - Map args = {}; - await channel?.invokeMethod('clearMatches', args); - } - - @override - @Deprecated("Use tRexRunnerHtml instead") - Future getTRexRunnerHtml() async { - return await tRexRunnerHtml; - } - - @override - @Deprecated("Use tRexRunnerCss instead") - Future getTRexRunnerCss() async { - return await tRexRunnerCss; - } - - @override - Future scrollTo({ - required int x, - required int y, - bool animated = false, - }) async { - Map args = {}; - args.putIfAbsent('x', () => x); - args.putIfAbsent('y', () => y); - args.putIfAbsent('animated', () => animated); - await channel?.invokeMethod('scrollTo', args); - } - - @override - Future scrollBy({ - required int x, - required int y, - bool animated = false, - }) async { - Map args = {}; - args.putIfAbsent('x', () => x); - args.putIfAbsent('y', () => y); - args.putIfAbsent('animated', () => animated); - await channel?.invokeMethod('scrollBy', args); - } - - @override - Future pauseTimers() async { - Map args = {}; - await channel?.invokeMethod('pauseTimers', args); - } - - @override - Future resumeTimers() async { - Map args = {}; - await channel?.invokeMethod('resumeTimers', args); - } - - @override - Future printCurrentPage({ - PrintJobSettings? settings, - }) async { - Map args = {}; - args.putIfAbsent("settings", () => settings?.toMap()); - String? jobId = await channel?.invokeMethod( - 'printCurrentPage', - args, - ); - if (jobId != null) { - return AndroidPrintJobController( - PlatformPrintJobControllerCreationParams(id: jobId), - ); - } - return null; - } - - @override - Future getContentHeight() async { - Map args = {}; - var height = await channel?.invokeMethod('getContentHeight', args); - if (height == null || height == 0) { - // try to use javascript - var scrollHeight = await evaluateJavascript( - source: "document.documentElement.scrollHeight;", - ); - if (scrollHeight != null && scrollHeight is num) { - height = scrollHeight.toInt(); - } - } - return height; - } - - @override - Future getContentWidth() async { - Map args = {}; - var height = await channel?.invokeMethod('getContentWidth', args); - if (height == null || height == 0) { - // try to use javascript - var scrollHeight = await evaluateJavascript( - source: "document.documentElement.scrollWidth;", - ); - if (scrollHeight != null && scrollHeight is num) { - height = scrollHeight.toInt(); - } - } - return height; - } - - @override - Future zoomBy({ - required double zoomFactor, - @Deprecated('Use animated instead') bool? iosAnimated, - bool animated = false, - }) async { - assert(zoomFactor > 0.01 && zoomFactor <= 100.0); - - Map args = {}; - args.putIfAbsent('zoomFactor', () => zoomFactor); - args.putIfAbsent('animated', () => iosAnimated ?? animated); - return await channel?.invokeMethod('zoomBy', args); - } - - @override - Future getOriginalUrl() async { - Map args = {}; - String? url = await channel?.invokeMethod('getOriginalUrl', args); - return url != null ? WebUri(url) : null; - } - - @override - Future getZoomScale() async { - Map args = {}; - return await channel?.invokeMethod('getZoomScale', args); - } - - @override - @Deprecated('Use getZoomScale instead') - Future getScale() async { - return await getZoomScale(); - } - - @override - Future getSelectedText() async { - Map args = {}; - return await channel?.invokeMethod('getSelectedText', args); - } - - @override - Future getHitTestResult() async { - Map args = {}; - Map? hitTestResultMap = await channel?.invokeMethod( - 'getHitTestResult', - args, - ); - - if (hitTestResultMap == null) { - return null; - } - - hitTestResultMap = hitTestResultMap.cast(); - - InAppWebViewHitTestResultType? type = - InAppWebViewHitTestResultType.fromNativeValue( - hitTestResultMap["type"]?.toInt(), - ); - String? extra = hitTestResultMap["extra"]; - return InAppWebViewHitTestResult(type: type, extra: extra); - } - - @override - Future requestFocus({ - FocusDirection? direction, - InAppWebViewRect? previouslyFocusedRect, - }) async { - Map args = {}; - args.putIfAbsent("direction", () => direction?.toNativeValue()); - args.putIfAbsent( - "previouslyFocusedRect", - () => previouslyFocusedRect?.toMap(), - ); - return await channel?.invokeMethod('requestFocus', args); - } - - @override - Future clearFocus() async { - Map args = {}; - return await channel?.invokeMethod('clearFocus', args); - } - - @override - Future showInputMethod() async { - Map args = {}; - return await channel?.invokeMethod('showInputMethod', args); - } - - @override - Future hideInputMethod() async { - Map args = {}; - return await channel?.invokeMethod('hideInputMethod', args); - } - - @override - Future setContextMenu(ContextMenu? contextMenu) async { - Map args = {}; - args.putIfAbsent("contextMenu", () => contextMenu?.toMap()); - await channel?.invokeMethod('setContextMenu', args); - _inAppBrowser?.setContextMenu(contextMenu); - } - - @override - Future requestFocusNodeHref() async { - Map args = {}; - Map? result = await channel?.invokeMethod( - 'requestFocusNodeHref', - args, - ); - return result != null - ? RequestFocusNodeHrefResult( - url: result['url'] != null ? WebUri(result['url']) : null, - title: result['title'], - src: result['src'], - ) - : null; - } - - @override - Future requestImageRef() async { - Map args = {}; - Map? result = await channel?.invokeMethod( - 'requestImageRef', - args, - ); - return result != null - ? RequestImageRefResult( - url: result['url'] != null ? WebUri(result['url']) : null, - ) - : null; - } - - @override - Future> getMetaTags() async { - List metaTags = []; - - List>? metaTagList = (await evaluateJavascript( - source: """ -(function() { - var metaTags = []; - var metaTagNodes = document.head.getElementsByTagName('meta'); - for (var i = 0; i < metaTagNodes.length; i++) { - var metaTagNode = metaTagNodes[i]; - - var otherAttributes = metaTagNode.getAttributeNames(); - var nameIndex = otherAttributes.indexOf("name"); - if (nameIndex !== -1) otherAttributes.splice(nameIndex, 1); - var contentIndex = otherAttributes.indexOf("content"); - if (contentIndex !== -1) otherAttributes.splice(contentIndex, 1); - - var attrs = []; - for (var j = 0; j < otherAttributes.length; j++) { - var otherAttribute = otherAttributes[j]; - attrs.push( - { - name: otherAttribute, - value: metaTagNode.getAttribute(otherAttribute) - } - ); - } - - metaTags.push( - { - name: metaTagNode.name, - content: metaTagNode.content, - attrs: attrs - } - ); - } - return metaTags; -})(); - """, - ))?.cast>(); - - if (metaTagList == null) { - return metaTags; - } - - for (var metaTag in metaTagList) { - var attrs = []; - - for (var metaTagAttr in metaTag["attrs"]) { - attrs.add( - MetaTagAttribute( - name: metaTagAttr["name"], - value: metaTagAttr["value"], - ), - ); - } - - metaTags.add( - MetaTag( - name: metaTag["name"], - content: metaTag["content"], - attrs: attrs, - ), - ); - } - - return metaTags; - } - - @override - Future getMetaThemeColor() async { - Color? themeColor; - - try { - Map args = {}; - themeColor = UtilColor.fromStringRepresentation( - await channel?.invokeMethod('getMetaThemeColor', args), - ); - return themeColor; - } catch (e) { - // not implemented - } - - // try using javascript - var metaTags = await getMetaTags(); - MetaTag? metaTagThemeColor; - - for (var metaTag in metaTags) { - if (metaTag.name == "theme-color") { - metaTagThemeColor = metaTag; - break; - } - } - - if (metaTagThemeColor == null) { - return null; - } - - var colorValue = metaTagThemeColor.content; - - themeColor = colorValue != null - ? UtilColor.fromStringRepresentation(colorValue) - : null; - - return themeColor; - } - - @override - Future getScrollX() async { - Map args = {}; - return await channel?.invokeMethod('getScrollX', args); - } - - @override - Future getScrollY() async { - Map args = {}; - return await channel?.invokeMethod('getScrollY', args); - } - - @override - Future getCertificate() async { - Map args = {}; - Map? sslCertificateMap = (await channel?.invokeMethod( - 'getCertificate', - args, - ))?.cast(); - return SslCertificate.fromMap(sslCertificateMap); - } - - @override - Future addUserScript({required UserScript userScript}) async { - Map args = {}; - args.putIfAbsent('userScript', () => userScript.toMap()); - if (!(_userScripts[userScript.injectionTime]?.contains(userScript) ?? - false)) { - _userScripts[userScript.injectionTime]?.add(userScript); - await channel?.invokeMethod('addUserScript', args); - } - } - - @override - Future addUserScripts({required List userScripts}) async { - for (var i = 0; i < userScripts.length; i++) { - await addUserScript(userScript: userScripts[i]); - } - } - - @override - Future removeUserScript({required UserScript userScript}) async { - var index = _userScripts[userScript.injectionTime]?.indexOf(userScript); - if (index == null || index == -1) { - return false; - } - - _userScripts[userScript.injectionTime]?.remove(userScript); - Map args = {}; - args.putIfAbsent('userScript', () => userScript.toMap()); - args.putIfAbsent('index', () => index); - await channel?.invokeMethod('removeUserScript', args); - - return true; - } - - @override - Future removeUserScriptsByGroupName({required String groupName}) async { - final List userScriptsAtDocumentStart = List.from( - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_START] ?? [], - ); - for (final userScript in userScriptsAtDocumentStart) { - if (userScript.groupName == groupName) { - _userScripts[userScript.injectionTime]?.remove(userScript); - } - } - - final List userScriptsAtDocumentEnd = List.from( - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_END] ?? [], - ); - for (final userScript in userScriptsAtDocumentEnd) { - if (userScript.groupName == groupName) { - _userScripts[userScript.injectionTime]?.remove(userScript); - } - } - - Map args = {}; - args.putIfAbsent('groupName', () => groupName); - await channel?.invokeMethod('removeUserScriptsByGroupName', args); - } - - @override - Future removeUserScripts({ - required List userScripts, - }) async { - for (final userScript in userScripts) { - await removeUserScript(userScript: userScript); - } - } - - @override - Future removeAllUserScripts() async { - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.clear(); - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.clear(); - - Map args = {}; - await channel?.invokeMethod('removeAllUserScripts', args); - } - - @override - bool hasUserScript({required UserScript userScript}) { - return _userScripts[userScript.injectionTime]?.contains(userScript) ?? - false; - } - - @override - Future callAsyncJavaScript({ - required String functionBody, - Map arguments = const {}, - ContentWorld? contentWorld, - }) async { - Map args = {}; - args.putIfAbsent('functionBody', () => functionBody); - args.putIfAbsent('arguments', () => arguments); - args.putIfAbsent('contentWorld', () => contentWorld?.toMap()); - var data = await channel?.invokeMethod('callAsyncJavaScript', args); - if (data == null) { - return null; - } - data = json.decode(data); - return CallAsyncJavaScriptResult( - value: data["value"], - error: data["error"], - ); - } - - @override - Future saveWebArchive({ - required String filePath, - bool autoname = false, - }) async { - if (!autoname) { - assert( - WebArchiveFormat.MHT.isSupported() && - filePath.endsWith("." + WebArchiveFormat.MHT.toNativeValue()!), - ); - } - - Map args = {}; - args.putIfAbsent("filePath", () => filePath); - args.putIfAbsent("autoname", () => autoname); - return await channel?.invokeMethod('saveWebArchive', args); - } - - @override - Future isSecureContext() async { - Map args = {}; - return await channel?.invokeMethod('isSecureContext', args) ?? false; - } - - @override - Future createWebMessageChannel() async { - Map args = {}; - Map? result = (await channel?.invokeMethod( - 'createWebMessageChannel', - args, - ))?.cast(); - final webMessageChannel = AndroidWebMessageChannel.static().fromMap(result); - if (webMessageChannel != null) { - _webMessageChannels.add(webMessageChannel); - } - return webMessageChannel; - } - - @override - Future postWebMessage({ - required WebMessage message, - WebUri? targetOrigin, - }) async { - if (targetOrigin == null) { - targetOrigin = WebUri(''); - } - Map args = {}; - args.putIfAbsent('message', () => message.toMap()); - args.putIfAbsent('targetOrigin', () => targetOrigin.toString()); - await channel?.invokeMethod('postWebMessage', args); - } - - @override - Future addWebMessageListener( - PlatformWebMessageListener webMessageListener, - ) async { - assert( - !_webMessageListeners.contains(webMessageListener), - "${webMessageListener} was already added.", - ); - assert( - !_webMessageListenerObjNames.contains( - webMessageListener.params.jsObjectName, - ), - "jsObjectName ${webMessageListener.params.jsObjectName} was already added.", - ); - _webMessageListeners.add(webMessageListener as AndroidWebMessageListener); - _webMessageListenerObjNames.add(webMessageListener.params.jsObjectName); - - Map args = {}; - args.putIfAbsent('webMessageListener', () => webMessageListener.toMap()); - await channel?.invokeMethod('addWebMessageListener', args); - } - - @override - bool hasWebMessageListener(PlatformWebMessageListener webMessageListener) { - return _webMessageListeners.contains(webMessageListener) || - _webMessageListenerObjNames.contains( - webMessageListener.params.jsObjectName, - ); - } - - @override - Future canScrollVertically() async { - Map args = {}; - return await channel?.invokeMethod('canScrollVertically', args) ?? - false; - } - - @override - Future canScrollHorizontally() async { - Map args = {}; - return await channel?.invokeMethod('canScrollHorizontally', args) ?? - false; - } - - @override - Future startSafeBrowsing() async { - Map args = {}; - return await channel?.invokeMethod('startSafeBrowsing', args) ?? - false; - } - - @override - Future clearSslPreferences() async { - Map args = {}; - await channel?.invokeMethod('clearSslPreferences', args); - } - - @override - Future pause() async { - Map args = {}; - await channel?.invokeMethod('pause', args); - } - - @override - Future resume() async { - Map args = {}; - await channel?.invokeMethod('resume', args); - } - - @override - Future pageDown({required bool bottom}) async { - Map args = {}; - args.putIfAbsent("bottom", () => bottom); - return await channel?.invokeMethod('pageDown', args) ?? false; - } - - @override - Future pageUp({required bool top}) async { - Map args = {}; - args.putIfAbsent("top", () => top); - return await channel?.invokeMethod('pageUp', args) ?? false; - } - - @override - Future zoomIn() async { - Map args = {}; - return await channel?.invokeMethod('zoomIn', args) ?? false; - } - - @override - Future zoomOut() async { - Map args = {}; - return await channel?.invokeMethod('zoomOut', args) ?? false; - } - - @override - Future clearHistory() async { - Map args = {}; - return await channel?.invokeMethod('clearHistory', args); - } - - @override - Future isInFullscreen() async { - Map args = {}; - return await channel?.invokeMethod('isInFullscreen', args) ?? false; - } - - @override - Future clearFormData() async { - Map args = {}; - return await channel?.invokeMethod('clearFormData', args); - } - - @override - Future saveState() async { - Map args = {}; - return await channel?.invokeMethod('saveState', args); - } - - @override - Future restoreState(Uint8List? state) async { - Map args = {}; - args.putIfAbsent('state', () => state); - return await channel?.invokeMethod('restoreState', args) ?? false; - } - - @override - Future getDefaultUserAgent() async { - Map args = {}; - return await _staticChannel.invokeMethod( - 'getDefaultUserAgent', - args, - ) ?? - ''; - } - - @override - Future clearClientCertPreferences() async { - Map args = {}; - await _staticChannel.invokeMethod('clearClientCertPreferences', args); - } - - @override - Future getSafeBrowsingPrivacyPolicyUrl() async { - Map args = {}; - String? url = await _staticChannel.invokeMethod( - 'getSafeBrowsingPrivacyPolicyUrl', - args, - ); - return url != null ? WebUri(url) : null; - } - - @override - @Deprecated("Use setSafeBrowsingAllowlist instead") - Future setSafeBrowsingWhitelist({required List hosts}) async { - return await setSafeBrowsingAllowlist(hosts: hosts); - } - - @override - Future setSafeBrowsingAllowlist({required List hosts}) async { - Map args = {}; - args.putIfAbsent('hosts', () => hosts); - return await _staticChannel.invokeMethod( - 'setSafeBrowsingAllowlist', - args, - ) ?? - false; - } - - @override - Future getCurrentWebViewPackage() async { - Map args = {}; - Map? packageInfo = (await _staticChannel.invokeMethod( - 'getCurrentWebViewPackage', - args, - ))?.cast(); - return WebViewPackageInfo.fromMap(packageInfo); - } - - @override - Future setWebContentsDebuggingEnabled(bool debuggingEnabled) async { - Map args = {}; - args.putIfAbsent('debuggingEnabled', () => debuggingEnabled); - return await _staticChannel.invokeMethod( - 'setWebContentsDebuggingEnabled', - args, - ); - } - - @override - Future getVariationsHeader() async { - Map args = {}; - return await _staticChannel.invokeMethod( - 'getVariationsHeader', - args, - ); - } - - @override - Future isMultiProcessEnabled() async { - Map args = {}; - return await _staticChannel.invokeMethod( - 'isMultiProcessEnabled', - args, - ) ?? - false; - } - - @override - Future disableWebView() async { - Map args = {}; - await _staticChannel.invokeMethod('disableWebView', args); - } - - @override - Future disposeKeepAlive(InAppWebViewKeepAlive keepAlive) async { - Map args = {}; - args.putIfAbsent('keepAliveId', () => keepAlive.id); - await _staticChannel.invokeMethod('disposeKeepAlive', args); - _keepAliveMap[keepAlive] = null; - } - - @override - Future clearAllCache({bool includeDiskFiles = true}) async { - Map args = {}; - args.putIfAbsent('includeDiskFiles', () => includeDiskFiles); - await _staticChannel.invokeMethod('clearAllCache', args); - } - - @override - Future enableSlowWholeDocumentDraw() async { - Map args = {}; - await _staticChannel.invokeMethod('enableSlowWholeDocumentDraw', args); - } - - @override - Future setJavaScriptBridgeName(String bridgeName) async { - assert( - RegExp(r'^[a-zA-Z_]\w*$').hasMatch(bridgeName), - 'bridgeName must be a non-empty string with only alphanumeric and underscore characters. It can\'t start with a number.', - ); - Map args = {}; - args.putIfAbsent('bridgeName', () => bridgeName); - await _staticChannel.invokeMethod('setJavaScriptBridgeName', args); - } - - @override - Future getJavaScriptBridgeName() async { - Map args = {}; - return await _staticChannel.invokeMethod( - 'getJavaScriptBridgeName', - args, - ) ?? - ''; - } - - @override - Future get tRexRunnerHtml async => await rootBundle.loadString( - 'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html', - ); - - @override - Future get tRexRunnerCss async => await rootBundle.loadString( - 'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.css', - ); - - @override - dynamic getViewId() { - return id; - } - - @override - void dispose({bool isKeepAlive = false}) { - disposeChannel(removeMethodCallHandler: !isKeepAlive); - _inAppBrowser = null; - webStorage.dispose(); - if (!isKeepAlive) { - _controllerFromPlatform = null; - _javaScriptHandlersMap.clear(); - _userScripts.clear(); - _webMessageListenerObjNames.clear(); - _injectedScriptsFromURL.clear(); - for (final webMessageChannel in _webMessageChannels) { - webMessageChannel.dispose(); - } - _webMessageChannels.clear(); - for (final webMessageListener in _webMessageListeners) { - webMessageListener.dispose(); - } - _webMessageListeners.clear(); - } - } -} - -extension InternalInAppWebViewController on AndroidInAppWebViewController { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_android/lib/src/in_app_webview/main.dart b/flutter_inappwebview_android/lib/src/in_app_webview/main.dart deleted file mode 100644 index b83b0611e7..0000000000 --- a/flutter_inappwebview_android/lib/src/in_app_webview/main.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'in_app_webview_controller.dart' hide InternalInAppWebViewController; -export 'in_app_webview.dart'; -export 'headless_in_app_webview.dart' hide InternalHeadlessInAppWebView; diff --git a/flutter_inappwebview_android/lib/src/inappwebview_platform.dart b/flutter_inappwebview_android/lib/src/inappwebview_platform.dart deleted file mode 100644 index 0b1990a439..0000000000 --- a/flutter_inappwebview_android/lib/src/inappwebview_platform.dart +++ /dev/null @@ -1,654 +0,0 @@ -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import 'chrome_safari_browser/chrome_safari_browser.dart'; -import 'cookie_manager.dart'; -import 'find_interaction/main.dart'; -import 'http_auth_credentials_database.dart'; -import 'in_app_browser/in_app_browser.dart'; -import 'in_app_webview/main.dart'; -import 'print_job/main.dart'; -import 'process_global_config.dart'; -import 'proxy_controller.dart'; -import 'pull_to_refresh/main.dart'; -import 'service_worker_controller.dart'; -import 'tracing_controller.dart'; -import 'web_message/main.dart'; -import 'web_storage/main.dart'; -import 'webview_asset_loader.dart'; -import 'webview_feature.dart' as wv; - -/// Implementation of [InAppWebViewPlatform] using the WebView API. -class AndroidInAppWebViewPlatform extends InAppWebViewPlatform { - /// Registers this class as the default instance of [InAppWebViewPlatform]. - static void registerWith() { - InAppWebViewPlatform.instance = AndroidInAppWebViewPlatform(); - } - - /// Creates a new [AndroidCookieManager]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [CookieManager] in `flutter_inappwebview` instead. - @override - AndroidCookieManager createPlatformCookieManager( - PlatformCookieManagerCreationParams params, - ) { - return AndroidCookieManager(params); - } - - /// Creates a new empty [AndroidCookieManager] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [CookieManager] in `flutter_inappwebview` instead. - @override - AndroidCookieManager createPlatformCookieManagerStatic() { - return AndroidCookieManager.static(); - } - - /// Creates a new [AndroidInAppWebViewController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebViewController] in `flutter_inappwebview` instead. - @override - AndroidInAppWebViewController createPlatformInAppWebViewController( - PlatformInAppWebViewControllerCreationParams params, - ) { - return AndroidInAppWebViewController(params); - } - - /// Creates a new empty [AndroidInAppWebViewController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebViewController] in `flutter_inappwebview` instead. - @override - AndroidInAppWebViewController createPlatformInAppWebViewControllerStatic() { - return AndroidInAppWebViewController.static(); - } - - /// Creates a new [AndroidInAppWebViewWidget]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebView] in `flutter_inappwebview` instead. - @override - AndroidInAppWebViewWidget createPlatformInAppWebViewWidget( - PlatformInAppWebViewWidgetCreationParams params, - ) { - return AndroidInAppWebViewWidget(params); - } - - /// Creates a new empty [AndroidInAppWebViewWidget] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebView] in `flutter_inappwebview` instead. - @override - AndroidInAppWebViewWidget createPlatformInAppWebViewWidgetStatic() { - return AndroidInAppWebViewWidget.static(); - } - - /// Creates a new [AndroidFindInteractionController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [FindInteractionController] in `flutter_inappwebview` instead. - @override - AndroidFindInteractionController createPlatformFindInteractionController( - PlatformFindInteractionControllerCreationParams params, - ) { - return AndroidFindInteractionController(params); - } - - /// Creates a new empty [AndroidFindInteractionController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [FindInteractionController] in `flutter_inappwebview` instead. - @override - AndroidFindInteractionController - createPlatformFindInteractionControllerStatic() { - return AndroidFindInteractionController.static(); - } - - /// Creates a new [AndroidPrintJobController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [PrintJobController] in `flutter_inappwebview` instead. - @override - AndroidPrintJobController createPlatformPrintJobController( - PlatformPrintJobControllerCreationParams params, - ) { - return AndroidPrintJobController(params); - } - - /// Creates a new empty [PlatformPrintJobController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [PrintJobController] in `flutter_inappwebview` instead. - @override - AndroidPrintJobController createPlatformPrintJobControllerStatic() { - return AndroidPrintJobController.static(); - } - - /// Creates a new [AndroidPullToRefreshController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [PullToRefreshController] in `flutter_inappwebview` instead. - @override - AndroidPullToRefreshController createPlatformPullToRefreshController( - PlatformPullToRefreshControllerCreationParams params, - ) { - return AndroidPullToRefreshController(params); - } - - /// Creates a new empty [AndroidPullToRefreshController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [PullToRefreshController] in `flutter_inappwebview` instead. - @override - AndroidPullToRefreshController createPlatformPullToRefreshControllerStatic() { - return AndroidPullToRefreshController.static(); - } - - /// Creates a new [AndroidWebMessageChannel]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebMessageChannel] in `flutter_inappwebview` instead. - @override - AndroidWebMessageChannel createPlatformWebMessageChannel( - PlatformWebMessageChannelCreationParams params, - ) { - return AndroidWebMessageChannel(params); - } - - /// Creates a new empty [AndroidWebMessageChannel] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebMessageChannel] in `flutter_inappwebview` instead. - @override - AndroidWebMessageChannel createPlatformWebMessageChannelStatic() { - return AndroidWebMessageChannel.static(); - } - - /// Creates a new [AndroidWebMessageListener]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebMessageListener] in `flutter_inappwebview` instead. - @override - AndroidWebMessageListener createPlatformWebMessageListener( - PlatformWebMessageListenerCreationParams params, - ) { - return AndroidWebMessageListener(params); - } - - /// Creates a new empty [AndroidWebMessageListener] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebMessageListener] in `flutter_inappwebview` instead. - @override - AndroidWebMessageListener createPlatformWebMessageListenerStatic() { - return AndroidWebMessageListener.static(); - } - - /// Creates a new [AndroidJavaScriptReplyProxy]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [JavaScriptReplyProxy] in `flutter_inappwebview` instead. - @override - AndroidJavaScriptReplyProxy createPlatformJavaScriptReplyProxy( - PlatformJavaScriptReplyProxyCreationParams params, - ) { - return AndroidJavaScriptReplyProxy(params); - } - - /// Creates a new [AndroidWebMessagePort]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebMessagePort] in `flutter_inappwebview` instead. - @override - AndroidWebMessagePort createPlatformWebMessagePort( - PlatformWebMessagePortCreationParams params, - ) { - return AndroidWebMessagePort(params); - } - - /// Creates a new [AndroidWebStorage]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebStorage] in `flutter_inappwebview` instead. - @override - AndroidWebStorage createPlatformWebStorage( - PlatformWebStorageCreationParams params, - ) { - return AndroidWebStorage(params); - } - - /// Creates a new empty [AndroidWebStorage] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebStorage] in `flutter_inappwebview` instead. - @override - AndroidWebStorage createPlatformWebStorageStatic() { - return AndroidWebStorage( - AndroidWebStorageCreationParams( - localStorage: createPlatformLocalStorageStatic(), - sessionStorage: createPlatformSessionStorageStatic(), - ), - ); - } - - /// Creates a new [AndroidLocalStorage]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [LocalStorage] in `flutter_inappwebview` instead. - @override - AndroidLocalStorage createPlatformLocalStorage( - PlatformLocalStorageCreationParams params, - ) { - return AndroidLocalStorage(params); - } - - /// Creates a new empty [AndroidLocalStorage] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [LocalStorage] in `flutter_inappwebview` instead. - @override - AndroidLocalStorage createPlatformLocalStorageStatic() { - return AndroidLocalStorage.defaultStorage(controller: null); - } - - /// Creates a new [AndroidSessionStorage]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [SessionStorage] in `flutter_inappwebview` instead. - @override - AndroidSessionStorage createPlatformSessionStorage( - PlatformSessionStorageCreationParams params, - ) { - return AndroidSessionStorage(params); - } - - /// Creates a new empty [AndroidSessionStorage] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [SessionStorage] in `flutter_inappwebview` instead. - @override - AndroidSessionStorage createPlatformSessionStorageStatic() { - return AndroidSessionStorage.defaultStorage(controller: null); - } - - /// Creates a new [AndroidHeadlessInAppWebView]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [HeadlessInAppWebView] in `flutter_inappwebview` instead. - @override - AndroidHeadlessInAppWebView createPlatformHeadlessInAppWebView( - PlatformHeadlessInAppWebViewCreationParams params, - ) { - return AndroidHeadlessInAppWebView(params); - } - - /// Creates a new empty [AndroidHeadlessInAppWebView] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [HeadlessInAppWebView] in `flutter_inappwebview` instead. - @override - AndroidHeadlessInAppWebView createPlatformHeadlessInAppWebViewStatic() { - return AndroidHeadlessInAppWebView.static(); - } - - /// Creates a new [AndroidHttpAuthCredentialDatabase]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [HttpAuthCredentialDatabase] in `flutter_inappwebview` instead. - @override - AndroidHttpAuthCredentialDatabase createPlatformHttpAuthCredentialDatabase( - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) { - return AndroidHttpAuthCredentialDatabase(params); - } - - /// Creates a new empty [AndroidHttpAuthCredentialDatabase] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [HttpAuthCredentialDatabase] in `flutter_inappwebview` instead. - @override - AndroidHttpAuthCredentialDatabase - createPlatformHttpAuthCredentialDatabaseStatic() { - return AndroidHttpAuthCredentialDatabase.static(); - } - - /// Creates a new [AndroidInAppBrowser]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppBrowser] in `flutter_inappwebview` instead. - @override - AndroidInAppBrowser createPlatformInAppBrowser( - PlatformInAppBrowserCreationParams params, - ) { - return AndroidInAppBrowser(params); - } - - /// Creates a new empty [AndroidInAppBrowser] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppBrowser] in `flutter_inappwebview` instead. - @override - AndroidInAppBrowser createPlatformInAppBrowserStatic() { - return AndroidInAppBrowser.static(); - } - - /// Creates a new [AndroidProcessGlobalConfig]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ProcessGlobalConfig] in `flutter_inappwebview` instead. - @override - AndroidProcessGlobalConfig createPlatformProcessGlobalConfig( - PlatformProcessGlobalConfigCreationParams params, - ) { - return AndroidProcessGlobalConfig(params); - } - - /// Creates a new empty [AndroidProcessGlobalConfig] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ProcessGlobalConfig] in `flutter_inappwebview` instead. - @override - AndroidProcessGlobalConfig createPlatformProcessGlobalConfigStatic() { - return AndroidProcessGlobalConfig.static(); - } - - /// Creates a new [AndroidProxyController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ProxyController] in `flutter_inappwebview` instead. - @override - AndroidProxyController createPlatformProxyController( - PlatformProxyControllerCreationParams params, - ) { - return AndroidProxyController(params); - } - - /// Creates a new empty [AndroidProxyController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ProxyController] in `flutter_inappwebview` instead. - @override - AndroidProxyController createPlatformProxyControllerStatic() { - return AndroidProxyController.static(); - } - - /// Creates a new [AndroidServiceWorkerController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ServiceWorkerController] in `flutter_inappwebview` instead. - @override - AndroidServiceWorkerController createPlatformServiceWorkerController( - PlatformServiceWorkerControllerCreationParams params, - ) { - return AndroidServiceWorkerController(params); - } - - /// Creates a new empty [AndroidServiceWorkerController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ServiceWorkerController] in `flutter_inappwebview` instead. - @override - AndroidServiceWorkerController createPlatformServiceWorkerControllerStatic() { - return AndroidServiceWorkerController.static(); - } - - /// Creates a new [AndroidTracingController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [TracingController] in `flutter_inappwebview` instead. - @override - AndroidTracingController createPlatformTracingController( - PlatformTracingControllerCreationParams params, - ) { - return AndroidTracingController(params); - } - - /// Creates a new empty [AndroidTracingController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [TracingController] in `flutter_inappwebview` instead. - @override - AndroidTracingController createPlatformTracingControllerStatic() { - return AndroidTracingController.static(); - } - - /// Creates a new [AndroidAssetsPathHandler]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [AssetsPathHandler] in `flutter_inappwebview` instead. - @override - AndroidAssetsPathHandler createPlatformAssetsPathHandler( - PlatformAssetsPathHandlerCreationParams params, - ) { - return AndroidAssetsPathHandler(params); - } - - /// Creates a new [AndroidResourcesPathHandler]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ResourcesPathHandler] in `flutter_inappwebview` instead. - @override - AndroidResourcesPathHandler createPlatformResourcesPathHandler( - PlatformResourcesPathHandlerCreationParams params, - ) { - return AndroidResourcesPathHandler(params); - } - - /// Creates a new [AndroidInternalStoragePathHandler]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InternalStoragePathHandler] in `flutter_inappwebview` instead. - @override - AndroidInternalStoragePathHandler createPlatformInternalStoragePathHandler( - PlatformInternalStoragePathHandlerCreationParams params, - ) { - return AndroidInternalStoragePathHandler(params); - } - - /// Creates a new [AndroidCustomPathHandler]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [CustomPathHandler] in `flutter_inappwebview` instead. - @override - AndroidCustomPathHandler createPlatformCustomPathHandler( - PlatformCustomPathHandlerCreationParams params, - ) { - return AndroidCustomPathHandler(params); - } - - /// Creates a new empty [AndroidAssetsPathHandler] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [AssetsPathHandler] in `flutter_inappwebview` instead. - @override - AndroidAssetsPathHandler createPlatformAssetsPathHandlerStatic() { - return AndroidAssetsPathHandler.static(); - } - - /// Creates a new empty [AndroidResourcesPathHandler] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ResourcesPathHandler] in `flutter_inappwebview` instead. - @override - AndroidResourcesPathHandler createPlatformResourcesPathHandlerStatic() { - return AndroidResourcesPathHandler.static(); - } - - /// Creates a new empty [AndroidInternalStoragePathHandler] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InternalStoragePathHandler] in `flutter_inappwebview` instead. - @override - AndroidInternalStoragePathHandler - createPlatformInternalStoragePathHandlerStatic() { - return AndroidInternalStoragePathHandler.static(); - } - - /// Creates a new empty [AndroidCustomPathHandler] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [CustomPathHandler] in `flutter_inappwebview` instead. - @override - AndroidCustomPathHandler createPlatformCustomPathHandlerStatic() { - return AndroidCustomPathHandler.static(); - } - - /// Creates a new [wv.AndroidWebViewFeature]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebViewFeature] in `flutter_inappwebview` instead. - @override - wv.AndroidWebViewFeature createPlatformWebViewFeature( - PlatformWebViewFeatureCreationParams params, - ) { - return wv.AndroidWebViewFeature(params); - } - - /// Creates a new empty [wv.AndroidWebViewFeature] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebViewFeature] in `flutter_inappwebview` instead. - @override - wv.AndroidWebViewFeature createPlatformWebViewFeatureStatic() { - return wv.AndroidWebViewFeature.static(); - } - - /// Creates a new [AndroidChromeSafariBrowser]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ChromeSafariBrowser] in `flutter_inappwebview` instead. - @override - AndroidChromeSafariBrowser createPlatformChromeSafariBrowser( - PlatformChromeSafariBrowserCreationParams params, - ) { - return AndroidChromeSafariBrowser(params); - } - - /// Creates a new empty [AndroidChromeSafariBrowser] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ChromeSafariBrowser] in `flutter_inappwebview` instead. - @override - AndroidChromeSafariBrowser createPlatformChromeSafariBrowserStatic() { - return AndroidChromeSafariBrowser.static(); - } - - /// Creates a new empty [AndroidWebStorageManager] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebStorageManager] in `flutter_inappwebview` instead. - @override - AndroidWebStorageManager createPlatformWebStorageManager( - PlatformWebStorageManagerCreationParams params, - ) { - return AndroidWebStorageManager(params); - } - - /// Creates a new empty [AndroidWebStorageManager] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebStorageManager] in `flutter_inappwebview` instead. - @override - AndroidWebStorageManager createPlatformWebStorageManagerStatic() { - return AndroidWebStorageManager.static(); - } - - /// Creates a new [DefaultInAppLocalhostServer]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppLocalhostServer] in `flutter_inappwebview` instead. - @override - DefaultInAppLocalhostServer createPlatformInAppLocalhostServer( - PlatformInAppLocalhostServerCreationParams params, - ) { - return DefaultInAppLocalhostServer(params); - } - - /// Creates a new empty [DefaultInAppLocalhostServer] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppLocalhostServer] in `flutter_inappwebview` instead. - @override - DefaultInAppLocalhostServer createPlatformInAppLocalhostServerStatic() { - return DefaultInAppLocalhostServer.static(); - } - - // ************************************************************************ // - // Create static instances of unsupported classes to be able to call // - // isClassSupported, isMethodSupported, isPropertySupported, etc. // - // static methods without throwing a missing platform implementation // - // exception. // - // ************************************************************************ // - - /// Creates a new empty [PlatformWebViewEnvironment] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebViewEnvironment] in `flutter_inappwebview` instead. - @override - PlatformWebViewEnvironment createPlatformWebViewEnvironmentStatic() { - return _PlatformWebViewEnvironment.static(); - } - - /// Creates a new empty [PlatformWebAuthenticationSession] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebAuthenticationSession] in `flutter_inappwebview` instead. - @override - PlatformWebAuthenticationSession - createPlatformWebAuthenticationSessionStatic() { - return _PlatformWebAuthenticationSession.static(); - } - - /// Creates a new empty [PlatformWebNotificationController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebNotificationController] in `flutter_inappwebview` instead. - @override - PlatformWebNotificationController - createPlatformWebNotificationControllerStatic() { - return _PlatformWebNotificationController.static(); - } -} - -class _PlatformWebAuthenticationSession - extends PlatformWebAuthenticationSession { - _PlatformWebAuthenticationSession( - PlatformWebAuthenticationSessionCreationParams params, - ) : super.implementation(params); - - static final _PlatformWebAuthenticationSession _staticValue = - _PlatformWebAuthenticationSession( - const PlatformWebAuthenticationSessionCreationParams(), - ); - - factory _PlatformWebAuthenticationSession.static() => _staticValue; -} - -class _PlatformWebViewEnvironment extends PlatformWebViewEnvironment { - _PlatformWebViewEnvironment(PlatformWebViewEnvironmentCreationParams params) - : super.implementation(params); - static final _PlatformWebViewEnvironment _staticValue = - _PlatformWebViewEnvironment( - const PlatformWebViewEnvironmentCreationParams(), - ); - - factory _PlatformWebViewEnvironment.static() => _staticValue; -} - -class _PlatformWebNotificationController - extends PlatformWebNotificationController { - _PlatformWebNotificationController( - PlatformWebNotificationControllerCreationParams params, - ) : super.implementation(params); - - static final _PlatformWebNotificationController _staticValue = - _PlatformWebNotificationController( - PlatformWebNotificationControllerCreationParams( - id: '', - notification: WebNotification(), - ), - ); - - factory _PlatformWebNotificationController.static() => _staticValue; -} diff --git a/flutter_inappwebview_android/lib/src/main.dart b/flutter_inappwebview_android/lib/src/main.dart deleted file mode 100644 index b49714ad73..0000000000 --- a/flutter_inappwebview_android/lib/src/main.dart +++ /dev/null @@ -1,18 +0,0 @@ -export 'inappwebview_platform.dart'; -export 'in_app_webview/main.dart'; -export 'in_app_browser/main.dart'; -export 'chrome_safari_browser/main.dart'; -export 'web_storage/main.dart'; -export 'cookie_manager.dart' hide InternalCookieManager; -export 'http_auth_credentials_database.dart' - hide InternalHttpAuthCredentialDatabase; -export 'pull_to_refresh/main.dart'; -export 'web_message/main.dart'; -export 'print_job/main.dart'; -export 'find_interaction/main.dart'; -export 'service_worker_controller.dart'; -export 'webview_feature.dart' hide InternalWebViewFeature; -export 'proxy_controller.dart' hide InternalProxyController; -export 'webview_asset_loader.dart'; -export 'tracing_controller.dart' hide InternalTracingController; -export 'process_global_config.dart' hide InternalProcessGlobalConfig; diff --git a/flutter_inappwebview_android/lib/src/platform_util.dart b/flutter_inappwebview_android/lib/src/platform_util.dart deleted file mode 100644 index e52ccbd8cc..0000000000 --- a/flutter_inappwebview_android/lib/src/platform_util.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'package:flutter/services.dart'; - -///Platform native utilities -class PlatformUtil { - static PlatformUtil? _instance; - static const MethodChannel _channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_platformutil', - ); - - PlatformUtil._(); - - ///Get [PlatformUtil] instance. - static PlatformUtil instance() { - return (_instance != null) ? _instance! : _init(); - } - - static PlatformUtil _init() { - _channel.setMethodCallHandler((call) async { - try { - return await _handleMethod(call); - } on Error catch (e) { - print(e); - print(e.stackTrace); - } - }); - _instance = PlatformUtil._(); - return _instance!; - } - - static Future _handleMethod(MethodCall call) async {} - - String? _cachedSystemVersion; - - ///Get current platform system version. - Future getSystemVersion() async { - if (_cachedSystemVersion != null) { - return _cachedSystemVersion!; - } - Map args = {}; - _cachedSystemVersion = await _channel.invokeMethod( - 'getSystemVersion', - args, - ); - return _cachedSystemVersion!; - } - - ///Format date. - Future formatDate({ - required DateTime date, - required String format, - String locale = "en_US", - String timezone = "UTC", - }) async { - Map args = {}; - args.putIfAbsent('date', () => date.millisecondsSinceEpoch); - args.putIfAbsent('format', () => format); - args.putIfAbsent('locale', () => locale); - args.putIfAbsent('timezone', () => timezone); - return await _channel.invokeMethod('formatDate', args); - } - - ///Get cookie expiration date used by Web platform. - Future getWebCookieExpirationDate({required DateTime date}) async { - Map args = {}; - args.putIfAbsent('date', () => date.millisecondsSinceEpoch); - return await _channel.invokeMethod('getWebCookieExpirationDate', args); - } -} diff --git a/flutter_inappwebview_android/lib/src/print_job/main.dart b/flutter_inappwebview_android/lib/src/print_job/main.dart deleted file mode 100644 index 4e70ad9405..0000000000 --- a/flutter_inappwebview_android/lib/src/print_job/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'print_job_controller.dart'; diff --git a/flutter_inappwebview_android/lib/src/print_job/print_job_controller.dart b/flutter_inappwebview_android/lib/src/print_job/print_job_controller.dart deleted file mode 100644 index ee3e2365ec..0000000000 --- a/flutter_inappwebview_android/lib/src/print_job/print_job_controller.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [AndroidPrintJobController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformPrintJobControllerCreationParams] for -/// more information. -@immutable -class AndroidPrintJobControllerCreationParams - extends PlatformPrintJobControllerCreationParams { - /// Creates a new [AndroidPrintJobControllerCreationParams] instance. - const AndroidPrintJobControllerCreationParams({required super.id}); - - /// Creates a [AndroidPrintJobControllerCreationParams] instance based on [PlatformPrintJobControllerCreationParams]. - factory AndroidPrintJobControllerCreationParams.fromPlatformPrintJobControllerCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformPrintJobControllerCreationParams params, - ) { - return AndroidPrintJobControllerCreationParams(id: params.id); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController} -class AndroidPrintJobController extends PlatformPrintJobController - with ChannelController { - /// Constructs a [AndroidPrintJobController]. - AndroidPrintJobController(PlatformPrintJobControllerCreationParams params) - : super.implementation( - params is AndroidPrintJobControllerCreationParams - ? params - : AndroidPrintJobControllerCreationParams.fromPlatformPrintJobControllerCreationParams( - params, - ), - ) { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_printjobcontroller_${params.id}', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - static final AndroidPrintJobController _staticValue = - AndroidPrintJobController( - AndroidPrintJobControllerCreationParams(id: ''), - ); - - /// Provide static access. - factory AndroidPrintJobController.static() { - return _staticValue; - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onComplete": - bool completed = call.arguments["completed"]; - String? error = call.arguments["error"]; - onComplete?.call(completed, error); - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - } - - @override - Future cancel() async { - Map args = {}; - await channel?.invokeMethod('cancel', args); - } - - @override - Future restart() async { - Map args = {}; - await channel?.invokeMethod('restart', args); - } - - @override - Future getInfo() async { - Map args = {}; - Map? infoMap = (await channel?.invokeMethod( - 'getInfo', - args, - ))?.cast(); - return PrintJobInfo.fromMap(infoMap); - } - - @override - Future dispose() async { - Map args = {}; - await channel?.invokeMethod('dispose', args); - disposeChannel(); - } -} diff --git a/flutter_inappwebview_android/lib/src/process_global_config.dart b/flutter_inappwebview_android/lib/src/process_global_config.dart deleted file mode 100644 index f66362bc89..0000000000 --- a/flutter_inappwebview_android/lib/src/process_global_config.dart +++ /dev/null @@ -1,94 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [AndroidProcessGlobalConfig]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformProcessGlobalConfigCreationParams] for -/// more information. -@immutable -class AndroidProcessGlobalConfigCreationParams - extends PlatformProcessGlobalConfigCreationParams { - /// Creates a new [AndroidProcessGlobalConfigCreationParams] instance. - const AndroidProcessGlobalConfigCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformProcessGlobalConfigCreationParams params, - ) : super(); - - /// Creates a [AndroidProcessGlobalConfigCreationParams] instance based on [PlatformProcessGlobalConfigCreationParams]. - factory AndroidProcessGlobalConfigCreationParams.fromPlatformProcessGlobalConfigCreationParams( - PlatformProcessGlobalConfigCreationParams params, - ) { - return AndroidProcessGlobalConfigCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformProcessGlobalConfig} -class AndroidProcessGlobalConfig extends PlatformProcessGlobalConfig - with ChannelController { - /// Creates a new [AndroidProcessGlobalConfig]. - AndroidProcessGlobalConfig(PlatformProcessGlobalConfigCreationParams params) - : super.implementation( - params is AndroidProcessGlobalConfigCreationParams - ? params - : AndroidProcessGlobalConfigCreationParams.fromPlatformProcessGlobalConfigCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_processglobalconfig', - ); - handler = handleMethod; - initMethodCallHandler(); - } - - static AndroidProcessGlobalConfig? _instance; - - ///Gets the [AndroidProcessGlobalConfig] shared instance. - static AndroidProcessGlobalConfig instance() { - return (_instance != null) ? _instance! : _init(); - } - - static AndroidProcessGlobalConfig _init() { - _instance = AndroidProcessGlobalConfig( - AndroidProcessGlobalConfigCreationParams( - const PlatformProcessGlobalConfigCreationParams(), - ), - ); - return _instance!; - } - - static final AndroidProcessGlobalConfig _staticValue = - AndroidProcessGlobalConfig( - AndroidProcessGlobalConfigCreationParams( - const PlatformProcessGlobalConfigCreationParams(), - ), - ); - - /// Provide static access. - factory AndroidProcessGlobalConfig.static() { - return _staticValue; - } - - Future _handleMethod(MethodCall call) async {} - - @override - Future apply({required ProcessGlobalConfigSettings settings}) async { - Map args = {}; - args.putIfAbsent("settings", () => settings.toMap()); - await channel?.invokeMethod('apply', args); - } - - @override - void dispose() { - // empty - } -} - -extension InternalProcessGlobalConfig on AndroidProcessGlobalConfig { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_android/lib/src/proxy_controller.dart b/flutter_inappwebview_android/lib/src/proxy_controller.dart deleted file mode 100644 index cc71946032..0000000000 --- a/flutter_inappwebview_android/lib/src/proxy_controller.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [AndroidProxyController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformProxyControllerCreationParams] for -/// more information. -@immutable -class AndroidProxyControllerCreationParams - extends PlatformProxyControllerCreationParams { - /// Creates a new [AndroidProxyControllerCreationParams] instance. - const AndroidProxyControllerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformProxyControllerCreationParams params, - ) : super(); - - /// Creates a [AndroidProxyControllerCreationParams] instance based on [PlatformProxyControllerCreationParams]. - factory AndroidProxyControllerCreationParams.fromPlatformProxyControllerCreationParams( - PlatformProxyControllerCreationParams params, - ) { - return AndroidProxyControllerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformProxyController} -class AndroidProxyController extends PlatformProxyController - with ChannelController { - /// Creates a new [AndroidProxyController]. - AndroidProxyController(PlatformProxyControllerCreationParams params) - : super.implementation( - params is AndroidProxyControllerCreationParams - ? params - : AndroidProxyControllerCreationParams.fromPlatformProxyControllerCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_proxycontroller', - ); - handler = handleMethod; - initMethodCallHandler(); - } - - static AndroidProxyController? _instance; - - ///Gets the [AndroidProxyController] shared instance. - static AndroidProxyController instance() { - return (_instance != null) ? _instance! : _init(); - } - - static AndroidProxyController _init() { - _instance = AndroidProxyController( - AndroidProxyControllerCreationParams( - const PlatformProxyControllerCreationParams(), - ), - ); - return _instance!; - } - - static final AndroidProxyController _staticValue = AndroidProxyController( - AndroidProxyControllerCreationParams( - const PlatformProxyControllerCreationParams(), - ), - ); - - /// Provide static access. - factory AndroidProxyController.static() { - return _staticValue; - } - - Future _handleMethod(MethodCall call) async {} - - @override - Future setProxyOverride({required ProxySettings settings}) async { - Map args = {}; - args.putIfAbsent("settings", () => settings.toMap()); - await channel?.invokeMethod('setProxyOverride', args); - } - - @override - Future clearProxyOverride() async { - Map args = {}; - await channel?.invokeMethod('clearProxyOverride', args); - } - - @override - void dispose() { - // empty - } -} - -extension InternalProxyController on AndroidProxyController { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_android/lib/src/pull_to_refresh/main.dart b/flutter_inappwebview_android/lib/src/pull_to_refresh/main.dart deleted file mode 100644 index 586af9d873..0000000000 --- a/flutter_inappwebview_android/lib/src/pull_to_refresh/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'pull_to_refresh_controller.dart' hide InternalPullToRefreshController; diff --git a/flutter_inappwebview_android/lib/src/pull_to_refresh/pull_to_refresh_controller.dart b/flutter_inappwebview_android/lib/src/pull_to_refresh/pull_to_refresh_controller.dart deleted file mode 100644 index 9e166a5bbb..0000000000 --- a/flutter_inappwebview_android/lib/src/pull_to_refresh/pull_to_refresh_controller.dart +++ /dev/null @@ -1,183 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [AndroidPullToRefreshController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformPullToRefreshControllerCreationParams] for -/// more information. -class AndroidPullToRefreshControllerCreationParams - extends PlatformPullToRefreshControllerCreationParams { - /// Creates a new [AndroidPullToRefreshControllerCreationParams] instance. - AndroidPullToRefreshControllerCreationParams({ - super.onRefresh, - super.options, - super.settings, - }); - - /// Creates a [AndroidPullToRefreshControllerCreationParams] instance based on [PlatformPullToRefreshControllerCreationParams]. - factory AndroidPullToRefreshControllerCreationParams.fromPlatformPullToRefreshControllerCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformPullToRefreshControllerCreationParams params, - ) { - return AndroidPullToRefreshControllerCreationParams( - onRefresh: params.onRefresh, - options: params.options, - settings: params.settings, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController} -class AndroidPullToRefreshController extends PlatformPullToRefreshController - with ChannelController { - /// Constructs a [AndroidPullToRefreshController]. - AndroidPullToRefreshController( - PlatformPullToRefreshControllerCreationParams params, - ) : super.implementation( - params is AndroidPullToRefreshControllerCreationParams - ? params - : AndroidPullToRefreshControllerCreationParams.fromPlatformPullToRefreshControllerCreationParams( - params, - ), - ); - - static final AndroidPullToRefreshController _staticValue = - AndroidPullToRefreshController( - AndroidPullToRefreshControllerCreationParams(), - ); - - /// Provide static access. - factory AndroidPullToRefreshController.static() { - return _staticValue; - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - debugLoggingSettings: - PlatformPullToRefreshController.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - _debugLog(call.method, call.arguments); - - switch (call.method) { - case "onRefresh": - if (params.onRefresh != null) params.onRefresh!(); - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - Future setEnabled(bool enabled) async { - Map args = {}; - args.putIfAbsent('enabled', () => enabled); - await channel?.invokeMethod('setEnabled', args); - } - - @override - Future isEnabled() async { - Map args = {}; - return await channel?.invokeMethod('isEnabled', args) ?? false; - } - - Future _setRefreshing(bool refreshing) async { - Map args = {}; - args.putIfAbsent('refreshing', () => refreshing); - await channel?.invokeMethod('setRefreshing', args); - } - - @override - Future beginRefreshing() async { - return await _setRefreshing(true); - } - - @override - Future endRefreshing() async { - await _setRefreshing(false); - } - - @override - Future isRefreshing() async { - Map args = {}; - return await channel?.invokeMethod('isRefreshing', args) ?? false; - } - - @override - Future setColor(Color color) async { - Map args = {}; - args.putIfAbsent('color', () => color.toHex()); - await channel?.invokeMethod('setColor', args); - } - - @override - Future setBackgroundColor(Color color) async { - Map args = {}; - args.putIfAbsent('color', () => color.toHex()); - await channel?.invokeMethod('setBackgroundColor', args); - } - - @override - Future setDistanceToTriggerSync(int distanceToTriggerSync) async { - Map args = {}; - args.putIfAbsent('distanceToTriggerSync', () => distanceToTriggerSync); - await channel?.invokeMethod('setDistanceToTriggerSync', args); - } - - @override - Future setSlingshotDistance(int slingshotDistance) async { - Map args = {}; - args.putIfAbsent('slingshotDistance', () => slingshotDistance); - await channel?.invokeMethod('setSlingshotDistance', args); - } - - @override - Future getDefaultSlingshotDistance() async { - Map args = {}; - return await channel?.invokeMethod( - 'getDefaultSlingshotDistance', - args, - ) ?? - 0; - } - - @Deprecated("Use setIndicatorSize instead") - @override - Future setSize(AndroidPullToRefreshSize size) async { - Map args = {}; - args.putIfAbsent('size', () => size.toNativeValue()); - await channel?.invokeMethod('setSize', args); - } - - @override - Future setIndicatorSize(PullToRefreshSize size) async { - Map args = {}; - args.putIfAbsent('size', () => size.toNativeValue()); - await channel?.invokeMethod('setSize', args); - } - - @override - void dispose({bool isKeepAlive = false}) { - disposeChannel(removeMethodCallHandler: !isKeepAlive); - } -} - -extension InternalPullToRefreshController on AndroidPullToRefreshController { - void init(dynamic id) { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_$id', - ); - handler = _handleMethod; - initMethodCallHandler(); - } -} diff --git a/flutter_inappwebview_android/lib/src/service_worker_controller.dart b/flutter_inappwebview_android/lib/src/service_worker_controller.dart deleted file mode 100644 index a78f5196a2..0000000000 --- a/flutter_inappwebview_android/lib/src/service_worker_controller.dart +++ /dev/null @@ -1,168 +0,0 @@ -import 'dart:async'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [AndroidServiceWorkerController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformServiceWorkerControllerCreationParams] for -/// more information. -@immutable -class AndroidServiceWorkerControllerCreationParams - extends PlatformServiceWorkerControllerCreationParams { - /// Creates a new [AndroidServiceWorkerControllerCreationParams] instance. - const AndroidServiceWorkerControllerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformServiceWorkerControllerCreationParams params, - ) : super(); - - /// Creates a [AndroidServiceWorkerControllerCreationParams] instance based on [PlatformServiceWorkerControllerCreationParams]. - factory AndroidServiceWorkerControllerCreationParams.fromPlatformServiceWorkerControllerCreationParams( - PlatformServiceWorkerControllerCreationParams params, - ) { - return AndroidServiceWorkerControllerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformServiceWorkerController} -class AndroidServiceWorkerController extends PlatformServiceWorkerController - with ChannelController { - /// Creates a new [AndroidServiceWorkerController]. - AndroidServiceWorkerController( - PlatformServiceWorkerControllerCreationParams params, - ) : super.implementation( - params is AndroidServiceWorkerControllerCreationParams - ? params - : AndroidServiceWorkerControllerCreationParams.fromPlatformServiceWorkerControllerCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_serviceworkercontroller', - ); - handler = handleMethod; - initMethodCallHandler(); - } - - factory AndroidServiceWorkerController.static() { - return instance(); - } - - static AndroidServiceWorkerController? _instance; - - ///Gets the [AndroidServiceWorkerController] shared instance. - static AndroidServiceWorkerController instance() { - return (_instance != null) ? _instance! : _init(); - } - - static AndroidServiceWorkerController _init() { - _instance = AndroidServiceWorkerController( - AndroidServiceWorkerControllerCreationParams( - const PlatformServiceWorkerControllerCreationParams(), - ), - ); - return _instance!; - } - - ServiceWorkerClient? _serviceWorkerClient; - - @override - ServiceWorkerClient? get serviceWorkerClient => _serviceWorkerClient; - - @override - Future setServiceWorkerClient(ServiceWorkerClient? value) async { - Map args = {}; - args.putIfAbsent('isNull', () => value == null); - await channel?.invokeMethod("setServiceWorkerClient", args); - _serviceWorkerClient = value; - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "shouldInterceptRequest": - if (serviceWorkerClient != null && - serviceWorkerClient!.shouldInterceptRequest != null) { - Map arguments = call.arguments - .cast(); - WebResourceRequest request = WebResourceRequest.fromMap(arguments)!; - - return (await serviceWorkerClient!.shouldInterceptRequest!( - request, - ))?.toMap(); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - - return null; - } - - @override - Future getAllowContentAccess() async { - Map args = {}; - return await channel?.invokeMethod('getAllowContentAccess', args) ?? - false; - } - - @override - Future getAllowFileAccess() async { - Map args = {}; - return await channel?.invokeMethod('getAllowFileAccess', args) ?? - false; - } - - @override - Future getBlockNetworkLoads() async { - Map args = {}; - return await channel?.invokeMethod('getBlockNetworkLoads', args) ?? - false; - } - - @override - Future getCacheMode() async { - Map args = {}; - return CacheMode.fromNativeValue( - await channel?.invokeMethod('getCacheMode', args), - ); - } - - @override - Future setAllowContentAccess(bool allow) async { - Map args = {}; - args.putIfAbsent("allow", () => allow); - await channel?.invokeMethod('setAllowContentAccess', args); - } - - @override - Future setAllowFileAccess(bool allow) async { - Map args = {}; - args.putIfAbsent("allow", () => allow); - await channel?.invokeMethod('setAllowFileAccess', args); - } - - @override - Future setBlockNetworkLoads(bool flag) async { - Map args = {}; - args.putIfAbsent("flag", () => flag); - await channel?.invokeMethod('setBlockNetworkLoads', args); - } - - @override - Future setCacheMode(CacheMode mode) async { - Map args = {}; - args.putIfAbsent("mode", () => mode.toNativeValue()); - await channel?.invokeMethod('setCacheMode', args); - } - - @override - void dispose() { - // empty - } -} - -extension InternalServiceWorkerController on AndroidServiceWorkerController { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_android/lib/src/tracing_controller.dart b/flutter_inappwebview_android/lib/src/tracing_controller.dart deleted file mode 100644 index dd6beca46d..0000000000 --- a/flutter_inappwebview_android/lib/src/tracing_controller.dart +++ /dev/null @@ -1,105 +0,0 @@ -import 'dart:async'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [AndroidTracingController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformTracingControllerCreationParams] for -/// more information. -@immutable -class AndroidTracingControllerCreationParams - extends PlatformTracingControllerCreationParams { - /// Creates a new [AndroidTracingControllerCreationParams] instance. - const AndroidTracingControllerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformTracingControllerCreationParams params, - ) : super(); - - /// Creates a [AndroidTracingControllerCreationParams] instance based on [PlatformTracingControllerCreationParams]. - factory AndroidTracingControllerCreationParams.fromPlatformTracingControllerCreationParams( - PlatformTracingControllerCreationParams params, - ) { - return AndroidTracingControllerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformTracingController} -class AndroidTracingController extends PlatformTracingController - with ChannelController { - /// Creates a new [AndroidTracingController]. - AndroidTracingController(PlatformTracingControllerCreationParams params) - : super.implementation( - params is AndroidTracingControllerCreationParams - ? params - : AndroidTracingControllerCreationParams.fromPlatformTracingControllerCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_tracingcontroller', - ); - handler = handleMethod; - initMethodCallHandler(); - } - - static AndroidTracingController? _instance; - - ///Gets the [AndroidTracingController] shared instance. - static AndroidTracingController instance() { - return (_instance != null) ? _instance! : _init(); - } - - static AndroidTracingController _init() { - _instance = AndroidTracingController( - AndroidTracingControllerCreationParams( - const PlatformTracingControllerCreationParams(), - ), - ); - return _instance!; - } - - static final AndroidTracingController _staticValue = AndroidTracingController( - AndroidTracingControllerCreationParams( - const PlatformTracingControllerCreationParams(), - ), - ); - - /// Provide static access. - factory AndroidTracingController.static() { - return _staticValue; - } - - Future _handleMethod(MethodCall call) async {} - - @override - Future start({required TracingSettings settings}) async { - Map args = {}; - args.putIfAbsent("settings", () => settings.toMap()); - await channel?.invokeMethod('start', args); - } - - @override - Future stop({String? filePath}) async { - Map args = {}; - args.putIfAbsent("filePath", () => filePath); - return await channel?.invokeMethod('stop', args) ?? false; - } - - @override - Future isTracing() async { - Map args = {}; - return await channel?.invokeMethod('isTracing', args) ?? false; - } - - @override - void dispose() { - // empty - } -} - -extension InternalTracingController on AndroidTracingController { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_android/lib/src/web_message/main.dart b/flutter_inappwebview_android/lib/src/web_message/main.dart deleted file mode 100644 index d41e30c755..0000000000 --- a/flutter_inappwebview_android/lib/src/web_message/main.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'web_message_port.dart' hide InternalWebMessagePort; -export 'web_message_channel.dart' hide InternalWebMessageChannel; -export 'web_message_listener.dart'; diff --git a/flutter_inappwebview_android/lib/src/web_message/web_message_channel.dart b/flutter_inappwebview_android/lib/src/web_message/web_message_channel.dart deleted file mode 100644 index 961fb99d64..0000000000 --- a/flutter_inappwebview_android/lib/src/web_message/web_message_channel.dart +++ /dev/null @@ -1,138 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import 'web_message_port.dart'; - -/// Object specifying creation parameters for creating a [AndroidWebMessageChannel]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebMessageChannelCreationParams] for -/// more information. -@immutable -class AndroidWebMessageChannelCreationParams - extends PlatformWebMessageChannelCreationParams { - /// Creates a new [AndroidWebMessageChannelCreationParams] instance. - const AndroidWebMessageChannelCreationParams({ - required super.id, - required super.port1, - required super.port2, - }); - - /// Creates a [AndroidWebMessageChannelCreationParams] instance based on [PlatformWebMessageChannelCreationParams]. - factory AndroidWebMessageChannelCreationParams.fromPlatformWebMessageChannelCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebMessageChannelCreationParams params, - ) { - return AndroidWebMessageChannelCreationParams( - id: params.id, - port1: params.port1, - port2: params.port2, - ); - } - - @override - String toString() { - return 'AndroidWebMessageChannelCreationParams{id: $id, port1: $port1, port2: $port2}'; - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel} -class AndroidWebMessageChannel extends PlatformWebMessageChannel - with ChannelController { - /// Constructs a [AndroidWebMessageChannel]. - AndroidWebMessageChannel(PlatformWebMessageChannelCreationParams params) - : super.implementation( - params is AndroidWebMessageChannelCreationParams - ? params - : AndroidWebMessageChannelCreationParams.fromPlatformWebMessageChannelCreationParams( - params, - ), - ) { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_web_message_channel_${params.id}', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - static final AndroidWebMessageChannel _staticValue = AndroidWebMessageChannel( - AndroidWebMessageChannelCreationParams( - id: '', - port1: AndroidWebMessagePort( - AndroidWebMessagePortCreationParams(index: 0), - ), - port2: AndroidWebMessagePort( - AndroidWebMessagePortCreationParams(index: 1), - ), - ), - ); - - /// Provide static access. - factory AndroidWebMessageChannel.static() { - return _staticValue; - } - - AndroidWebMessagePort get _androidPort1 => port1 as AndroidWebMessagePort; - - AndroidWebMessagePort get _androidPort2 => port2 as AndroidWebMessagePort; - - static AndroidWebMessageChannel? _fromMap(Map? map) { - if (map == null) { - return null; - } - var webMessageChannel = AndroidWebMessageChannel( - AndroidWebMessageChannelCreationParams( - id: map["id"], - port1: AndroidWebMessagePort( - AndroidWebMessagePortCreationParams(index: 0), - ), - port2: AndroidWebMessagePort( - AndroidWebMessagePortCreationParams(index: 1), - ), - ), - ); - webMessageChannel._androidPort1.webMessageChannel = webMessageChannel; - webMessageChannel._androidPort2.webMessageChannel = webMessageChannel; - return webMessageChannel; - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onMessage": - int index = call.arguments["index"]; - var port = index == 0 ? _androidPort1 : _androidPort2; - if (port.onMessage != null) { - WebMessage? message = call.arguments["message"] != null - ? WebMessage.fromMap( - call.arguments["message"].cast(), - ) - : null; - port.onMessage!(message); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - AndroidWebMessageChannel? fromMap(Map? map) { - return _fromMap(map); - } - - @override - void dispose() { - disposeChannel(); - } - - @override - String toString() { - return 'AndroidWebMessageChannel{id: $id, port1: $port1, port2: $port2}'; - } -} - -extension InternalWebMessageChannel on AndroidWebMessageChannel { - MethodChannel? get internalChannel => channel; -} diff --git a/flutter_inappwebview_android/lib/src/web_message/web_message_listener.dart b/flutter_inappwebview_android/lib/src/web_message/web_message_listener.dart deleted file mode 100644 index efe8765201..0000000000 --- a/flutter_inappwebview_android/lib/src/web_message/web_message_listener.dart +++ /dev/null @@ -1,191 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [AndroidWebMessageListener]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebMessageListenerCreationParams] for -/// more information. -@immutable -class AndroidWebMessageListenerCreationParams - extends PlatformWebMessageListenerCreationParams { - /// Creates a new [AndroidWebMessageListenerCreationParams] instance. - const AndroidWebMessageListenerCreationParams({ - required this.allowedOriginRules, - required super.jsObjectName, - super.onPostMessage, - }); - - /// Creates a [AndroidWebMessageListenerCreationParams] instance based on [PlatformWebMessageListenerCreationParams]. - factory AndroidWebMessageListenerCreationParams.fromPlatformWebMessageListenerCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebMessageListenerCreationParams params, - ) { - return AndroidWebMessageListenerCreationParams( - allowedOriginRules: params.allowedOriginRules ?? Set.from(["*"]), - jsObjectName: params.jsObjectName, - onPostMessage: params.onPostMessage, - ); - } - - @override - final Set allowedOriginRules; - - @override - String toString() { - return 'AndroidWebMessageListenerCreationParams{jsObjectName: $jsObjectName, allowedOriginRules: $allowedOriginRules, onPostMessage: $onPostMessage}'; - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener} -class AndroidWebMessageListener extends PlatformWebMessageListener - with ChannelController { - /// Constructs a [AndroidWebMessageListener]. - AndroidWebMessageListener(PlatformWebMessageListenerCreationParams params) - : super.implementation( - params is AndroidWebMessageListenerCreationParams - ? params - : AndroidWebMessageListenerCreationParams.fromPlatformWebMessageListenerCreationParams( - params, - ), - ) { - assert( - !this._androidParams.allowedOriginRules.contains(""), - "allowedOriginRules cannot contain empty strings", - ); - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_web_message_listener_${_id}_${params.jsObjectName}', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - static final AndroidWebMessageListener _staticValue = - AndroidWebMessageListener( - AndroidWebMessageListenerCreationParams( - jsObjectName: '', - allowedOriginRules: Set.from(["*"]), - ), - ); - - /// Provide static access. - factory AndroidWebMessageListener.static() { - return _staticValue; - } - - ///Message Listener ID used internally. - final String _id = IdGenerator.generate(); - - AndroidJavaScriptReplyProxy? _replyProxy; - - AndroidWebMessageListenerCreationParams get _androidParams => - params as AndroidWebMessageListenerCreationParams; - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onPostMessage": - if (_replyProxy == null) { - _replyProxy = AndroidJavaScriptReplyProxy( - PlatformJavaScriptReplyProxyCreationParams( - webMessageListener: this, - ), - ); - } - if (onPostMessage != null) { - WebMessage? message = call.arguments["message"] != null - ? WebMessage.fromMap( - call.arguments["message"].cast(), - ) - : null; - WebUri? sourceOrigin = call.arguments["sourceOrigin"] != null - ? WebUri(call.arguments["sourceOrigin"]) - : null; - bool isMainFrame = call.arguments["isMainFrame"]; - onPostMessage!(message, sourceOrigin, isMainFrame, _replyProxy!); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - void dispose() { - disposeChannel(); - } - - @override - Map toMap() { - return { - "id": _id, - "jsObjectName": params.jsObjectName, - "allowedOriginRules": _androidParams.allowedOriginRules.toList(), - }; - } - - @override - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return 'AndroidWebMessageListener{id: ${_id}, jsObjectName: ${params.jsObjectName}, allowedOriginRules: ${params.allowedOriginRules}, replyProxy: $_replyProxy}'; - } -} - -/// Object specifying creation parameters for creating a [AndroidJavaScriptReplyProxy]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformJavaScriptReplyProxyCreationParams] for -/// more information. -@immutable -class AndroidJavaScriptReplyProxyCreationParams - extends PlatformJavaScriptReplyProxyCreationParams { - /// Creates a new [AndroidJavaScriptReplyProxyCreationParams] instance. - const AndroidJavaScriptReplyProxyCreationParams({ - required super.webMessageListener, - }); - - /// Creates a [AndroidJavaScriptReplyProxyCreationParams] instance based on [PlatformJavaScriptReplyProxyCreationParams]. - factory AndroidJavaScriptReplyProxyCreationParams.fromPlatformJavaScriptReplyProxyCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformJavaScriptReplyProxyCreationParams params, - ) { - return AndroidJavaScriptReplyProxyCreationParams( - webMessageListener: params.webMessageListener, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.JavaScriptReplyProxy} -class AndroidJavaScriptReplyProxy extends PlatformJavaScriptReplyProxy { - /// Constructs a [AndroidWebMessageListener]. - AndroidJavaScriptReplyProxy(PlatformJavaScriptReplyProxyCreationParams params) - : super.implementation( - params is AndroidJavaScriptReplyProxyCreationParams - ? params - : AndroidJavaScriptReplyProxyCreationParams.fromPlatformJavaScriptReplyProxyCreationParams( - params, - ), - ); - - AndroidWebMessageListener get _androidWebMessageListener => - params.webMessageListener as AndroidWebMessageListener; - - @override - Future postMessage(WebMessage message) async { - Map args = {}; - args.putIfAbsent('message', () => message.toMap()); - await _androidWebMessageListener.channel?.invokeMethod('postMessage', args); - } - - @override - String toString() { - return 'AndroidJavaScriptReplyProxy{}'; - } -} diff --git a/flutter_inappwebview_android/lib/src/web_message/web_message_port.dart b/flutter_inappwebview_android/lib/src/web_message/web_message_port.dart deleted file mode 100644 index e47451a866..0000000000 --- a/flutter_inappwebview_android/lib/src/web_message/web_message_port.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import 'web_message_channel.dart'; - -/// Object specifying creation parameters for creating a [AndroidWebMessagePort]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebMessagePortCreationParams] for -/// more information. -@immutable -class AndroidWebMessagePortCreationParams - extends PlatformWebMessagePortCreationParams { - /// Creates a new [AndroidWebMessagePortCreationParams] instance. - const AndroidWebMessagePortCreationParams({required super.index}); - - /// Creates a [AndroidWebMessagePortCreationParams] instance based on [PlatformWebMessagePortCreationParams]. - factory AndroidWebMessagePortCreationParams.fromPlatformWebMessagePortCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebMessagePortCreationParams params, - ) { - return AndroidWebMessagePortCreationParams(index: params.index); - } - - @override - String toString() { - return 'AndroidWebMessagePortCreationParams{index: $index}'; - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessagePort} -class AndroidWebMessagePort extends PlatformWebMessagePort { - WebMessageCallback? _onMessage; - late AndroidWebMessageChannel _webMessageChannel; - - /// Constructs a [AndroidWebMessagePort]. - AndroidWebMessagePort(PlatformWebMessagePortCreationParams params) - : super.implementation( - params is AndroidWebMessagePortCreationParams - ? params - : AndroidWebMessagePortCreationParams.fromPlatformWebMessagePortCreationParams( - params, - ), - ); - - @override - Future setWebMessageCallback(WebMessageCallback? onMessage) async { - Map args = {}; - args.putIfAbsent('index', () => params.index); - await _webMessageChannel.internalChannel?.invokeMethod( - 'setWebMessageCallback', - args, - ); - this._onMessage = onMessage; - } - - @override - Future postMessage(WebMessage message) async { - Map args = {}; - args.putIfAbsent('index', () => params.index); - args.putIfAbsent('message', () => message.toMap()); - await _webMessageChannel.internalChannel?.invokeMethod('postMessage', args); - } - - @override - Future close() async { - Map args = {}; - args.putIfAbsent('index', () => params.index); - await _webMessageChannel.internalChannel?.invokeMethod('close', args); - } - - @override - Map toMap({EnumMethod? enumMethod}) { - return { - "index": params.index, - "webMessageChannelId": this._webMessageChannel.params.id, - }; - } - - @override - Map toJson() { - return toMap(); - } - - @override - String toString() { - return 'AndroidWebMessagePort{index: ${params.index}}'; - } -} - -extension InternalWebMessagePort on AndroidWebMessagePort { - WebMessageCallback? get onMessage => _onMessage; - void set onMessage(WebMessageCallback? value) => _onMessage = value; - - AndroidWebMessageChannel get webMessageChannel => _webMessageChannel; - void set webMessageChannel(AndroidWebMessageChannel value) => - _webMessageChannel = value; -} diff --git a/flutter_inappwebview_android/lib/src/web_storage/main.dart b/flutter_inappwebview_android/lib/src/web_storage/main.dart deleted file mode 100644 index dab327ba6d..0000000000 --- a/flutter_inappwebview_android/lib/src/web_storage/main.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'web_storage.dart'; -export 'web_storage_manager.dart'; diff --git a/flutter_inappwebview_android/lib/src/web_storage/web_storage.dart b/flutter_inappwebview_android/lib/src/web_storage/web_storage.dart deleted file mode 100644 index 3705a70013..0000000000 --- a/flutter_inappwebview_android/lib/src/web_storage/web_storage.dart +++ /dev/null @@ -1,306 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../in_app_webview/in_app_webview_controller.dart'; - -/// Object specifying creation parameters for creating a [AndroidWebStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebStorageCreationParams] for -/// more information. -class AndroidWebStorageCreationParams extends PlatformWebStorageCreationParams { - /// Creates a new [AndroidWebStorageCreationParams] instance. - AndroidWebStorageCreationParams({ - required super.localStorage, - required super.sessionStorage, - }); - - /// Creates a [AndroidWebStorageCreationParams] instance based on [PlatformWebStorageCreationParams]. - factory AndroidWebStorageCreationParams.fromPlatformWebStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebStorageCreationParams params, - ) { - return AndroidWebStorageCreationParams( - localStorage: params.localStorage, - sessionStorage: params.sessionStorage, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage} -class AndroidWebStorage extends PlatformWebStorage { - /// Constructs a [AndroidWebStorage]. - AndroidWebStorage(PlatformWebStorageCreationParams params) - : super.implementation( - params is AndroidWebStorageCreationParams - ? params - : AndroidWebStorageCreationParams.fromPlatformWebStorageCreationParams( - params, - ), - ); - - @override - PlatformLocalStorage get localStorage => params.localStorage; - - @override - PlatformSessionStorage get sessionStorage => params.sessionStorage; - - @override - void dispose() { - localStorage.dispose(); - sessionStorage.dispose(); - } -} - -/// Object specifying creation parameters for creating a [AndroidStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformStorageCreationParams] for -/// more information. -class AndroidStorageCreationParams extends PlatformStorageCreationParams { - /// Creates a new [AndroidStorageCreationParams] instance. - AndroidStorageCreationParams({ - required super.controller, - required super.webStorageType, - }); - - /// Creates a [AndroidStorageCreationParams] instance based on [PlatformStorageCreationParams]. - factory AndroidStorageCreationParams.fromPlatformStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformStorageCreationParams params, - ) { - return AndroidStorageCreationParams( - controller: params.controller, - webStorageType: params.webStorageType, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformStorage} -abstract mixin class AndroidStorage implements PlatformStorage { - @override - AndroidInAppWebViewController? controller; - - @override - Future length() async { - var result = await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.length; - """, - ); - return result != null ? int.parse(json.decode(result)) : null; - } - - @override - Future setItem({required String key, required dynamic value}) async { - var encodedValue = json.encode(value); - await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.setItem("$key", ${value is String ? encodedValue : "JSON.stringify($encodedValue)"}); - """, - ); - } - - @override - Future getItem({required String key}) async { - var itemValue = await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.getItem("$key"); - """, - ); - - if (itemValue == null) { - return null; - } - - try { - return json.decode(itemValue); - } catch (e) {} - - return itemValue; - } - - @override - Future removeItem({required String key}) async { - await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.removeItem("$key"); - """, - ); - } - - @override - Future> getItems() async { - var webStorageItems = []; - - List>? items = (await controller?.evaluateJavascript( - source: - """ -(function() { - var webStorageItems = []; - for(var i = 0; i < window.$webStorageType.length; i++){ - var key = window.$webStorageType.key(i); - webStorageItems.push( - { - key: key, - value: window.$webStorageType.getItem(key) - } - ); - } - return webStorageItems; -})(); - """, - ))?.cast>(); - - if (items == null) { - return webStorageItems; - } - - for (var item in items) { - webStorageItems.add( - WebStorageItem(key: item["key"], value: item["value"]), - ); - } - - return webStorageItems; - } - - @override - Future clear() async { - await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.clear(); - """, - ); - } - - @override - Future key({required int index}) async { - var result = await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.key($index); - """, - ); - return result != null ? json.decode(result) : null; - } - - @override - void dispose() { - controller = null; - } -} - -/// Object specifying creation parameters for creating a [AndroidLocalStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformLocalStorageCreationParams] for -/// more information. -class AndroidLocalStorageCreationParams - extends PlatformLocalStorageCreationParams { - /// Creates a new [AndroidLocalStorageCreationParams] instance. - AndroidLocalStorageCreationParams(super.params); - - /// Creates a [AndroidLocalStorageCreationParams] instance based on [PlatformLocalStorageCreationParams]. - factory AndroidLocalStorageCreationParams.fromPlatformLocalStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformLocalStorageCreationParams params, - ) { - return AndroidLocalStorageCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformLocalStorage} -class AndroidLocalStorage extends PlatformLocalStorage with AndroidStorage { - /// Constructs a [AndroidLocalStorage]. - AndroidLocalStorage(PlatformLocalStorageCreationParams params) - : super.implementation( - params is AndroidLocalStorageCreationParams - ? params - : AndroidLocalStorageCreationParams.fromPlatformLocalStorageCreationParams( - params, - ), - ); - - /// Default storage - factory AndroidLocalStorage.defaultStorage({ - required PlatformInAppWebViewController? controller, - }) { - return AndroidLocalStorage( - AndroidLocalStorageCreationParams( - PlatformLocalStorageCreationParams( - PlatformStorageCreationParams( - controller: controller, - webStorageType: WebStorageType.LOCAL_STORAGE, - ), - ), - ), - ); - } - - @override - AndroidInAppWebViewController? get controller => - params.controller as AndroidInAppWebViewController?; -} - -/// Object specifying creation parameters for creating a [AndroidSessionStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformSessionStorageCreationParams] for -/// more information. -class AndroidSessionStorageCreationParams - extends PlatformSessionStorageCreationParams { - /// Creates a new [AndroidSessionStorageCreationParams] instance. - AndroidSessionStorageCreationParams(super.params); - - /// Creates a [AndroidSessionStorageCreationParams] instance based on [PlatformSessionStorageCreationParams]. - factory AndroidSessionStorageCreationParams.fromPlatformSessionStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformSessionStorageCreationParams params, - ) { - return AndroidSessionStorageCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformSessionStorage} -class AndroidSessionStorage extends PlatformSessionStorage with AndroidStorage { - /// Constructs a [AndroidSessionStorage]. - AndroidSessionStorage(PlatformSessionStorageCreationParams params) - : super.implementation( - params is AndroidSessionStorageCreationParams - ? params - : AndroidSessionStorageCreationParams.fromPlatformSessionStorageCreationParams( - params, - ), - ); - - /// Default storage - factory AndroidSessionStorage.defaultStorage({ - required PlatformInAppWebViewController? controller, - }) { - return AndroidSessionStorage( - AndroidSessionStorageCreationParams( - PlatformSessionStorageCreationParams( - PlatformStorageCreationParams( - controller: controller, - webStorageType: WebStorageType.SESSION_STORAGE, - ), - ), - ), - ); - } - - @override - AndroidInAppWebViewController? get controller => - params.controller as AndroidInAppWebViewController?; -} diff --git a/flutter_inappwebview_android/lib/src/web_storage/web_storage_manager.dart b/flutter_inappwebview_android/lib/src/web_storage/web_storage_manager.dart deleted file mode 100755 index c5752270e1..0000000000 --- a/flutter_inappwebview_android/lib/src/web_storage/web_storage_manager.dart +++ /dev/null @@ -1,135 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [AndroidWebStorageManager]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebStorageManagerCreationParams] for -/// more information. -@immutable -class AndroidWebStorageManagerCreationParams - extends PlatformWebStorageManagerCreationParams { - /// Creates a new [AndroidWebStorageManagerCreationParams] instance. - const AndroidWebStorageManagerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformWebStorageManagerCreationParams params, - ) : super(); - - /// Creates a [AndroidWebStorageManagerCreationParams] instance based on [PlatformWebStorageManagerCreationParams]. - factory AndroidWebStorageManagerCreationParams.fromPlatformWebStorageManagerCreationParams( - PlatformWebStorageManagerCreationParams params, - ) { - return AndroidWebStorageManagerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager} -class AndroidWebStorageManager extends PlatformWebStorageManager - with ChannelController { - /// Creates a new [AndroidWebStorageManager]. - AndroidWebStorageManager(PlatformWebStorageManagerCreationParams params) - : super.implementation( - params is AndroidWebStorageManagerCreationParams - ? params - : AndroidWebStorageManagerCreationParams.fromPlatformWebStorageManagerCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_webstoragemanager', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - static AndroidWebStorageManager? _instance; - - ///Gets the WebStorage manager shared instance. - static AndroidWebStorageManager instance() { - return (_instance != null) ? _instance! : _init(); - } - - static AndroidWebStorageManager _init() { - _instance = AndroidWebStorageManager( - AndroidWebStorageManagerCreationParams( - const PlatformWebStorageManagerCreationParams(), - ), - ); - return _instance!; - } - - static AndroidWebStorageManager? _static; - - /// Provide static access. - factory AndroidWebStorageManager.static() { - _static ??= AndroidWebStorageManager( - AndroidWebStorageManagerCreationParams( - const PlatformWebStorageManagerCreationParams(), - ), - ); - return _static!; - } - - Future _handleMethod(MethodCall call) async {} - - @override - Future> getOrigins() async { - List originsList = []; - - Map args = {}; - List> origins = - (await channel?.invokeMethod( - 'getOrigins', - args, - ))?.cast>() ?? - []; - - for (var origin in origins) { - originsList.add( - WebStorageOrigin( - origin: origin["origin"], - quota: origin["quota"], - usage: origin["usage"], - ), - ); - } - - return originsList; - } - - @override - Future deleteAllData() async { - Map args = {}; - await channel?.invokeMethod('deleteAllData', args); - } - - @override - Future deleteOrigin({required String origin}) async { - Map args = {}; - args.putIfAbsent("origin", () => origin); - await channel?.invokeMethod('deleteOrigin', args); - } - - @override - Future getQuotaForOrigin({required String origin}) async { - Map args = {}; - args.putIfAbsent("origin", () => origin); - return await channel?.invokeMethod('getQuotaForOrigin', args) ?? 0; - } - - @override - Future getUsageForOrigin({required String origin}) async { - Map args = {}; - args.putIfAbsent("origin", () => origin); - return await channel?.invokeMethod('getUsageForOrigin', args) ?? 0; - } - - @override - void dispose() { - // empty - } -} diff --git a/flutter_inappwebview_android/lib/src/webview_asset_loader.dart b/flutter_inappwebview_android/lib/src/webview_asset_loader.dart deleted file mode 100644 index ce8ebbe126..0000000000 --- a/flutter_inappwebview_android/lib/src/webview_asset_loader.dart +++ /dev/null @@ -1,294 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [AndroidPathHandler]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformPathHandlerCreationParams] for -/// more information. -@immutable -class AndroidPathHandlerCreationParams - extends PlatformPathHandlerCreationParams { - /// Creates a new [AndroidPathHandlerCreationParams] instance. - AndroidPathHandlerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformPathHandlerCreationParams params, - ) : super(path: params.path); - - /// Creates a [AndroidPathHandlerCreationParams] instance based on [PlatformPathHandlerCreationParams]. - factory AndroidPathHandlerCreationParams.fromPlatformPathHandlerCreationParams( - PlatformPathHandlerCreationParams params, - ) { - return AndroidPathHandlerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformPathHandler} -abstract mixin class AndroidPathHandler - implements ChannelController, PlatformPathHandler { - final String _id = IdGenerator.generate(); - - @override - late final PlatformPathHandlerEvents? eventHandler; - - @override - late final String path; - - void _init(PlatformPathHandlerCreationParams params) { - this.path = params.path; - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_custompathhandler_${_id}', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "handle": - String path = call.arguments["path"]; - return (await eventHandler?.handle(path))?.toMap(); - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - } - - @override - Map toMap({EnumMethod? enumMethod}) { - return {"path": path, "type": type, "id": _id}; - } - - @override - Map toJson() { - return toMap(); - } - - @override - String toString() { - return 'AndroidPathHandler{path: $path, type: $type}'; - } - - @override - void dispose() { - disposeChannel(); - eventHandler = null; - } -} - -/// Object specifying creation parameters for creating a [AndroidAssetsPathHandler]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformAssetsPathHandlerCreationParams] for -/// more information. -@immutable -class AndroidAssetsPathHandlerCreationParams - extends PlatformAssetsPathHandlerCreationParams { - /// Creates a new [AndroidAssetsPathHandlerCreationParams] instance. - AndroidAssetsPathHandlerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformAssetsPathHandlerCreationParams params, - ) : super(params); - - /// Creates a [AndroidAssetsPathHandlerCreationParams] instance based on [PlatformAssetsPathHandlerCreationParams]. - factory AndroidAssetsPathHandlerCreationParams.fromPlatformAssetsPathHandlerCreationParams( - PlatformAssetsPathHandlerCreationParams params, - ) { - return AndroidAssetsPathHandlerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformAssetsPathHandler} -class AndroidAssetsPathHandler extends PlatformAssetsPathHandler - with AndroidPathHandler, ChannelController { - /// Constructs a [AndroidAssetsPathHandler]. - AndroidAssetsPathHandler(PlatformAssetsPathHandlerCreationParams params) - : super.implementation( - params is AndroidAssetsPathHandlerCreationParams - ? params - : AndroidAssetsPathHandlerCreationParams.fromPlatformAssetsPathHandlerCreationParams( - params, - ), - ) { - _init(params); - } - - static final AndroidAssetsPathHandler _staticValue = AndroidAssetsPathHandler( - AndroidAssetsPathHandlerCreationParams( - PlatformAssetsPathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - ), - ), - ); - - /// Creates a new empty [AndroidAssetsPathHandler] to access static methods. - factory AndroidAssetsPathHandler.static() => _staticValue; -} - -/// Object specifying creation parameters for creating a [AndroidResourcesPathHandler]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformResourcesPathHandlerCreationParams] for -/// more information. -@immutable -class AndroidResourcesPathHandlerCreationParams - extends PlatformResourcesPathHandlerCreationParams { - /// Creates a new [AndroidResourcesPathHandlerCreationParams] instance. - AndroidResourcesPathHandlerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformResourcesPathHandlerCreationParams params, - ) : super(params); - - /// Creates a [AndroidResourcesPathHandlerCreationParams] instance based on [PlatformResourcesPathHandlerCreationParams]. - factory AndroidResourcesPathHandlerCreationParams.fromPlatformResourcesPathHandlerCreationParams( - PlatformResourcesPathHandlerCreationParams params, - ) { - return AndroidResourcesPathHandlerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformResourcesPathHandler} -class AndroidResourcesPathHandler extends PlatformResourcesPathHandler - with AndroidPathHandler, ChannelController { - /// Constructs a [AndroidResourcesPathHandler]. - AndroidResourcesPathHandler(PlatformResourcesPathHandlerCreationParams params) - : super.implementation( - params is AndroidResourcesPathHandlerCreationParams - ? params - : AndroidResourcesPathHandlerCreationParams.fromPlatformResourcesPathHandlerCreationParams( - params, - ), - ) { - _init(params); - } - - static final AndroidResourcesPathHandler _staticValue = - AndroidResourcesPathHandler( - AndroidResourcesPathHandlerCreationParams( - PlatformResourcesPathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - ), - ), - ); - - /// Creates a new empty [AndroidResourcesPathHandler] to access static methods. - factory AndroidResourcesPathHandler.static() => _staticValue; -} - -/// Object specifying creation parameters for creating a [AndroidInternalStoragePathHandler]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformInternalStoragePathHandlerCreationParams] for -/// more information. -@immutable -class AndroidInternalStoragePathHandlerCreationParams - extends PlatformInternalStoragePathHandlerCreationParams { - /// Creates a new [AndroidInternalStoragePathHandlerCreationParams] instance. - AndroidInternalStoragePathHandlerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformInternalStoragePathHandlerCreationParams params, - ) : super(params, directory: params.directory); - - /// Creates a [AndroidInternalStoragePathHandlerCreationParams] instance based on [PlatformInternalStoragePathHandlerCreationParams]. - factory AndroidInternalStoragePathHandlerCreationParams.fromPlatformInternalStoragePathHandlerCreationParams( - PlatformInternalStoragePathHandlerCreationParams params, - ) { - return AndroidInternalStoragePathHandlerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformInternalStoragePathHandler} -class AndroidInternalStoragePathHandler - extends PlatformInternalStoragePathHandler - with AndroidPathHandler, ChannelController { - /// Constructs a [AndroidInternalStoragePathHandler]. - AndroidInternalStoragePathHandler( - PlatformInternalStoragePathHandlerCreationParams params, - ) : super.implementation( - params is AndroidInternalStoragePathHandlerCreationParams - ? params - : AndroidInternalStoragePathHandlerCreationParams.fromPlatformInternalStoragePathHandlerCreationParams( - params, - ), - ) { - _init(params); - } - - static final AndroidInternalStoragePathHandler _staticValue = - AndroidInternalStoragePathHandler( - AndroidInternalStoragePathHandlerCreationParams( - PlatformInternalStoragePathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - directory: '', - ), - ), - ); - - /// Creates a new empty [AndroidInternalStoragePathHandler] to access static methods. - factory AndroidInternalStoragePathHandler.static() => _staticValue; - - AndroidInternalStoragePathHandlerCreationParams get _internalParams => - params as AndroidInternalStoragePathHandlerCreationParams; - - @override - String get directory => _internalParams.directory; - - @override - Map toMap({EnumMethod? enumMethod}) { - return {...super.toMap(), 'directory': directory}; - } -} - -/// Object specifying creation parameters for creating a [AndroidCustomPathHandler]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformCustomPathHandlerCreationParams] for -/// more information. -@immutable -class AndroidCustomPathHandlerCreationParams - extends PlatformCustomPathHandlerCreationParams { - /// Creates a new [AndroidCustomPathHandlerCreationParams] instance. - AndroidCustomPathHandlerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformCustomPathHandlerCreationParams params, - ) : super(params); - - /// Creates a [AndroidCustomPathHandlerCreationParams] instance based on [PlatformCustomPathHandlerCreationParams]. - factory AndroidCustomPathHandlerCreationParams.fromPlatformCustomPathHandlerCreationParams( - PlatformCustomPathHandlerCreationParams params, - ) { - return AndroidCustomPathHandlerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformCustomPathHandler} -class AndroidCustomPathHandler extends PlatformCustomPathHandler - with AndroidPathHandler, ChannelController { - /// Constructs a [AndroidCustomPathHandler]. - AndroidCustomPathHandler(PlatformCustomPathHandlerCreationParams params) - : super.implementation( - params is AndroidCustomPathHandlerCreationParams - ? params - : AndroidCustomPathHandlerCreationParams.fromPlatformCustomPathHandlerCreationParams( - params, - ), - ) { - _init(params); - } - - static final AndroidCustomPathHandler _staticValue = AndroidCustomPathHandler( - AndroidCustomPathHandlerCreationParams( - PlatformCustomPathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - ), - ), - ); - - /// Creates a new empty [AndroidCustomPathHandler] to access static methods. - factory AndroidCustomPathHandler.static() => _staticValue; -} diff --git a/flutter_inappwebview_android/lib/src/webview_feature.dart b/flutter_inappwebview_android/lib/src/webview_feature.dart deleted file mode 100644 index 711b873299..0000000000 --- a/flutter_inappwebview_android/lib/src/webview_feature.dart +++ /dev/null @@ -1,97 +0,0 @@ -import 'dart:async'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [AndroidWebViewFeature]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebViewFeatureCreationParams] for -/// more information. -@immutable -class AndroidWebViewFeatureCreationParams - extends PlatformWebViewFeatureCreationParams { - /// Creates a new [AndroidWebViewFeatureCreationParams] instance. - const AndroidWebViewFeatureCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformWebViewFeatureCreationParams params, - ) : super(); - - /// Creates a [AndroidWebViewFeatureCreationParams] instance based on [PlatformWebViewFeatureCreationParams]. - factory AndroidWebViewFeatureCreationParams.fromPlatformWebViewFeatureCreationParams( - PlatformWebViewFeatureCreationParams params, - ) { - return AndroidWebViewFeatureCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebViewFeature} -class AndroidWebViewFeature extends PlatformWebViewFeature - with ChannelController { - /// Creates a new [AndroidWebViewFeature]. - AndroidWebViewFeature(PlatformWebViewFeatureCreationParams params) - : super.implementation( - params is AndroidWebViewFeatureCreationParams - ? params - : AndroidWebViewFeatureCreationParams.fromPlatformWebViewFeatureCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_webviewfeature', - ); - handler = handleMethod; - initMethodCallHandler(); - } - - factory AndroidWebViewFeature.static() { - return instance(); - } - - static AndroidWebViewFeature? _instance; - - ///Gets the [AndroidWebViewFeature] shared instance. - static AndroidWebViewFeature instance() { - return (_instance != null) ? _instance! : _init(); - } - - static AndroidWebViewFeature _init() { - _instance = AndroidWebViewFeature( - AndroidWebViewFeatureCreationParams( - const PlatformWebViewFeatureCreationParams(), - ), - ); - return _instance!; - } - - Future _handleMethod(MethodCall call) async {} - - @override - Future isFeatureSupported(WebViewFeature feature) async { - Map args = {}; - args.putIfAbsent("feature", () => feature.toNativeValue()); - return await channel?.invokeMethod('isFeatureSupported', args) ?? - false; - } - - @override - Future isStartupFeatureSupported(WebViewFeature startupFeature) async { - Map args = {}; - args.putIfAbsent("startupFeature", () => startupFeature.toNativeValue()); - return await channel?.invokeMethod( - 'isStartupFeatureSupported', - args, - ) ?? - false; - } - - @override - void dispose() { - // empty - } -} - -extension InternalWebViewFeature on AndroidWebViewFeature { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_android/pubspec.yaml b/flutter_inappwebview_android/pubspec.yaml deleted file mode 100644 index ff16a72863..0000000000 --- a/flutter_inappwebview_android/pubspec.yaml +++ /dev/null @@ -1,84 +0,0 @@ -name: flutter_inappwebview_android -description: Android implementation of the flutter_inappwebview plugin. -version: 1.2.0-beta.3 -homepage: https://inappwebview.dev/ -repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_android -issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues -funding: - - https://inappwebview.dev/donate/ -topics: - - html - - webview - - webview-flutter - - inappwebview - - browser - -environment: - sdk: ^3.8.0 - flutter: ">=3.32.0" - -dependencies: - flutter: - sdk: flutter - flutter_inappwebview_platform_interface: ^1.4.0-beta.3 - # path: ../flutter_inappwebview_platform_interface - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^6.0.0 - plugin_platform_interface: ^2.1.8 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - # This section identifies this Flutter project as a plugin project. - # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) - # which should be registered in the plugin registry. This is required for - # using method channels. - # The Android 'package' specifies package in which the registered class is. - # This is required for using method channels on Android. - # The 'ffiPlugin' specifies that native code should be built and bundled. - # This is required for using `dart:ffi`. - # All these are used by the tooling to maintain consistency when - # adding or updating assets for this project. - plugin: - implements: flutter_inappwebview - platforms: - android: - package: com.pichillilorenzo.flutter_inappwebview_android - pluginClass: InAppWebViewFlutterPlugin - dartPluginClass: AndroidInAppWebViewPlatform - - # To add assets to your plugin package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # To add custom fonts to your plugin package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages diff --git a/flutter_inappwebview_android/test/flutter_inappwebview_android_test.dart b/flutter_inappwebview_android/test/flutter_inappwebview_android_test.dart deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/flutter_inappwebview_ios/.gitignore b/flutter_inappwebview_ios/.gitignore deleted file mode 100644 index feb282d170..0000000000 --- a/flutter_inappwebview_ios/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock -**/doc/api/ -.dart_tool/ -.packages -build/ - -.build/ -.swiftpm/ diff --git a/flutter_inappwebview_ios/.metadata b/flutter_inappwebview_ios/.metadata deleted file mode 100644 index 1d00c64b89..0000000000 --- a/flutter_inappwebview_ios/.metadata +++ /dev/null @@ -1,30 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e" - channel: "stable" - -project_type: plugin - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - - platform: ios - create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/flutter_inappwebview_ios/CHANGELOG.md b/flutter_inappwebview_ios/CHANGELOG.md deleted file mode 100644 index 895f33ec86..0000000000 --- a/flutter_inappwebview_ios/CHANGELOG.md +++ /dev/null @@ -1,123 +0,0 @@ -## 1.2.0-beta.3 - -- Updated flutter_inappwebview_platform_interface version to ^1.4.0-beta.3 -- Implemented `saveState`, `restoreState` InAppWebViewController methods -- Implemented `PlatformProxyController` class -- Add Swift Package Manager support [#2409](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2409) -- Merged "Add proxy support for iOS" [#2362](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2362) (thanks to [yerkejs](https://github.com/yerkejs)) -- Fixed "[iOS] Webview opened with windowId does not receive javascript handler callback." [#2393](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2393) -- Fixed internal javascript callback handlers when the WebView has windowId not null -- Fixed "When useShouldInterceptAjaxRequest is true, some ajax requests doesn't work" [#2197](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2197) -- Fixed "iOS App rejected by apple for violating Guideline 2.5.1 - Performance - Software Requirements | Flutter 3.35.x seems to use non-public or deprecated APIs" [#2754](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2754) -- Fixed "InAppWebViewController.goTo" implementation -- Merged "fix #2484, Remove not-empty assert for Cookie.value" [#2486](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2486) (thanks to [laishere](https://github.com/laishere)) -- Merged "Fix gesture recognition delay prevention for latest Flutter versions" [#2538](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2538) (thanks to [muccy-timeware](https://github.com/muccy-timeware)) - -## 1.2.0-beta.2 - -- Updated flutter_inappwebview_platform_interface version to ^1.4.0-beta.2 -- Implemented `setInputMethodEnabled`, `hideInputMethod` InAppWebViewController methods -- Implemented `isUserInteractionEnabled`, `alpha` properties of `InAppWebViewSettings` -- Merged "Show / Hide / Disable / Enable soft Keyboard Input (Android & iOS)" [#2408](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2408) (thanks to [Mecharyry](https://github.com/Mecharyry)) -- Fixed "In iOS version 17.2, when moving the input focus in a WebView, an unknown area appears at the top of the screen." [#1947](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1947) - -## 1.2.0-beta.1 - -- Updated flutter_inappwebview_platform_interface version to ^1.4.0-beta.1 -- Implemented `requestFocus` WebView method -- Updated ConsoleLogJS internal PluginScript to main-frame only as using it on non-main frames could cause issues such as [#1738](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738) -- Added support for `UserScript.allowedOriginRules` parameter -- Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error -- Merged "change priority of DispatchQueue" [#2322](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2322) (thanks to [nnnlog](https://github.com/nnnlog)) -- Fixed `show`, `hide` methods and `hidden` setting for `InAppBrowser` - -## 1.1.2 - -- Updated flutter_inappwebview_platform_interface version to ^1.3.0 - -## 1.1.1 - -- Updated flutter_inappwebview_platform_interface version to ^1.2.0 - -## 1.1.0+3 - -- Updated flutter_inappwebview_platform_interface version - -## ## 1.1.0+2 - -- Updated pubspec.yaml - -## 1.1.0+1 - -- Fixed "v6.1.0 fails to compile on Xcode 15" [#2288](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2288) - -## 1.1.0 - -- Fixed XCode 16 build -- Updates minimum supported SDK version to Flutter 3.24/Dart 3.5. -- Merged "Add privacy manifest for iOS" [#2029](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2029) (thanks to [ueman](https://github.com/ueman)) - -## 1.0.13 - -- Updated `flutter_inappwebview_platform_interface` version dependency to `^1.0.10` - -## 1.0.12 - -- Updated `flutter_inappwebview_platform_interface` version dependency to `^1.0.9` -- Fix typos and other code improvements (thanks to [michalsrutek](https://github.com/michalsrutek)) -- Fixed "runtime issue of SecTrustCopyExceptions 'This method should not be called on the main thread as it may lead to UI unresponsiveness.' when using onReceivedServerTrustAuthRequest" [#1924](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1924) -- Merged "💥 Fix iPad crash due to missing sourceView" [#1933](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1933) (thanks to [michalsrutek](https://github.com/michalsrutek)) -- Merged "💥 Fix crash - remove force unwrapping from dispose method" [#1932](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1932) (thanks to [michalsrutek](https://github.com/michalsrutek)) - -## 1.0.11 - -- Updated `flutter_inappwebview_platform_interface` version dependency to `^1.0.8` - -## 1.0.10 - -- Updated `flutter_inappwebview_platform_interface` version dependency to `^1.0.7` - -## 1.0.9 - -- Implemented `InAppWebViewSettings.interceptOnlyAsyncAjaxRequests` -- Updated `useShouldInterceptAjaxRequest` automatic infer logic -- Updated `CookieManager` methods return value -- Fixed "iOS crash at public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)" [#1912](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1912) - -## 1.0.8 - -- Fixed error in InterceptAjaxRequestJS 'Failed to set responseType property' -- Fixed shouldInterceptAjaxRequest javascript code when overriding XMLHttpRequest.open method parameters - -## 1.0.7 - -- Fixed "getFavicons: _TypeError: type '_Map' is not a subtype of type 'Iterable'" [#1897](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1897) - -## 1.0.6 - -- Possible fix for "iOS Fatal Crash" [#1894](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1894) - -## 1.0.5 - -- Call `super.dispose();` on `InAppBrowser` and `ChromeSafari` implementations - -## 1.0.4 - -- Fixed "Cloudflare Turnstile failure" [#1738](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738) - -## 1.0.3 - -- Fixed `InAppBrowserMenuItem.iconColor` not working - -## 1.0.2 - -- Added `PlatformPrintJobController.onComplete` setter -- Updated `flutter_inappwebview_platform_interface` version dependency to `1.0.2` - -## 1.0.1 - -- Updated README - -## 1.0.0 - -Initial release. diff --git a/flutter_inappwebview_ios/LICENSE b/flutter_inappwebview_ios/LICENSE deleted file mode 100644 index 6ccd8da42c..0000000000 --- a/flutter_inappwebview_ios/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2023 Lorenzo Pichilli - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/flutter_inappwebview_ios/README.md b/flutter_inappwebview_ios/README.md deleted file mode 100644 index 6121ff511b..0000000000 --- a/flutter_inappwebview_ios/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# flutter\_inappwebview\_ios - -The Apple iOS WKWebView implementation of [`flutter_inappwebview`](https://pub.dev/packages/flutter_inappwebview). - -## Usage - -This package is [endorsed](https://flutter.dev/docs/development/packages-and-plugins/developing-packages#endorsed-federated-plugin), -which means you can simply use `flutter_inappwebview` -normally. This package will be automatically included in your app when you do, -so you do not need to add it to your `pubspec.yaml`. - -However, if you `import` this package to use any of its APIs directly, you -should add it to your `pubspec.yaml` as usual. \ No newline at end of file diff --git a/flutter_inappwebview_ios/analysis_options.yaml b/flutter_inappwebview_ios/analysis_options.yaml deleted file mode 100644 index e2d13ab58a..0000000000 --- a/flutter_inappwebview_ios/analysis_options.yaml +++ /dev/null @@ -1,16 +0,0 @@ -include: package:flutter_lints/flutter.yaml - -linter: - rules: - constant_identifier_names: ignore - deprecated_member_use_from_same_package: ignore - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options -analyzer: - errors: - constant_identifier_names: ignore - deprecated_member_use: ignore - deprecated_member_use_from_same_package: ignore - unnecessary_cast: ignore - unnecessary_import: ignore diff --git a/flutter_inappwebview_ios/build.yaml b/flutter_inappwebview_ios/build.yaml deleted file mode 100644 index e2b3acf338..0000000000 --- a/flutter_inappwebview_ios/build.yaml +++ /dev/null @@ -1,5 +0,0 @@ -targets: - $default: - sources: - exclude: - - example/**.dart diff --git a/flutter_inappwebview_ios/example/.gitignore b/flutter_inappwebview_ios/example/.gitignore deleted file mode 100644 index 6c319542b3..0000000000 --- a/flutter_inappwebview_ios/example/.gitignore +++ /dev/null @@ -1,46 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.build/ -.buildlog/ -.history -.svn/ -.swiftpm/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/flutter_inappwebview_ios/example/README.md b/flutter_inappwebview_ios/example/README.md deleted file mode 100644 index 972be4edeb..0000000000 --- a/flutter_inappwebview_ios/example/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# flutter_inappwebview_ios_example - -Demonstrates how to use the flutter_inappwebview_ios plugin. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/flutter_inappwebview_ios/example/analysis_options.yaml b/flutter_inappwebview_ios/example/analysis_options.yaml deleted file mode 100644 index 0d2902135c..0000000000 --- a/flutter_inappwebview_ios/example/analysis_options.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at https://dart.dev/lints. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/flutter_inappwebview_ios/example/integration_test/plugin_integration_test.dart b/flutter_inappwebview_ios/example/integration_test/plugin_integration_test.dart deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/flutter_inappwebview_ios/example/ios/.gitignore b/flutter_inappwebview_ios/example/ios/.gitignore deleted file mode 100644 index 7a7f9873ad..0000000000 --- a/flutter_inappwebview_ios/example/ios/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -**/dgph -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/flutter_inappwebview_ios/example/ios/Flutter/AppFrameworkInfo.plist b/flutter_inappwebview_ios/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 1dc6cf7652..0000000000 --- a/flutter_inappwebview_ios/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 13.0 - - diff --git a/flutter_inappwebview_ios/example/ios/Flutter/Debug.xcconfig b/flutter_inappwebview_ios/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index ec97fc6f30..0000000000 --- a/flutter_inappwebview_ios/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/flutter_inappwebview_ios/example/ios/Flutter/Release.xcconfig b/flutter_inappwebview_ios/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index c4855bfe20..0000000000 --- a/flutter_inappwebview_ios/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/flutter_inappwebview_ios/example/ios/Podfile b/flutter_inappwebview_ios/example/ios/Podfile deleted file mode 100644 index e51a31d9ca..0000000000 --- a/flutter_inappwebview_ios/example/ios/Podfile +++ /dev/null @@ -1,44 +0,0 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '13.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_ios_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) - target 'RunnerTests' do - inherit! :search_paths - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_ios_build_settings(target) - end -end diff --git a/flutter_inappwebview_ios/example/ios/Podfile.lock b/flutter_inappwebview_ios/example/ios/Podfile.lock deleted file mode 100644 index d0ef70837c..0000000000 --- a/flutter_inappwebview_ios/example/ios/Podfile.lock +++ /dev/null @@ -1,63 +0,0 @@ -PODS: - - Flutter (1.0.0) - - flutter_inappwebview_ios (0.0.1): - - Flutter - - flutter_inappwebview_ios/Core (= 0.0.1) - - swift-collections (~> 1.1.1) - - flutter_inappwebview_ios/Core (0.0.1): - - Flutter - - swift-collections (~> 1.1.1) - - integration_test (0.0.1): - - Flutter - - InternalCollectionsUtilities (1.1.1) - - swift-collections (1.1.1): - - swift-collections/BitCollections (= 1.1.1) - - swift-collections/DequeModule (= 1.1.1) - - swift-collections/HashTreeCollections (= 1.1.1) - - swift-collections/HeapModule (= 1.1.1) - - swift-collections/OrderedCollections (= 1.1.1) - - swift-collections/BitCollections (1.1.1): - - InternalCollectionsUtilities (= 1.1.1) - - swift-collections/DequeModule (1.1.1): - - InternalCollectionsUtilities (= 1.1.1) - - swift-collections/HashTreeCollections (1.1.1): - - InternalCollectionsUtilities (= 1.1.1) - - swift-collections/HeapModule (1.1.1): - - InternalCollectionsUtilities (= 1.1.1) - - swift-collections/OrderedCollections (1.1.1): - - InternalCollectionsUtilities (= 1.1.1) - - url_launcher_ios (0.0.1): - - Flutter - -DEPENDENCIES: - - Flutter (from `Flutter`) - - flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`) - - integration_test (from `.symlinks/plugins/integration_test/ios`) - - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - -SPEC REPOS: - trunk: - - InternalCollectionsUtilities - - swift-collections - -EXTERNAL SOURCES: - Flutter: - :path: Flutter - flutter_inappwebview_ios: - :path: ".symlinks/plugins/flutter_inappwebview_ios/ios" - integration_test: - :path: ".symlinks/plugins/integration_test/ios" - url_launcher_ios: - :path: ".symlinks/plugins/url_launcher_ios/ios" - -SPEC CHECKSUMS: - Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 - flutter_inappwebview_ios: 9cde7869829d54b4110df350f3eedd192c5a4aea - integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e - InternalCollectionsUtilities: af3f471602c4a67cbcb0bee0a80f6f55a33ae453 - swift-collections: ba248ecaf44ef500b27d5cf94d304218c89892ff - url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b - -PODFILE CHECKSUM: 4f1c12611da7338d21589c0b2ecd6bd20b109694 - -COCOAPODS: 1.16.2 diff --git a/flutter_inappwebview_ios/example/ios/Runner.xcodeproj/project.pbxproj b/flutter_inappwebview_ios/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index c57a42cd6b..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,763 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 2AEFC1BCE57696CFB524C917 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F06B3504FD80C126966B946 /* Pods_Runner.framework */; }; - 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - 9F7E248190F10CDFFE1B9F12 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 85F83D3F0BBD2197898F5DFC /* Pods_RunnerTests.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 97C146E61CF9000F007C117D /* Project object */; - proxyType = 1; - remoteGlobalIDString = 97C146ED1CF9000F007C117D; - remoteInfo = Runner; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 6191FBBF2F2E4381002BA59D /* Embed ExtensionKit Extensions */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = "$(EXTENSIONS_FOLDER_PATH)"; - dstSubfolderSpec = 16; - files = ( - ); - name = "Embed ExtensionKit Extensions"; - runOnlyForDeploymentPostprocessing = 0; - }; - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 1F06B3504FD80C126966B946 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 6660D89C5EDBC328D89A4CE7 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 76BC409F37DD190669C98D9F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 85F83D3F0BBD2197898F5DFC /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 95FDF4160527781306CCD3C9 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 99AAD0F26DFA3994C0E5CDED /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - E6F19CEA11FA2F8AD20FA31C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - FEFDECE11D03E4EBD4E10F4E /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, - 2AEFC1BCE57696CFB524C917 /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - FC346C6B0F16A863F4C4A9B7 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9F7E248190F10CDFFE1B9F12 /* Pods_RunnerTests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 331C8082294A63A400263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C807B294A618700263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 9784EF9C1548AE18BB01375B /* Pods */ = { - isa = PBXGroup; - children = ( - FEFDECE11D03E4EBD4E10F4E /* Pods-Runner.debug.xcconfig */, - 76BC409F37DD190669C98D9F /* Pods-Runner.release.xcconfig */, - E6F19CEA11FA2F8AD20FA31C /* Pods-Runner.profile.xcconfig */, - 6660D89C5EDBC328D89A4CE7 /* Pods-RunnerTests.debug.xcconfig */, - 95FDF4160527781306CCD3C9 /* Pods-RunnerTests.release.xcconfig */, - 99AAD0F26DFA3994C0E5CDED /* Pods-RunnerTests.profile.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 331C8082294A63A400263BE5 /* RunnerTests */, - 9784EF9C1548AE18BB01375B /* Pods */, - B64A5180AE8577DFEA35EF09 /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - 331C8081294A63A400263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - B64A5180AE8577DFEA35EF09 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 1F06B3504FD80C126966B946 /* Pods_Runner.framework */, - 85F83D3F0BBD2197898F5DFC /* Pods_RunnerTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C8080294A63A400263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - B91DAF9275918AA664072B3D /* [CP] Check Pods Manifest.lock */, - 331C807D294A63A400263BE5 /* Sources */, - 331C807F294A63A400263BE5 /* Resources */, - FC346C6B0F16A863F4C4A9B7 /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 331C8086294A63A400263BE5 /* PBXTargetDependency */, - ); - name = RunnerTests; - productName = RunnerTests; - productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - A6B9BE57D7454ABEE37269EA /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 6191FBBF2F2E4381002BA59D /* Embed ExtensionKit Extensions */, - 9EFC7D64BDEDDFE7BBF69506 /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - packageProductDependencies = ( - 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, - ); - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = YES; - LastSwiftUpdateCheck = 2620; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C8080294A63A400263BE5 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = 97C146ED1CF9000F007C117D; - }; - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, - ); - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - 331C8080294A63A400263BE5 /* RunnerTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 331C807F294A63A400263BE5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - 9EFC7D64BDEDDFE7BBF69506 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - A6B9BE57D7454ABEE37269EA /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - B91DAF9275918AA664072B3D /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 331C807D294A63A400263BE5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 97C146ED1CF9000F007C117D /* Runner */; - targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = PFP8UV45Y6; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterInappwebviewIosExample2; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 331C8088294A63A400263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 6660D89C5EDBC328D89A4CE7 /* Pods-RunnerTests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = PFP8UV45Y6; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterInappwebviewIosExample.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Debug; - }; - 331C8089294A63A400263BE5 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 95FDF4160527781306CCD3C9 /* Pods-RunnerTests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = PFP8UV45Y6; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterInappwebviewIosExample.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Release; - }; - 331C808A294A63A400263BE5 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 99AAD0F26DFA3994C0E5CDED /* Pods-RunnerTests.profile.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = PFP8UV45Y6; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterInappwebviewIosExample.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = PFP8UV45Y6; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterInappwebviewIosExample2; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = PFP8UV45Y6; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterInappwebviewIosExample2; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 331C8088294A63A400263BE5 /* Debug */, - 331C8089294A63A400263BE5 /* Release */, - 331C808A294A63A400263BE5 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { - isa = XCLocalSwiftPackageReference; - relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; - }; -/* End XCLocalSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { - isa = XCSwiftPackageProductDependency; - productName = FlutterGeneratedPluginSwiftPackage; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/flutter_inappwebview_ios/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/flutter_inappwebview_ios/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a625..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/flutter_inappwebview_ios/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_inappwebview_ios/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/flutter_inappwebview_ios/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/flutter_inappwebview_ios/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5ea..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/flutter_inappwebview_ios/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/flutter_inappwebview_ios/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index c3fedb29c9..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_inappwebview_ios/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/flutter_inappwebview_ios/example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14c7..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/flutter_inappwebview_ios/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_inappwebview_ios/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/flutter_inappwebview_ios/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/flutter_inappwebview_ios/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5ea..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/flutter_inappwebview_ios/example/ios/Runner/AppDelegate.swift b/flutter_inappwebview_ios/example/ios/Runner/AppDelegate.swift deleted file mode 100644 index b636303481..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@main -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fab2d..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4725..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 7353c41ecf..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 797d452e45..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 6ed2d933e1..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 4cd7b0099c..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index fe730945a0..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index 321773cd85..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 797d452e45..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 502f463a9b..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index 0ec3034392..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 0ec3034392..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index e9f5fea27c..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index 84ac32ae7d..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 8953cba090..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 0467bf12aa..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2fd4..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19eacad..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eacad..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eacad..0000000000 Binary files a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b70..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/flutter_inappwebview_ios/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/flutter_inappwebview_ios/example/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7c9..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_inappwebview_ios/example/ios/Runner/Base.lproj/Main.storyboard b/flutter_inappwebview_ios/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516fb..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_inappwebview_ios/example/ios/Runner/Info.plist b/flutter_inappwebview_ios/example/ios/Runner/Info.plist deleted file mode 100644 index ef1c4f490b..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner/Info.plist +++ /dev/null @@ -1,72 +0,0 @@ - - - - - CADisableMinimumFrameDurationOnPhone - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Flutter Inappwebview Ios - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - flutter_inappwebview_ios_example - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UIApplicationSupportsIndirectInputEvents - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - NSAllowsArbitraryLoadsInWebContent - - NSAllowsLocalNetworking - - - NSCameraUsageDescription - InAppWebView requires access to cam. - NSDocumentsFolderUsageDescription - InAppWebView requires access to documents folder - NSLocalNetworkUsageDescription - Allow Flutter tools on your computer to connect and debug your application. - NSLocationAlwaysAndWhenInUseUsageDescription - Need location - NSLocationAlwaysUsageDescription - Need location - NSLocationWhenInUseUsageDescription - Need location - NSMicrophoneUsageDescription - InAppWebView requires access to mic. - - diff --git a/flutter_inappwebview_ios/example/ios/Runner/Runner-Bridging-Header.h b/flutter_inappwebview_ios/example/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a560b..0000000000 --- a/flutter_inappwebview_ios/example/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/flutter_inappwebview_ios/example/ios/RunnerTests/RunnerTests.swift b/flutter_inappwebview_ios/example/ios/RunnerTests/RunnerTests.swift deleted file mode 100644 index 3fff3af35f..0000000000 --- a/flutter_inappwebview_ios/example/ios/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,26 +0,0 @@ -import Flutter -import UIKit -import XCTest - -@testable import flutter_inappwebview_ios - -// This demonstrates a simple unit test of the Swift portion of this plugin's implementation. -// -// See https://developer.apple.com/documentation/xctest for more information about using XCTest. - -class RunnerTests: XCTestCase { - - func testGetPlatformVersion() { - let plugin = FlutterInappwebviewIosPlugin() - - let call = FlutterMethodCall(methodName: "getPlatformVersion", arguments: []) - - let resultExpectation = expectation(description: "result block must be called.") - plugin.handle(call) { result in - XCTAssertEqual(result as! String, "iOS " + UIDevice.current.systemVersion) - resultExpectation.fulfill() - } - waitForExpectations(timeout: 1) - } - -} diff --git a/flutter_inappwebview_ios/example/lib/main.dart b/flutter_inappwebview_ios/example/lib/main.dart deleted file mode 100644 index 53c70898db..0000000000 --- a/flutter_inappwebview_ios/example/lib/main.dart +++ /dev/null @@ -1,183 +0,0 @@ -import 'dart:async'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import 'package:flutter_inappwebview_ios/flutter_inappwebview_ios.dart'; -import 'package:url_launcher/url_launcher.dart'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - - runApp(const MaterialApp(home: MyApp())); -} - -class MyApp extends StatefulWidget { - const MyApp({super.key}); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - final GlobalKey webViewKey = GlobalKey(); - - IOSInAppWebViewController? webViewController; - InAppWebViewSettings settings = InAppWebViewSettings( - isInspectable: kDebugMode, - mediaPlaybackRequiresUserGesture: false, - allowsInlineMediaPlayback: true); - - IOSPullToRefreshController? pullToRefreshController; - String url = ""; - double progress = 0; - final urlController = TextEditingController(); - - @override - void initState() { - super.initState(); - - pullToRefreshController = IOSPullToRefreshController( - IOSPullToRefreshControllerCreationParams( - settings: PullToRefreshSettings( - color: Colors.blue, - ), - onRefresh: () async { - webViewController?.loadUrl( - urlRequest: URLRequest(url: await webViewController?.getUrl())); - }, - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text("Official InAppWebView website")), - body: SafeArea( - child: Column(children: [ - TextField( - decoration: const InputDecoration(prefixIcon: Icon(Icons.search)), - controller: urlController, - keyboardType: TextInputType.url, - onSubmitted: (value) { - var url = WebUri(value); - if (url.scheme.isEmpty) { - url = WebUri("https://www.google.com/search?q=$value"); - } - webViewController?.loadUrl(urlRequest: URLRequest(url: url)); - }, - ), - Expanded( - child: Stack( - children: [ - IOSInAppWebViewWidget( - IOSInAppWebViewWidgetCreationParams( - key: webViewKey, - initialUrlRequest: - URLRequest(url: WebUri("https://inappwebview.dev/")), - initialSettings: settings, - pullToRefreshController: pullToRefreshController, - onWebViewCreated: (controller) { - webViewController = - controller as IOSInAppWebViewController; - }, - onLoadStart: (controller, url) { - setState(() { - this.url = url.toString(); - urlController.text = this.url; - }); - }, - onPermissionRequest: (controller, request) async { - return PermissionResponse( - resources: request.resources, - action: PermissionResponseAction.GRANT); - }, - shouldOverrideUrlLoading: - (controller, navigationAction) async { - var uri = navigationAction.request.url!; - - if (![ - "http", - "https", - "file", - "chrome", - "data", - "javascript", - "about" - ].contains(uri.scheme)) { - if (await canLaunchUrl(uri)) { - // Launch the App - await launchUrl( - uri, - ); - // and cancel the request - return NavigationActionPolicy.CANCEL; - } - } - - return NavigationActionPolicy.ALLOW; - }, - onLoadStop: (controller, url) async { - pullToRefreshController?.endRefreshing(); - setState(() { - this.url = url.toString(); - urlController.text = this.url; - }); - }, - onReceivedError: (controller, request, error) { - pullToRefreshController?.endRefreshing(); - }, - onProgressChanged: (controller, progress) { - if (progress == 100) { - pullToRefreshController?.endRefreshing(); - } - setState(() { - this.progress = progress / 100; - urlController.text = url; - }); - }, - onUpdateVisitedHistory: (controller, url, isReload) { - setState(() { - this.url = url.toString(); - urlController.text = this.url; - }); - }, - onConsoleMessage: (controller, consoleMessage) { - if (kDebugMode) { - print(consoleMessage); - } - }, - ), - ).build(context), - progress < 1.0 - ? LinearProgressIndicator(value: progress) - : Container(), - ], - ), - ), - OverflowBar( - alignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - child: const Icon(Icons.arrow_back), - onPressed: () { - webViewController?.goBack(); - }, - ), - ElevatedButton( - child: const Icon(Icons.arrow_forward), - onPressed: () { - webViewController?.goForward(); - }, - ), - ElevatedButton( - child: const Icon(Icons.refresh), - onPressed: () { - webViewController?.reload(); - }, - ), - ], - ), - ]))); - } -} diff --git a/flutter_inappwebview_ios/example/pubspec.lock b/flutter_inappwebview_ios/example/pubspec.lock deleted file mode 100644 index ddd54e3fa6..0000000000 --- a/flutter_inappwebview_ios/example/pubspec.lock +++ /dev/null @@ -1,374 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" - url: "https://pub.dev" - source: hosted - version: "2.11.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - file: - dependency: transitive - description: - name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_driver: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_inappwebview_internal_annotations: - dependency: transitive - description: - path: "../../dev_packages/flutter_inappwebview_internal_annotations" - relative: true - source: path - version: "1.3.0" - flutter_inappwebview_ios: - dependency: "direct main" - description: - path: ".." - relative: true - source: path - version: "1.2.0-beta.3" - flutter_inappwebview_platform_interface: - dependency: "direct main" - description: - path: "../../flutter_inappwebview_platform_interface" - relative: true - source: path - version: "1.4.0-beta.3" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 - url: "https://pub.dev" - source: hosted - version: "2.0.3" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - fuchsia_remote_debug_protocol: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - integration_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" - source: hosted - version: "11.0.2" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" - source: hosted - version: "3.0.10" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - lints: - dependency: transitive - description: - name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" - url: "https://pub.dev" - source: hosted - version: "1.17.0" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - platform: - dependency: transitive - description: - name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" - url: "https://pub.dev" - source: hosted - version: "3.1.5" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - process: - dependency: transitive - description: - name: process - sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" - url: "https://pub.dev" - source: hosted - version: "5.0.2" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_span: - dependency: transitive - description: - name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - sync_http: - dependency: transitive - description: - name: sync_http - sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" - url: "https://pub.dev" - source: hosted - version: "0.3.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test_api: - dependency: transitive - description: - name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 - url: "https://pub.dev" - source: hosted - version: "0.7.7" - url_launcher: - dependency: "direct main" - description: - name: url_launcher - sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.dev" - source: hosted - version: "6.3.2" - url_launcher_android: - dependency: transitive - description: - name: url_launcher_android - sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611" - url: "https://pub.dev" - source: hosted - version: "6.3.28" - url_launcher_ios: - dependency: transitive - description: - name: url_launcher_ios - sha256: cfde38aa257dae62ffe79c87fab20165dfdf6988c1d31b58ebf59b9106062aad - url: "https://pub.dev" - source: hosted - version: "6.3.6" - url_launcher_linux: - dependency: transitive - description: - name: url_launcher_linux - sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a - url: "https://pub.dev" - source: hosted - version: "3.2.2" - url_launcher_macos: - dependency: transitive - description: - name: url_launcher_macos - sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" - url: "https://pub.dev" - source: hosted - version: "3.2.5" - url_launcher_platform_interface: - dependency: transitive - description: - name: url_launcher_platform_interface - sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - url_launcher_web: - dependency: transitive - description: - name: url_launcher_web - sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f - url: "https://pub.dev" - source: hosted - version: "2.4.2" - url_launcher_windows: - dependency: transitive - description: - name: url_launcher_windows - sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" - url: "https://pub.dev" - source: hosted - version: "3.1.5" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" - source: hosted - version: "2.2.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" - url: "https://pub.dev" - source: hosted - version: "14.2.5" - web: - dependency: transitive - description: - name: web - sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - webdriver: - dependency: transitive - description: - name: webdriver - sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" - url: "https://pub.dev" - source: hosted - version: "3.0.3" -sdks: - dart: ">=3.10.0 <4.0.0" - flutter: ">=3.38.0" diff --git a/flutter_inappwebview_ios/example/pubspec.yaml b/flutter_inappwebview_ios/example/pubspec.yaml deleted file mode 100644 index 37a7d7aa93..0000000000 --- a/flutter_inappwebview_ios/example/pubspec.yaml +++ /dev/null @@ -1,91 +0,0 @@ -name: flutter_inappwebview_ios_example -description: Demonstrates how to use the flutter_inappwebview_ios plugin. -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -environment: - sdk: ">=2.17.0 <4.0.0" - flutter: ">=3.0.0" - -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. -dependencies: - flutter: - sdk: flutter - - flutter_inappwebview_ios: - # When depending on this package from a real application you should use: - # flutter_inappwebview_ios: ^x.y.z - # See https://dart.dev/tools/pub/dependencies#version-constraints - # The example app is bundled with the plugin so we use a path dependency on - # the parent directory to use the current plugin's version. - path: ../ - - flutter_inappwebview_platform_interface: - path: ../../flutter_inappwebview_platform_interface - - url_launcher: ^6.1.0 - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 - -dev_dependencies: - integration_test: - sdk: flutter - flutter_test: - sdk: flutter - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^2.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/flutter_inappwebview_ios/example/test/widget_test.dart b/flutter_inappwebview_ios/example/test/widget_test.dart deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/flutter_inappwebview_ios/ios/.gitignore b/flutter_inappwebview_ios/ios/.gitignore deleted file mode 100755 index 0c885071e3..0000000000 --- a/flutter_inappwebview_ios/ios/.gitignore +++ /dev/null @@ -1,38 +0,0 @@ -.idea/ -.vagrant/ -.sconsign.dblite -.svn/ - -.DS_Store -*.swp -profile - -DerivedData/ -build/ -GeneratedPluginRegistrant.h -GeneratedPluginRegistrant.m - -.generated/ - -*.pbxuser -*.mode1v3 -*.mode2v3 -*.perspectivev3 - -!default.pbxuser -!default.mode1v3 -!default.mode2v3 -!default.perspectivev3 - -xcuserdata - -*.moved-aside - -*.pyc -*sync/ -Icon? -.tags* - -/Flutter/Generated.xcconfig -/Flutter/ephemeral/ -/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios.podspec b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios.podspec deleted file mode 100755 index 61391eb9aa..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios.podspec +++ /dev/null @@ -1,41 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint flutterplugintest.podspec' to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'flutter_inappwebview_ios' - s.version = '0.0.1' - s.summary = 'A new Flutter plugin.' - s.description = <<-DESC -A new Flutter plugin. - DESC - s.homepage = 'http://example.com' - s.license = { :file => '../LICENSE' } - s.author = { 'Your Company' => 'email@example.com' } - s.source = { :path => '.' } - s.source_files = 'flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/**/*.swift' - s.resources = 'flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Resources/**/*.storyboard' - s.dependency 'Flutter' - s.resource_bundles = {'flutter_inappwebview_ios_privacy' => ['flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Resources/PrivacyInfo.xcprivacy']} - - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } - - s.libraries = 'swiftCoreGraphics' - - s.dependency 'swift-collections', '~>1.1.1' - - s.xcconfig = { - 'LIBRARY_SEARCH_PATHS' => '$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)/ $(SDKROOT)/usr/lib/swift', - 'LD_RUNPATH_SEARCH_PATHS' => '/usr/lib/swift', - } - - s.swift_version = '5.0' - - s.platforms = { :ios => '12.0' } - - s.default_subspec = 'Core' - - s.subspec 'Core' do |core| - core.platform = :ios, '12.0' - end -end diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Package.resolved b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Package.resolved deleted file mode 100644 index eb9351a474..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Package.resolved +++ /dev/null @@ -1,14 +0,0 @@ -{ - "pins" : [ - { - "identity" : "swift-collections", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-collections.git", - "state" : { - "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", - "version" : "1.3.0" - } - } - ], - "version" : 2 -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Package.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Package.swift deleted file mode 100644 index e8408a1e4d..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Package.swift +++ /dev/null @@ -1,28 +0,0 @@ -// swift-tools-version: 5.9 -// The swift-tools-version declares the minimum version of Swift required to build this package. - -import PackageDescription - -let package = Package( - name: "flutter_inappwebview_ios", - platforms: [ - .iOS("12.0"), - ], - products: [ - .library(name: "flutter-inappwebview-ios", targets: ["flutter_inappwebview_ios"]) - ], - dependencies: [ - .package(url: "https://github.com/apple/swift-collections.git", from: "1.2.1") - ], - targets: [ - .target( - name: "flutter_inappwebview_ios", - dependencies: [ - .product(name: "Collections", package: "swift-collections") - ], - resources: [ - .process("Resources") - ] - ) - ] -) diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/CredentialDatabase.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/CredentialDatabase.swift deleted file mode 100755 index d7b30916cc..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/CredentialDatabase.swift +++ /dev/null @@ -1,172 +0,0 @@ -// -// CredentialDatabase.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 29/10/2019. -// - -import Foundation -import Flutter - -public class CredentialDatabase: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_credential_database" - static let credentialStore = URLCredentialStorage.shared - - private var plugin: InAppWebViewFlutterPlugin? - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: CredentialDatabase.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger())) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - switch call.method { - case "getAllAuthCredentials": - var allCredentials: [[String: Any?]] = [] - for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { - var crendentials: [[String: Any?]] = [] - for c in credentials { - let credential: [String: Any?] = c.value.toMap() - crendentials.append(credential) - } - if crendentials.count > 0 { - let dict: [String : Any] = [ - "protectionSpace": protectionSpace.toMap(), - "credentials": crendentials - ] - allCredentials.append(dict) - } - } - result(allCredentials) - break - case "getHttpAuthCredentials": - var crendentials: [[String: Any?]] = [] - - let host = arguments!["host"] as! String - let urlProtocol = arguments!["protocol"] as? String - let urlPort = arguments!["port"] as? Int ?? 0 - var realm = arguments!["realm"] as? String - if let r = realm, r.isEmpty { - realm = nil - } - - for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { - if protectionSpace.host == host && protectionSpace.realm == realm && - protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort { - for c in credentials { - crendentials.append(c.value.toMap()) - } - break - } - } - result(crendentials) - break - case "setHttpAuthCredential": - let host = arguments!["host"] as! String - let urlProtocol = arguments!["protocol"] as? String - let urlPort = arguments!["port"] as? Int ?? 0 - var realm = arguments!["realm"] as? String - if let r = realm, r.isEmpty { - realm = nil - } - let username = arguments!["username"] as! String - let password = arguments!["password"] as! String - let credential = URLCredential(user: username, password: password, persistence: .permanent) - CredentialDatabase.credentialStore.set(credential, - for: URLProtectionSpace(host: host, port: urlPort, protocol: urlProtocol, - realm: realm, authenticationMethod: NSURLAuthenticationMethodHTTPBasic)) - result(true) - break - case "removeHttpAuthCredential": - let host = arguments!["host"] as! String - let urlProtocol = arguments!["protocol"] as? String - let urlPort = arguments!["port"] as? Int ?? 0 - var realm = arguments!["realm"] as? String - if let r = realm, r.isEmpty { - realm = nil - } - let username = arguments!["username"] as! String - let password = arguments!["password"] as! String - - var credential: URLCredential? = nil - var protectionSpaceCredential: URLProtectionSpace? = nil - - for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { - if protectionSpace.host == host && protectionSpace.realm == realm && - protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort { - for c in credentials { - if c.value.user == username, c.value.password == password { - credential = c.value - protectionSpaceCredential = protectionSpace - break - } - } - } - if credential != nil { - break - } - } - - if let c = credential, let protectionSpace = protectionSpaceCredential { - CredentialDatabase.credentialStore.remove(c, for: protectionSpace) - } - - result(true) - break - case "removeHttpAuthCredentials": - let host = arguments!["host"] as! String - let urlProtocol = arguments!["protocol"] as? String - let urlPort = arguments!["port"] as? Int ?? 0 - var realm = arguments!["realm"] as? String - if let r = realm, r.isEmpty { - realm = nil - } - - var credentialsToRemove: [URLCredential] = [] - var protectionSpaceCredential: URLProtectionSpace? = nil - - for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { - if protectionSpace.host == host && protectionSpace.realm == realm && - protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort { - protectionSpaceCredential = protectionSpace - for c in credentials { - if let _ = c.value.user, let _ = c.value.password { - credentialsToRemove.append(c.value) - } - } - break - } - } - - if let protectionSpace = protectionSpaceCredential { - for credential in credentialsToRemove { - CredentialDatabase.credentialStore.remove(credential, for: protectionSpace) - } - } - - result(true) - break - case "clearAllAuthCredentials": - for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { - for credential in credentials { - CredentialDatabase.credentialStore.remove(credential.value, for: protectionSpace) - } - } - result(true) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public override func dispose() { - super.dispose() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/FindInteraction/FindInteractionChannelDelegate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/FindInteraction/FindInteractionChannelDelegate.swift deleted file mode 100644 index 006e9b5699..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/FindInteraction/FindInteractionChannelDelegate.swift +++ /dev/null @@ -1,159 +0,0 @@ -// -// FindInteractionChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/10/22. -// - -import Foundation -import Flutter - -public class FindInteractionChannelDelegate: ChannelDelegate { - private weak var findInteractionController: FindInteractionController? - - public init(findInteractionController: FindInteractionController, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.findInteractionController = findInteractionController - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "findAll": - if let findInteractionController = findInteractionController { - let find = arguments!["find"] as! String - findInteractionController.findAll(find: find, completionHandler: {(value, error) in - if error != nil { - result(FlutterError(code: "FindInteractionChannelDelegate", message: error?.localizedDescription, details: nil)) - return - } - result(true) - }) - } else { - result(false) - } - break - case "findNext": - if let findInteractionController = findInteractionController { - let forward = arguments!["forward"] as! Bool - findInteractionController.findNext(forward: forward, completionHandler: {(value, error) in - if error != nil { - result(FlutterError(code: "FindInteractionChannelDelegate", message: error?.localizedDescription, details: nil)) - return - } - result(true) - }) - } else { - result(false) - } - break - case "clearMatches": - if let findInteractionController = findInteractionController { - findInteractionController.clearMatches(completionHandler: {(value, error) in - if error != nil { - result(FlutterError(code: "FindInteractionChannelDelegate", message: error?.localizedDescription, details: nil)) - return - } - result(true) - }) - } else { - result(false) - } - break - case "setSearchText": - if let findInteractionController = findInteractionController { - let searchText = arguments!["searchText"] as? String - findInteractionController.searchText = searchText - result(true) - } else { - result(false) - } - break - case "getSearchText": - result(findInteractionController?.searchText) - break - case "isFindNavigatorVisible": - if #available(iOS 16.0, *) { - if let interaction = findInteractionController?.webView?.findInteraction { - result(interaction.isFindNavigatorVisible) - } else { - result(false) - } - } else { - result(false) - } - break - case "updateResultCount": - if #available(iOS 16.0, *) { - if let interaction = findInteractionController?.webView?.findInteraction { - interaction.updateResultCount() - result(true) - } else { - result(false) - } - } else { - result(false) - } - break - case "presentFindNavigator": - if #available(iOS 16.0, *) { - if let interaction = findInteractionController?.webView?.findInteraction { - interaction.presentFindNavigator(showingReplace: false) - result(true) - } else { - result(false) - } - } else { - result(false) - } - break - case "dismissFindNavigator": - if #available(iOS 16.0, *) { - if let interaction = findInteractionController?.webView?.findInteraction { - interaction.dismissFindNavigator() - result(true) - } else { - result(false) - } - } else { - result(false) - } - break - case "getActiveFindSession": - if let findInteractionController = findInteractionController { - result(findInteractionController.activeFindSession?.toMap()) - } else { - result(nil) - } - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func onFindResultReceived(activeMatchOrdinal: Int, numberOfMatches: Int, isDoneCounting: Bool) { - if isDoneCounting, let findInteractionController = findInteractionController { - findInteractionController.activeFindSession = FindSession(resultCount: numberOfMatches, - highlightedResultIndex: activeMatchOrdinal, - searchResultDisplayStyle: 2) // matches UIFindSession.SearchResultDisplayStyle.none - } - - let arguments: [String : Any?] = [ - "activeMatchOrdinal": activeMatchOrdinal, - "numberOfMatches": numberOfMatches, - "isDoneCounting": isDoneCounting - ] - channel?.invokeMethod("onFindResultReceived", arguments: arguments) - } - - public override func dispose() { - super.dispose() - findInteractionController = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/FindInteraction/FindInteractionController.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/FindInteraction/FindInteractionController.swift deleted file mode 100644 index 0553a8f890..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/FindInteraction/FindInteractionController.swift +++ /dev/null @@ -1,160 +0,0 @@ -// -// FindInteractionController.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/10/22. -// - -import Foundation -import Flutter - -public class FindInteractionController: NSObject, Disposable { - static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_find_interaction_" - - var webView: InAppWebView? - var channelDelegate: FindInteractionChannelDelegate? - - private var plugin: InAppWebViewFlutterPlugin? - private var settings: FindInteractionSettings? - - private var _searchText: String? = nil - var searchText: String? { - get { - if #available(iOS 16.0, *), let interaction = webView?.findInteraction { - return interaction.searchText - } - return _searchText - } - set { - if #available(iOS 16.0, *), let interaction = webView?.findInteraction { - interaction.searchText = newValue - } - self._searchText = newValue - } - } - - private var _activeFindSession: FindSession? = nil - var activeFindSession: FindSession? { - get { - if #available(iOS 16.0, *), let interaction = webView?.findInteraction { - if let activeFindSession = interaction.activeFindSession { - return FindSession.fromUIFindSession(uiFindSession: activeFindSession) - } - return nil - } - return _activeFindSession - } - set { - self._activeFindSession = newValue - } - } - - public init(plugin: InAppWebViewFlutterPlugin, id: Any, webView: InAppWebView, settings: FindInteractionSettings?) { - super.init() - self.plugin = plugin - self.webView = webView - self.settings = settings - let channel = FlutterMethodChannel(name: FindInteractionController.METHOD_CHANNEL_NAME_PREFIX + String(describing: id), - binaryMessenger: plugin.registrar.messenger()) - self.channelDelegate = FindInteractionChannelDelegate(findInteractionController: self, channel: channel) - } - - public func prepare() { -// if let settings = settings { -// -// } - } - - public func findAll(find: String?, completionHandler: ((Any?, Error?) -> Void)?) { - guard let webView else { - if let completionHandler = completionHandler { - completionHandler(nil, nil) - } - return - } - - var find = find - if find == nil { - find = searchText - } else { - // updated searchText - searchText = find - } - - guard let find else { - if let completionHandler = completionHandler { - completionHandler(nil, nil) - } - return - } - - if #available(iOS 16.0, *), webView.isFindInteractionEnabled { - if let interaction = webView.findInteraction { - interaction.searchText = find - interaction.presentFindNavigator(showingReplace: false) - } - if let completionHandler = completionHandler { - completionHandler(nil, nil) - } - } else if find != "" { - let startSearch = "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findAllAsync('\(find)');" - webView.evaluateJavaScript(startSearch, completionHandler: completionHandler) - } - } - - public func findNext(forward: Bool, completionHandler: ((Any?, Error?) -> Void)?) { - guard let webView else { - if let completionHandler = completionHandler { - completionHandler(nil, nil) - } - return - } - if #available(iOS 16.0, *), webView.isFindInteractionEnabled { - if let interaction = webView.findInteraction { - if forward { - interaction.findNext() - } else { - interaction.findPrevious() - } - } - if let completionHandler = completionHandler { - completionHandler(nil, nil) - } - } else { - webView.evaluateJavaScript("window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findNext(\(forward ? "true" : "false"));", completionHandler: completionHandler) - } - } - - public func clearMatches(completionHandler: ((Any?, Error?) -> Void)?) { - guard let webView else { - if let completionHandler = completionHandler { - completionHandler(nil, nil) - } - return - } - if #available(iOS 16.0, *), webView.isFindInteractionEnabled { - if let interaction = webView.findInteraction { - interaction.searchText = nil - interaction.dismissFindNavigator() - } - if let completionHandler = completionHandler { - completionHandler(nil, nil) - } - } else { - webView.evaluateJavaScript("window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._clearMatches();", completionHandler: completionHandler) - } - } - - public func dispose() { - channelDelegate?.dispose() - channelDelegate = nil - webView = nil - activeFindSession = nil - plugin = nil - } - - deinit { - debugPrint("FindInteractionControl - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/FindInteraction/FindInteractionSettings.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/FindInteraction/FindInteractionSettings.swift deleted file mode 100644 index 3c4ecb14a2..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/FindInteraction/FindInteractionSettings.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// FindInteractionSettings.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/10/22. -// - -import Foundation - -public class FindInteractionSettings: ISettings { - - override init(){ - super.init() - } - - override func parse(settings: [String: Any?]) -> FindInteractionSettings { - let _ = super.parse(settings: settings) - return self - } - - override func getRealSettings(obj: FindInteractionController?) -> [String: Any?] { - let realSettings: [String: Any?] = toMap() - return realSettings - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/HeadlessInAppWebView/HeadlessInAppWebView.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/HeadlessInAppWebView/HeadlessInAppWebView.swift deleted file mode 100644 index 1462dc0124..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/HeadlessInAppWebView/HeadlessInAppWebView.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// HeadlessInAppWebView.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 26/03/21. -// - -import Foundation -import Flutter - -public class HeadlessInAppWebView: Disposable { - static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_headless_inappwebview_" - - var id: String - var channelDelegate: HeadlessWebViewChannelDelegate? - var flutterWebView: FlutterWebViewController? - var plugin: InAppWebViewFlutterPlugin? - - public init(plugin: InAppWebViewFlutterPlugin, id: String, flutterWebView: FlutterWebViewController) { - self.id = id - self.flutterWebView = flutterWebView - self.plugin = plugin - let channel = FlutterMethodChannel(name: HeadlessInAppWebView.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: plugin.registrar.messenger()) - self.channelDelegate = HeadlessWebViewChannelDelegate(headlessWebView: self, channel: channel) - } - - public func onWebViewCreated() { - channelDelegate?.onWebViewCreated() - } - - public func prepare(params: NSDictionary) { - if let view = flutterWebView?.view() { - view.alpha = 0.01 - let initialSize = params["initialSize"] as? [String: Any?] - if let size = Size2D.fromMap(map: initialSize) { - setSize(size: size) - } else { - view.frame = CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height) - } - if let keyWindow = UIApplication.shared.keyWindow { - /// Note: The WKWebView behaves very unreliable when rendering offscreen - /// on a device. This is especially true with JavaScript, which simply - /// won't be executed sometimes. - /// So, add the headless WKWebView to the view hierarchy. - /// This way is also possible to take screenshots. - keyWindow.insertSubview(view, at: 0) - keyWindow.sendSubviewToBack(view) - } - } - } - - public func setSize(size: Size2D) { - if let view = flutterWebView?.view() { - let width = size.width == -1.0 ? UIScreen.main.bounds.width : CGFloat(size.width) - let height = size.height == -1.0 ? UIScreen.main.bounds.height : CGFloat(size.height) - view.frame = CGRect(x: 0.0, y: 0.0, width: width, height: height) - } - } - - public func getSize() -> Size2D? { - if let view = flutterWebView?.view() { - return Size2D(width: Double(view.frame.width), height: Double(view.frame.height)) - } - return nil - } - - public func disposeAndGetFlutterWebView(withFrame frame: CGRect) -> FlutterWebViewController? { - let newFlutterWebView = flutterWebView - if let view = flutterWebView?.view() { - // restore WebView frame and alpha - view.frame = frame - view.alpha = 1.0 - // remove from parent - view.removeFromSuperview() - dispose(disposeWebView: false) - } - return newFlutterWebView - } - - public func dispose(disposeWebView: Bool) { - channelDelegate?.dispose() - channelDelegate = nil - plugin?.headlessInAppWebViewManager?.webViews[id] = nil - if disposeWebView { - flutterWebView?.dispose(removeFromSuperview: true) - } - flutterWebView = nil - plugin = nil - } - - public func dispose() { - dispose(disposeWebView: true) - } - - deinit { - debugPrint("HeadlessInAppWebView - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift deleted file mode 100644 index d203dc4b05..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// HeadlessInAppWebViewManager.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/05/2020. -// - -import Foundation - -import Flutter -import UIKit -import WebKit -import Foundation -import AVFoundation - -public class HeadlessInAppWebViewManager: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_headless_inappwebview" - var plugin: InAppWebViewFlutterPlugin? - var webViews: [String: HeadlessInAppWebView?] = [:] - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: HeadlessInAppWebViewManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger())) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - let id: String = arguments!["id"] as! String - - switch call.method { - case "run": - let params = arguments!["params"] as! [String: Any?] - run(id: id, params: params) - result(true) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func run(id: String, params: [String: Any?]) { - guard let plugin = plugin else { - return - } - let flutterWebView = FlutterWebViewController(plugin: plugin, - withFrame: CGRect.zero, - viewIdentifier: id, - params: params as NSDictionary) - let headlessInAppWebView = HeadlessInAppWebView(plugin: plugin, id: id, flutterWebView: flutterWebView) - webViews[id] = headlessInAppWebView - - headlessInAppWebView.prepare(params: params as NSDictionary) - headlessInAppWebView.onWebViewCreated() - flutterWebView.makeInitialLoad(params: params as NSDictionary) - } - - public override func dispose() { - super.dispose() - let headlessWebViews = webViews.values - headlessWebViews.forEach { (headlessWebView: HeadlessInAppWebView?) in - headlessWebView?.dispose() - } - webViews.removeAll() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/HeadlessInAppWebView/HeadlessWebViewChannelDelegate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/HeadlessInAppWebView/HeadlessWebViewChannelDelegate.swift deleted file mode 100644 index 1b756c7567..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/HeadlessInAppWebView/HeadlessWebViewChannelDelegate.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// HeadlessWebViewChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 05/05/22. -// - -import Foundation -import Flutter - -public class HeadlessWebViewChannelDelegate: ChannelDelegate { - private weak var headlessWebView: HeadlessInAppWebView? - - public init(headlessWebView: HeadlessInAppWebView, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.headlessWebView = headlessWebView - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "dispose": - if let headlessWebView = headlessWebView { - headlessWebView.dispose() - result(true) - } else { - result(false) - } - break - case "setSize": - if let headlessWebView = headlessWebView { - let sizeMap = arguments!["size"] as? [String: Any?] - if let size = Size2D.fromMap(map: sizeMap) { - headlessWebView.setSize(size: size) - } - result(true) - } else { - result(false) - } - break - case "getSize": - result(headlessWebView?.getSize()?.toMap()) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func onWebViewCreated() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onWebViewCreated", arguments: arguments) - } - - public override func dispose() { - super.dispose() - headlessWebView = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/ISettings.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/ISettings.swift deleted file mode 100755 index 3c536486ca..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/ISettings.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// Options.swift -// flutter_inappwebview -// -// Created by Lorenzo on 26/09/18. -// - -import Foundation - -@objcMembers -public class ISettings: NSObject { - - override init(){ - super.init() - } - - func parse(settings: [String: Any?]) -> ISettings { - for (key, value) in settings { - if !(value is NSNull), value != nil { - if self.responds(to: Selector(key)) { - self.setValue(value, forKey: key) - } else if self.responds(to: Selector("_" + key)) { - self.setValue(value, forKey: "_" + key) - } - } - } - return self - } - - func toMap() -> [String: Any?] { - var settings: [String: Any?] = [:] - var counts = UInt32() - let properties = class_copyPropertyList(object_getClass(self), &counts) - for i in 0.. [String: Any?] { - let realSettings: [String: Any?] = toMap() - return realSettings - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserChannelDelegate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserChannelDelegate.swift deleted file mode 100644 index 113dc180e5..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserChannelDelegate.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// InAppBrowserChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 05/05/22. -// - -import Foundation -import Flutter - -public class InAppBrowserChannelDelegate: ChannelDelegate { - public override init(channel: FlutterMethodChannel) { - super.init(channel: channel) - } - - public func onBrowserCreated() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onBrowserCreated", arguments: arguments) - } - - public func onMenuItemClicked(menuItem: InAppBrowserMenuItem) { - let arguments: [String: Any?] = [ - "id": menuItem.id - ] - channel?.invokeMethod("onMenuItemClicked", arguments: arguments) - } - - public func onExit() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onExit", arguments: arguments) - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserDelegate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserDelegate.swift deleted file mode 100644 index ba013c58e9..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserDelegate.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// InAppBrowserDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 14/02/21. -// - -import Foundation - -public protocol InAppBrowserDelegate { - func didChangeTitle(title: String?) - func didStartNavigation(url: URL?) - func didUpdateVisitedHistory(url: URL?) - func didFinishNavigation(url: URL?) - func didFailNavigation(url: URL?, error: Error) - func didChangeProgress(progress: Double) -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserManager.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserManager.swift deleted file mode 100755 index 3076b6765f..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserManager.swift +++ /dev/null @@ -1,158 +0,0 @@ -// -// InAppBrowserManager.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 18/12/2019. -// - -import Flutter -import UIKit -import WebKit -import Foundation -import AVFoundation - -public class InAppBrowserManager: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappbrowser" - static let WEBVIEW_STORYBOARD = "WebView" - static let WEBVIEW_STORYBOARD_CONTROLLER_ID = "viewController" - static let NAV_STORYBOARD_CONTROLLER_ID = "navController" - var plugin: InAppWebViewFlutterPlugin? - - var navControllers: [String: InAppBrowserNavigationController?] = [:] - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: InAppBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger())) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "open": - open(arguments: arguments!) - result(true) - break - case "openWithSystemBrowser": - let url = arguments!["url"] as! String - openWithSystemBrowser(url: url, result: result) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func prepareInAppBrowserWebViewController(settings: [String: Any?]) -> InAppBrowserWebViewController { - let browserSettings = InAppBrowserSettings() - let _ = browserSettings.parse(settings: settings) - - let webViewSettings = InAppWebViewSettings() - let _ = webViewSettings.parse(settings: settings) - - let webViewController = InAppBrowserWebViewController() - webViewController.plugin = plugin - webViewController.browserSettings = browserSettings - webViewController.isHidden = browserSettings.hidden - webViewController.webViewSettings = webViewSettings - return webViewController - } - - public func open(arguments: NSDictionary) { - let id = arguments["id"] as! String - let urlRequest = arguments["urlRequest"] as? [String:Any?] - let assetFilePath = arguments["assetFilePath"] as? String - let data = arguments["data"] as? String - let mimeType = arguments["mimeType"] as? String - let encoding = arguments["encoding"] as? String - let baseUrl = arguments["baseUrl"] as? String - let settings = arguments["settings"] as! [String: Any?] - let contextMenu = arguments["contextMenu"] as! [String: Any] - let windowId = arguments["windowId"] as? Int64 - let initialUserScripts = arguments["initialUserScripts"] as? [[String: Any]] - let pullToRefreshInitialSettings = arguments["pullToRefreshSettings"] as! [String: Any?] - let menuItems = arguments["menuItems"] as! [[String: Any?]] - - let webViewController = prepareInAppBrowserWebViewController(settings: settings) - - webViewController.id = id - webViewController.initialUrlRequest = urlRequest != nil ? URLRequest.init(fromPluginMap: urlRequest!) : nil - webViewController.initialFile = assetFilePath - webViewController.initialData = data - webViewController.initialMimeType = mimeType - webViewController.initialEncoding = encoding - webViewController.initialBaseUrl = baseUrl - webViewController.contextMenu = contextMenu - webViewController.windowId = windowId - webViewController.initialUserScripts = initialUserScripts ?? [] - webViewController.pullToRefreshInitialSettings = pullToRefreshInitialSettings - for menuItem in menuItems { - webViewController.menuItems.append(InAppBrowserMenuItem.fromMap(map: menuItem)!) - } - - presentViewController(webViewController: webViewController) - } - - public func presentViewController(webViewController: InAppBrowserWebViewController) { - #if SWIFT_PACKAGE - let storyboard = UIStoryboard(name: InAppBrowserManager.WEBVIEW_STORYBOARD, bundle: Bundle.module) - #else - let storyboard = UIStoryboard(name: InAppBrowserManager.WEBVIEW_STORYBOARD, bundle: Bundle(for: InAppWebViewFlutterPlugin.self)) - #endif - let navController = storyboard.instantiateViewController(withIdentifier: InAppBrowserManager.NAV_STORYBOARD_CONTROLLER_ID) as! InAppBrowserNavigationController - webViewController.edgesForExtendedLayout = [] - navController.pushViewController(webViewController, animated: false) - webViewController.prepareNavigationControllerBeforeViewWillAppear() - - guard let visibleViewController = UIApplication.shared.visibleViewController else { - assertionFailure("Failure init the visibleViewController!") - return - } - - if let popover = webViewController.popoverPresentationController { - let sourceView = visibleViewController.view ?? UIView() - - popover.sourceRect = CGRect(x: sourceView.bounds.midX, y: sourceView.bounds.midY, width: 0, height: 0) - popover.permittedArrowDirections = [] - popover.sourceView = sourceView - } - - if let browserSettings = webViewController.browserSettings, browserSettings.hidden { - webViewController.loadViewIfNeeded() - } else { - visibleViewController.present(navController, animated: true) - } - - navControllers[webViewController.id] = navController - } - - public func openWithSystemBrowser(url: String, result: @escaping FlutterResult) { - let absoluteUrl = URL(string: url)!.absoluteURL - if !UIApplication.shared.canOpenURL(absoluteUrl) { - result(FlutterError(code: "InAppBrowserManager", message: url + " cannot be opened!", details: nil)) - return - } - else { - if #available(iOS 10.0, *) { - UIApplication.shared.open(absoluteUrl) - } else { - UIApplication.shared.openURL(absoluteUrl) - } - } - result(true) - } - - public override func dispose() { - super.dispose() - let navControllersValues = navControllers.values - navControllersValues.forEach { (navController: InAppBrowserNavigationController?) in - navController?.dismiss(animated: false) - } - navControllers.removeAll() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserNavigationController.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserNavigationController.swift deleted file mode 100644 index 3dc700cd6e..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserNavigationController.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// InAppBrowserNavigationController.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 14/02/21. -// - -import Foundation -import UIKit - -public class InAppBrowserNavigationController: UINavigationController { - deinit { - debugPrint("InAppBrowserNavigationController - dealloc") - UIApplication.shared.delegate?.window??.makeKeyAndVisible() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserSettings.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserSettings.swift deleted file mode 100755 index 54d34244c0..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserSettings.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// InAppBrowserOptions.swift -// flutter_inappwebview -// -// Created by Lorenzo on 17/09/18. -// - -import Foundation - -@objcMembers -public class InAppBrowserSettings: ISettings { - - var hidden = false - var hideToolbarTop = true - var toolbarTopBackgroundColor: String? - var hideUrlBar = false - var hideProgressBar = false - - var toolbarTopTranslucent = true - var toolbarTopBarTintColor: String? - var toolbarTopTintColor: String? - var hideToolbarBottom = true - var toolbarBottomBackgroundColor: String? - var toolbarBottomTintColor: String? - var toolbarBottomTranslucent = true - var closeButtonCaption: String? - var closeButtonColor: String? - var presentationStyle = 0 //fullscreen - var transitionStyle = 0 //crossDissolve - var hideCloseButton = false - var menuButtonColor: String? - - override init(){ - super.init() - } - - override func getRealSettings(obj: InAppBrowserWebViewController?) -> [String: Any?] { - var realOptions: [String: Any?] = toMap() - if let inAppBrowserWebViewController = obj { - realOptions["hidden"] = inAppBrowserWebViewController.isHidden - realOptions["hideUrlBar"] = inAppBrowserWebViewController.searchBar.isHidden - realOptions["hideProgressBar"] = inAppBrowserWebViewController.progressBar.isHidden - realOptions["closeButtonCaption"] = inAppBrowserWebViewController.closeButton.title - realOptions["closeButtonColor"] = inAppBrowserWebViewController.closeButton.tintColor?.hexString - realOptions["menuButtonColor"] = inAppBrowserWebViewController.menuButton?.tintColor?.hexString - if let navController = inAppBrowserWebViewController.navigationController { - realOptions["hideToolbarTop"] = navController.navigationBar.isHidden - realOptions["toolbarTopBackgroundColor"] = navController.navigationBar.backgroundColor?.hexString - realOptions["toolbarTopTranslucent"] = navController.navigationBar.isTranslucent - realOptions["toolbarTopBarTintColor"] = navController.navigationBar.barTintColor?.hexString - realOptions["toolbarTopTintColor"] = navController.navigationBar.tintColor?.hexString - realOptions["hideToolbarBottom"] = navController.toolbar.isHidden - realOptions["toolbarBottomBackgroundColor"] = navController.toolbar.barTintColor?.hexString - realOptions["toolbarBottomTranslucent"] = navController.toolbar.isTranslucent - realOptions["toolbarBottomTintColor"] = navController.toolbar.tintColor?.hexString - realOptions["presentationStyle"] = navController.modalPresentationStyle.rawValue - realOptions["transitionStyle"] = navController.modalTransitionStyle.rawValue - } - } - return realOptions - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserWebViewController.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserWebViewController.swift deleted file mode 100755 index 0fece252fd..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppBrowser/InAppBrowserWebViewController.swift +++ /dev/null @@ -1,656 +0,0 @@ -// -// InAppBrowserWebViewController.swift -// flutter_inappwebview -// -// Created by Lorenzo on 17/09/18. -// - -import Flutter -import UIKit -import WebKit -import Foundation - -public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelegate, UIScrollViewDelegate, UISearchBarDelegate, Disposable { - static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappbrowser_" - - var closeButton: UIBarButtonItem! - var reloadButton: UIBarButtonItem! - var backButton: UIBarButtonItem! - var forwardButton: UIBarButtonItem! - var shareButton: UIBarButtonItem! - var searchBar: UISearchBar! - var progressBar: UIProgressView! - var menuButton: UIBarButtonItem? - private var _menu: Any? - @available(iOS 13.0, *) - var menu: UIMenu? { - set { - _menu = newValue - } - get { - return _menu as? UIMenu - } - } - - var tmpWindow: UIWindow? - var id: String = "" - var plugin: InAppWebViewFlutterPlugin? - var windowId: Int64? - var webView: InAppWebView? - var channelDelegate: InAppBrowserChannelDelegate? - var initialUrlRequest: URLRequest? - var initialFile: String? - var contextMenu: [String: Any]? - var browserSettings: InAppBrowserSettings? - var webViewSettings: InAppWebViewSettings? - var initialData: String? - var initialMimeType: String? - var initialEncoding: String? - var initialBaseUrl: String? - var initialUserScripts: [[String: Any]] = [] - var pullToRefreshInitialSettings: [String: Any?] = [:] - var isHidden = false - var menuItems: [InAppBrowserMenuItem] = [] - - public override func loadView() { - guard let plugin = plugin else { - return - } - - let channel = FlutterMethodChannel(name: InAppBrowserWebViewController.METHOD_CHANNEL_NAME_PREFIX + id, binaryMessenger: plugin.registrar.messenger()) - channelDelegate = InAppBrowserChannelDelegate(channel: channel) - - var userScripts: [UserScript] = [] - for initialUserScript in initialUserScripts { - userScripts.append(UserScript.fromMap(map: initialUserScript, windowId: windowId)!) - } - - let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(settings: webViewSettings) - if let wId = windowId, let webViewTransport = plugin.inAppWebViewManager?.windowWebViews[wId] { - webView = webViewTransport.webView - webView!.contextMenu = contextMenu - webView!.initialUserScripts = userScripts - } else { - webView = InAppWebView(id: nil, - plugin: nil, - frame: .zero, - configuration: preWebviewConfiguration, - contextMenu: contextMenu, - userScripts: userScripts) - } - - guard let webView = webView else { - return - } - - webView.inAppBrowserDelegate = self - webView.id = id - webView.plugin = plugin - webView.channelDelegate = WebViewChannelDelegate(webView: webView, channel: channel) - - let pullToRefreshSettings = PullToRefreshSettings() - let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings) - let pullToRefreshControl = PullToRefreshControl(plugin: plugin, id: id, settings: pullToRefreshSettings) - webView.pullToRefreshControl = pullToRefreshControl - pullToRefreshControl.delegate = webView - pullToRefreshControl.prepare() - - let findInteractionController = FindInteractionController( - plugin: plugin, - id: id, webView: webView, settings: nil) - webView.findInteractionController = findInteractionController - findInteractionController.prepare() - - prepareWebView() - webView.windowCreated = true - - progressBar = UIProgressView(progressViewStyle: .bar) - - view = UIView() - view.addSubview(webView) - view.insertSubview(progressBar, aboveSubview: webView) - } - - public override func viewDidLoad() { - super.viewDidLoad() - - webView?.translatesAutoresizingMaskIntoConstraints = false - progressBar.translatesAutoresizingMaskIntoConstraints = false - - if #available(iOS 9.0, *) { - webView?.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0.0).isActive = true - webView?.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0.0).isActive = true - webView?.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0.0).isActive = true - webView?.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0.0).isActive = true - - progressBar.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0.0).isActive = true - progressBar.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0.0).isActive = true - progressBar.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0.0).isActive = true - } else { - if let webView = webView { - view.addConstraints([ - NSLayoutConstraint(item: webView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0), - NSLayoutConstraint(item: webView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0), - NSLayoutConstraint(item: webView, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: 0), - NSLayoutConstraint(item: webView, attribute: .right, relatedBy: .equal, toItem: view, attribute: .right, multiplier: 1, constant: 0) - ]) - } - if let progressBar = progressBar { - view.addConstraints([ - NSLayoutConstraint(item: progressBar, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0), - NSLayoutConstraint(item: progressBar, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: 0), - NSLayoutConstraint(item: progressBar, attribute: .right, relatedBy: .equal, toItem: view, attribute: .right, multiplier: 1, constant: 0) - ]) - } - } - - if windowId != nil { - channelDelegate?.onBrowserCreated() - webView?.runWindowBeforeCreatedCallbacks() - } else { - if #available(iOS 11.0, *) { - if let contentBlockers = webView?.settings?.contentBlockers, contentBlockers.count > 0 { - do { - let jsonData = try JSONSerialization.data(withJSONObject: contentBlockers, options: []) - let blockRules = String(data: jsonData, encoding: .utf8) - WKContentRuleListStore.default().compileContentRuleList( - forIdentifier: "ContentBlockingRules", - encodedContentRuleList: blockRules) { (contentRuleList, error) in - - if let error = error { - print(error.localizedDescription) - return - } - - let configuration = self.webView!.configuration - configuration.userContentController.add(contentRuleList!) - - self.initLoad() - } - return - } catch { - print(error.localizedDescription) - } - } - } - - initLoad() - } - } - - public func initLoad() { - if let initialFile = initialFile { - do { - try webView?.loadFile(assetFilePath: initialFile) - } - catch let error as NSError { - dump(error) - } - } - else if let initialData = initialData { - let baseUrl = URL(string: initialBaseUrl ?? "about:blank")! - var allowingReadAccessToURL: URL? = nil - if let allowingReadAccessTo = webView?.settings?.allowingReadAccessTo, baseUrl.scheme == "file" { - allowingReadAccessToURL = URL(string: allowingReadAccessTo) - if allowingReadAccessToURL?.scheme != "file" { - allowingReadAccessToURL = nil - } - } - webView?.loadData(data: initialData, mimeType: initialMimeType!, encoding: initialEncoding!, baseUrl: baseUrl, allowingReadAccessTo: allowingReadAccessToURL) - } - else if let initialUrlRequest = initialUrlRequest { - var allowingReadAccessToURL: URL? = nil - if let allowingReadAccessTo = webView?.settings?.allowingReadAccessTo, let url = initialUrlRequest.url, url.scheme == "file" { - allowingReadAccessToURL = URL(string: allowingReadAccessTo) - if allowingReadAccessToURL?.scheme != "file" { - allowingReadAccessToURL = nil - } - } - webView?.loadUrl(urlRequest: initialUrlRequest, allowingReadAccessTo: allowingReadAccessToURL) - } - - channelDelegate?.onBrowserCreated() - } - - public override func viewDidDisappear(_ animated: Bool) { - if !isHidden { - dispose() - } - super.viewDidDisappear(animated) - } - - public override func viewWillDisappear (_ animated: Bool) { - super.viewWillDisappear(animated) - } - - public func prepareNavigationControllerBeforeViewWillAppear() { - if let browserOptions = browserSettings { - navigationController?.modalPresentationStyle = UIModalPresentationStyle(rawValue: browserOptions.presentationStyle)! - navigationController?.modalTransitionStyle = UIModalTransitionStyle(rawValue: browserOptions.transitionStyle)! - } - } - - public func prepareWebView() { - webView?.settings = webViewSettings - webView?.prepare() - - searchBar = UISearchBar() - searchBar.keyboardType = .URL - searchBar.sizeToFit() - searchBar.delegate = self - navigationItem.titleView = searchBar - - let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) - reloadButton = UIBarButtonItem(barButtonSystemItem: .refresh, target: self, action: #selector(reload)) - shareButton = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(share)) - forwardButton = UIBarButtonItem(title: "\u{203A}", style: .plain, target: self, action: #selector(goForward)) - forwardButton.isEnabled = false - backButton = UIBarButtonItem(title: "\u{2039}", style: .plain, target: self, action: #selector(goBack)) - backButton.isEnabled = false - - toolbarItems = [backButton, spacer, forwardButton, spacer, shareButton, spacer, reloadButton] - - for state: UIControl.State in [.normal, .disabled, .highlighted, .selected] { - forwardButton.setTitleTextAttributes([ - NSAttributedString.Key.font: UIFont.systemFont(ofSize: 50.0), - NSAttributedString.Key.baselineOffset: 2.5 - ], for: state) - backButton.setTitleTextAttributes([ - NSAttributedString.Key.font: UIFont.systemFont(ofSize: 50.0), - NSAttributedString.Key.baselineOffset: 2.5 - ], for: state) - } - - if let browserSettings = browserSettings { - if !browserSettings.hideToolbarTop { - navigationController?.navigationBar.isHidden = false - if browserSettings.hideUrlBar { - searchBar.isHidden = true - } - if let bgColor = browserSettings.toolbarTopBackgroundColor, !bgColor.isEmpty { - navigationController?.navigationBar.backgroundColor = UIColor(hexString: bgColor) - } - if let barTintColor = browserSettings.toolbarTopBarTintColor, !barTintColor.isEmpty { - navigationController?.navigationBar.barTintColor = UIColor(hexString: barTintColor) - } - if let tintColor = browserSettings.toolbarTopTintColor, !tintColor.isEmpty { - navigationController?.navigationBar.tintColor = UIColor(hexString: tintColor) - } - navigationController?.navigationBar.isTranslucent = browserSettings.toolbarTopTranslucent - } - else { - navigationController?.navigationBar.isHidden = true - } - - if !browserSettings.hideToolbarBottom { - navigationController?.isToolbarHidden = false - if let bgColor = browserSettings.toolbarBottomBackgroundColor, !bgColor.isEmpty { - navigationController?.toolbar.barTintColor = UIColor(hexString: bgColor) - } - if let tintColor = browserSettings.toolbarBottomTintColor, !tintColor.isEmpty { - navigationController?.toolbar.tintColor = UIColor(hexString: tintColor) - } - navigationController?.toolbar.isTranslucent = false - } - else { - navigationController?.isToolbarHidden = true - } - - if let closeButtonCaption = browserSettings.closeButtonCaption, !closeButtonCaption.isEmpty { - closeButton = UIBarButtonItem(title: closeButtonCaption, style: .plain, target: self, action: #selector(close)) - } else { - setDefaultCloseButton() - } - - if let closeButtonColor = browserSettings.closeButtonColor, !closeButtonColor.isEmpty { - closeButton.tintColor = UIColor(hexString: closeButtonColor) - } - - if browserSettings.hideProgressBar { - progressBar.isHidden = true - } - - navigationItem.rightBarButtonItems = [] - - if !browserSettings.hideCloseButton { - navigationItem.rightBarButtonItems = [closeButton] - } - - if #available(iOS 14.0, *), !menuItems.isEmpty { - var uiActions: [UIAction] = [] - menuItems = menuItems.sorted(by: {$0.order ?? 0 < $1.order ?? 0}) - for menuItem in menuItems { - let uiAction = UIAction(title: menuItem.title, image: menuItem.icon, handler: {_ in - self.channelDelegate?.onMenuItemClicked(menuItem: menuItem) - }) - if !menuItem.showAsAction { - uiActions.append(uiAction) - } else { - let buttonItem = UIBarButtonItem(primaryAction: uiAction) - buttonItem.tintColor = menuItem.iconColor - navigationItem.rightBarButtonItems?.append(buttonItem) - } - } - if !uiActions.isEmpty { - menu = UIMenu(title: "", options: .displayInline, children: uiActions) - menuButton = UIBarButtonItem(image: UIImage(systemName: "ellipsis.circle"), menu: menu) - if let menuButtonColor = browserSettings.menuButtonColor, !menuButtonColor.isEmpty { - menuButton?.tintColor = UIColor(hexString: menuButtonColor) - } - let index = browserSettings.hideCloseButton ? 0 : 1 - navigationItem.rightBarButtonItems?.insert(menuButton!, at: index) - } - } - } - } - - func setDefaultCloseButton() { - if closeButton != nil { - closeButton.target = nil - closeButton.action = nil - } - var barButtonSystemItem = UIBarButtonItem.SystemItem.cancel - if #available(iOS 13.0, *) { - barButtonSystemItem = UIBarButtonItem.SystemItem.close - } - closeButton = UIBarButtonItem(barButtonSystemItem: barButtonSystemItem, target: self, action: #selector(close)) - } - - public func didChangeTitle(title: String?) { - guard let _ = title else { - return - } - } - - public func didStartNavigation(url: URL?) { - forwardButton.isEnabled = webView?.canGoForward ?? false - backButton.isEnabled = webView?.canGoBack ?? false - progressBar.setProgress(0.0, animated: false) - guard let url = url else { - return - } - searchBar.text = url.absoluteString - } - - public func didUpdateVisitedHistory(url: URL?) { - forwardButton.isEnabled = webView?.canGoForward ?? false - backButton.isEnabled = webView?.canGoBack ?? false - guard let url = url else { - return - } - searchBar.text = url.absoluteString - } - - public func didFinishNavigation(url: URL?) { - forwardButton.isEnabled = webView?.canGoForward ?? false - backButton.isEnabled = webView?.canGoBack ?? false - progressBar.setProgress(0.0, animated: false) - guard let url = url else { - return - } - searchBar.text = url.absoluteString - } - - public func didFailNavigation(url: URL?, error: Error) { - forwardButton.isEnabled = webView?.canGoForward ?? false - backButton.isEnabled = webView?.canGoBack ?? false - progressBar.setProgress(0.0, animated: false) - } - - public func didChangeProgress(progress: Double) { - progressBar.setProgress(Float(progress), animated: true) - } - - public func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { - guard let text = searchBar.text, - let urlEncoded = text.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), - let url = URL(string: urlEncoded) else { - return - } - let request = URLRequest(url: url) - webView?.load(request) - } - - public func show(completion: (() -> Void)? = nil) { - if let visibleViewController = UIApplication.shared.visibleViewController, - let navigationController = navigationController { - isHidden = false - visibleViewController.present(navigationController, animated: true) { - completion?() - } - } else { - completion?() - } - } - - public func hide(completion: (() -> Void)? = nil) { - if let navigationController = navigationController { - isHidden = true - navigationController.dismiss(animated: true) { - completion?() - UIApplication.shared.delegate?.window??.makeKeyAndVisible() - } - } else { - completion?() - UIApplication.shared.delegate?.window??.makeKeyAndVisible() - } - } - - @objc public func reload() { - webView?.reload() - didUpdateVisitedHistory(url: webView?.url) - } - - @objc public func share() { - let vc = UIActivityViewController(activityItems: [webView?.url?.absoluteString ?? ""], applicationActivities: []) - present(vc, animated: true, completion: nil) - } - - public func close(completion: (() -> Void)? = nil) { - if (navigationController?.responds(to: #selector(getter: navigationController?.presentingViewController)))! { - if let presentingViewController = navigationController?.presentingViewController { - presentingViewController.dismiss(animated: true, completion: {() -> Void in - completion?() - self.dispose() - }) - } else { - completion?() - dispose() - } - } - else { - if let parent = navigationController?.parent { - parent.dismiss(animated: true, completion: {() -> Void in - completion?() - self.dispose() - }) - } else { - completion?() - dispose() - } - } - } - - @objc public func close() { - close(completion: nil) - } - - @objc public func goBack() { - if let webView = webView, webView.canGoBack { - webView.goBack() - } - } - - @objc public func goForward() { - if let webView = webView, webView.canGoForward { - webView.goForward() - } - } - - @objc public func goBackOrForward(steps: Int) { - webView?.goBackOrForward(steps: steps) - } - - public func setSettings(newSettings: InAppBrowserSettings, newSettingsMap: [String: Any]) { - let newInAppWebViewSettings = InAppWebViewSettings() - let _ = newInAppWebViewSettings.parse(settings: newSettingsMap) - webView?.setSettings(newSettings: newInAppWebViewSettings, newSettingsMap: newSettingsMap) - - if newSettingsMap["hidden"] != nil, browserSettings?.hidden != newSettings.hidden { - if newSettings.hidden { - hide() - } - else { - show() - } - } - - if newSettingsMap["hideUrlBar"] != nil, browserSettings?.hideUrlBar != newSettings.hideUrlBar { - searchBar.isHidden = newSettings.hideUrlBar - } - - if newSettingsMap["hideToolbarTop"] != nil, browserSettings?.hideToolbarTop != newSettings.hideToolbarTop { - navigationController?.navigationBar.isHidden = newSettings.hideToolbarTop - } - - if newSettingsMap["toolbarTopBackgroundColor"] != nil, browserSettings?.toolbarTopBackgroundColor != newSettings.toolbarTopBackgroundColor { - if let bgColor = newSettings.toolbarTopBackgroundColor, !bgColor.isEmpty { - navigationController?.navigationBar.backgroundColor = UIColor(hexString: bgColor) - } else { - navigationController?.navigationBar.backgroundColor = nil - } - } - - if newSettingsMap["toolbarTopBarTintColor"] != nil, browserSettings?.toolbarTopBarTintColor != newSettings.toolbarTopBarTintColor { - if let barTintColor = newSettings.toolbarTopBarTintColor, !barTintColor.isEmpty { - navigationController?.navigationBar.barTintColor = UIColor(hexString: barTintColor) - } else { - navigationController?.navigationBar.barTintColor = nil - } - } - - if newSettingsMap["toolbarTopTintColor"] != nil, browserSettings?.toolbarTopTintColor != newSettings.toolbarTopTintColor { - if let tintColor = newSettings.toolbarTopTintColor, !tintColor.isEmpty { - navigationController?.navigationBar.tintColor = UIColor(hexString: tintColor) - } else { - navigationController?.navigationBar.tintColor = nil - } - } - - if newSettingsMap["hideToolbarBottom"] != nil, browserSettings?.hideToolbarBottom != newSettings.hideToolbarBottom { - navigationController?.isToolbarHidden = !newSettings.hideToolbarBottom - } - - if newSettingsMap["toolbarBottomBackgroundColor"] != nil, browserSettings?.toolbarBottomBackgroundColor != newSettings.toolbarBottomBackgroundColor { - if let bgColor = newSettings.toolbarBottomBackgroundColor, !bgColor.isEmpty { - navigationController?.toolbar.barTintColor = UIColor(hexString: bgColor) - } else { - navigationController?.toolbar.barTintColor = nil - } - } - - if newSettingsMap["toolbarBottomTintColor"] != nil, browserSettings?.toolbarBottomTintColor != newSettings.toolbarBottomTintColor { - if let tintColor = newSettings.toolbarBottomTintColor, !tintColor.isEmpty { - navigationController?.toolbar.tintColor = UIColor(hexString: tintColor) - } else { - navigationController?.toolbar.tintColor = nil - } - } - - if newSettingsMap["toolbarTopTranslucent"] != nil, browserSettings?.toolbarTopTranslucent != newSettings.toolbarTopTranslucent { - navigationController?.navigationBar.isTranslucent = newSettings.toolbarTopTranslucent - } - - if newSettingsMap["toolbarBottomTranslucent"] != nil, browserSettings?.toolbarBottomTranslucent != newSettings.toolbarBottomTranslucent { - navigationController?.toolbar.isTranslucent = newSettings.toolbarBottomTranslucent - } - - if newSettingsMap["closeButtonCaption"] != nil, browserSettings?.closeButtonCaption != newSettings.closeButtonCaption { - if let closeButtonCaption = newSettings.closeButtonCaption, !closeButtonCaption.isEmpty { - if let oldTitle = closeButton.title, !oldTitle.isEmpty { - closeButton.title = closeButtonCaption - } else { - closeButton.target = nil - closeButton.action = nil - closeButton = UIBarButtonItem(title: closeButtonCaption, style: .plain, target: self, action: #selector(close)) - } - } else { - setDefaultCloseButton() - } - } - - if newSettingsMap["closeButtonColor"] != nil, browserSettings?.closeButtonColor != newSettings.closeButtonColor { - if let tintColor = newSettings.closeButtonColor, !tintColor.isEmpty { - closeButton.tintColor = UIColor(hexString: tintColor) - } else { - closeButton.tintColor = nil - } - } - - if newSettingsMap["hideCloseButton"] != nil, browserSettings?.hideCloseButton != newSettings.hideCloseButton { - if !newSettings.hideCloseButton { - navigationItem.rightBarButtonItems = [closeButton] - } else { - navigationItem.rightBarButtonItems = [] - } - } - - if newSettingsMap["presentationStyle"] != nil, browserSettings?.presentationStyle != newSettings.presentationStyle { - navigationController?.modalPresentationStyle = UIModalPresentationStyle(rawValue: newSettings.presentationStyle)! - } - - if newSettingsMap["transitionStyle"] != nil, browserSettings?.transitionStyle != newSettings.transitionStyle { - navigationController?.modalTransitionStyle = UIModalTransitionStyle(rawValue: newSettings.transitionStyle)! - } - - if newSettingsMap["hideProgressBar"] != nil, browserSettings?.hideProgressBar != newSettings.hideProgressBar { - progressBar.isHidden = newSettings.hideProgressBar - } - - if newSettingsMap["menuButtonColor"] != nil, browserSettings?.menuButtonColor != newSettings.menuButtonColor { - if let tintColor = newSettings.menuButtonColor, !tintColor.isEmpty { - menuButton?.tintColor = UIColor(hexString: tintColor) - } else { - menuButton?.tintColor = nil - } - } - - browserSettings = newSettings - webViewSettings = newInAppWebViewSettings - } - - public func getSettings() -> [String: Any?]? { - let webViewSettingsMap = webView?.getSettings() - if (self.browserSettings == nil || webViewSettingsMap == nil) { - return nil - } - var settingsMap = self.browserSettings!.getRealSettings(obj: self) - settingsMap.merge(webViewSettingsMap!, uniquingKeysWith: { (current, _) in current }) - return settingsMap - } - - public func dispose() { - channelDelegate?.onExit() - channelDelegate?.dispose() - channelDelegate = nil - webView?.dispose() - webView?.removeFromSuperview() - webView = nil - view = nil - transitioningDelegate = nil - searchBar?.delegate = nil - closeButton?.target = nil - forwardButton?.target = nil - backButton?.target = nil - reloadButton?.target = nil - shareButton?.target = nil - menuButton?.target = nil - plugin?.inAppBrowserManager?.navControllers[id] = nil - plugin = nil - } - - deinit { - debugPrint("InAppBrowserWebViewController - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/ContextMenuSettings.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/ContextMenuSettings.swift deleted file mode 100644 index 9009e53644..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/ContextMenuSettings.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// ContextMenuOptions.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 30/05/2020. -// - -import Foundation - -public class ContextMenuSettings: ISettings { - - var hideDefaultSystemContextMenuItems = false - - override init(){ - super.init() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/CustomSchemeHandler.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/CustomSchemeHandler.swift deleted file mode 100755 index 22abdf2403..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/CustomSchemeHandler.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// CustomSchemeHandler.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 25/10/2019. -// - -import Flutter -import Foundation -import WebKit - -@available(iOS 11.0, *) -public class CustomSchemeHandler: NSObject, WKURLSchemeHandler { - var schemeHandlers: [Int: WKURLSchemeTask] = [:] - - public func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) { - schemeHandlers[urlSchemeTask.hash] = urlSchemeTask - let inAppWebView = webView as! InAppWebView - let request = WebResourceRequest.init(fromURLRequest: urlSchemeTask.request) - let callback = WebViewChannelDelegate.LoadResourceWithCustomSchemeCallback() - callback.nonNullSuccess = { (response: CustomSchemeResponse) in - if (self.schemeHandlers[urlSchemeTask.hash] != nil) { - let urlResponse = URLResponse(url: request.url, mimeType: response.contentType, expectedContentLength: -1, textEncodingName: response.contentEncoding) - urlSchemeTask.didReceive(urlResponse) - urlSchemeTask.didReceive(response.data) - urlSchemeTask.didFinish() - self.schemeHandlers.removeValue(forKey: urlSchemeTask.hash) - } - return false - } - callback.error = { (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - } - - if let channelDelegate = inAppWebView.channelDelegate { - channelDelegate.onLoadResourceWithCustomScheme(request: request, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - public func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) { - schemeHandlers.removeValue(forKey: urlSchemeTask.hash) - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/FlutterWebViewController.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/FlutterWebViewController.swift deleted file mode 100755 index 8fba99d492..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/FlutterWebViewController.swift +++ /dev/null @@ -1,212 +0,0 @@ -// -// FlutterWebViewController.swift -// flutter_inappwebview -// -// Created by Lorenzo on 13/11/18. -// - -import Foundation -import WebKit -import Flutter - -public class FlutterWebViewController: NSObject, FlutterPlatformView, Disposable { - - var myView: UIView? - var keepAliveId: String? - - init(plugin: InAppWebViewFlutterPlugin, withFrame frame: CGRect, viewIdentifier viewId: Any, params: NSDictionary) { - super.init() - - myView = UIView(frame: frame) - myView!.clipsToBounds = true - - keepAliveId = params["keepAliveId"] as? String - - let initialSettings = params["initialSettings"] as! [String: Any?] - let contextMenu = params["contextMenu"] as? [String: Any] - let windowId = params["windowId"] as? Int64 - let initialUserScripts = params["initialUserScripts"] as? [[String: Any]] - let pullToRefreshInitialSettings = params["pullToRefreshSettings"] as! [String: Any?] - - var userScripts: [UserScript] = [] - if let initialUserScripts = initialUserScripts { - for initialUserScript in initialUserScripts { - userScripts.append(UserScript.fromMap(map: initialUserScript, windowId: windowId)!) - } - } - - let settings = InAppWebViewSettings() - let _ = settings.parse(settings: initialSettings) - let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(settings: settings) - - var webView: InAppWebView? - - if let wId = windowId, let webViewTransport = plugin.inAppWebViewManager?.windowWebViews[wId] { - webView = webViewTransport.webView - webView!.id = viewId - webView!.plugin = plugin - let channel = FlutterMethodChannel(name: InAppWebView.METHOD_CHANNEL_NAME_PREFIX + String(describing: viewId), - binaryMessenger: plugin.registrar.messenger()) - webView!.channelDelegate = WebViewChannelDelegate(webView: webView!, channel: channel) - webView!.frame = myView!.bounds - webView!.contextMenu = contextMenu - webView!.initialUserScripts = userScripts - } else { - webView = InAppWebView(id: viewId, - plugin: plugin, - frame: myView!.bounds, - configuration: preWebviewConfiguration, - contextMenu: contextMenu, - userScripts: userScripts) - } - - let pullToRefreshSettings = PullToRefreshSettings() - let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings) - let pullToRefreshControl = PullToRefreshControl(plugin: plugin, id: viewId, settings: pullToRefreshSettings) - webView!.pullToRefreshControl = pullToRefreshControl - pullToRefreshControl.delegate = webView! - pullToRefreshControl.prepare() - - let findInteractionController = FindInteractionController( - plugin: plugin, - id: viewId, webView: webView!, settings: nil) - webView!.findInteractionController = findInteractionController - findInteractionController.prepare() - - webView!.autoresizingMask = [.flexibleWidth, .flexibleHeight] - myView!.autoresizesSubviews = true - myView!.autoresizingMask = [.flexibleWidth, .flexibleHeight] - myView!.addSubview(webView!) - - webView!.settings = settings - webView!.prepare() - webView!.windowCreated = true - } - - public func webView() -> InAppWebView? { - for subview in myView?.subviews ?? [] - { - if let item = subview as? InAppWebView - { - return item - } - } - return nil - } - - public func view() -> UIView { - return myView! - } - - public func makeInitialLoad(params: NSDictionary) { - guard let webView = webView() else { - return - } - - let windowId = params["windowId"] as? Int64 - let initialUrlRequest = params["initialUrlRequest"] as? [String: Any?] - let initialFile = params["initialFile"] as? String - let initialData = params["initialData"] as? [String: String?] - - if windowId == nil { - if #available(iOS 11.0, *) { - webView.configuration.userContentController.removeAllContentRuleLists() - if let contentBlockers = webView.settings?.contentBlockers, contentBlockers.count > 0 { - do { - let jsonData = try JSONSerialization.data(withJSONObject: contentBlockers, options: []) - let blockRules = String(data: jsonData, encoding: .utf8) - WKContentRuleListStore.default().compileContentRuleList( - forIdentifier: "ContentBlockingRules", - encodedContentRuleList: blockRules) { (contentRuleList, error) in - - if let error = error { - print(error.localizedDescription) - return - } - - let configuration = webView.configuration - configuration.userContentController.add(contentRuleList!) - - self.load(initialUrlRequest: initialUrlRequest, initialFile: initialFile, initialData: initialData) - } - return - } catch { - print(error.localizedDescription) - } - } - } - load(initialUrlRequest: initialUrlRequest, initialFile: initialFile, initialData: initialData) - } - else if windowId != nil { - webView.runWindowBeforeCreatedCallbacks() - } - } - - func load(initialUrlRequest: [String:Any?]?, initialFile: String?, initialData: [String: String?]?) { - guard let webView = webView() else { - return - } - - if let initialFile = initialFile { - do { - try webView.loadFile(assetFilePath: initialFile) - } - catch let error as NSError { - dump(error) - } - } - else if let initialData = initialData, let data = initialData["data"]!, - let mimeType = initialData["mimeType"]!, let encoding = initialData["encoding"]!, - let baseUrl = URL(string: initialData["baseUrl"]! ?? "about:blank") { - var allowingReadAccessToURL: URL? = nil - if let allowingReadAccessTo = webView.settings?.allowingReadAccessTo, baseUrl.scheme == "file" { - allowingReadAccessToURL = URL(string: allowingReadAccessTo) - if allowingReadAccessToURL?.scheme != "file" { - allowingReadAccessToURL = nil - } - } - webView.loadData(data: data, - mimeType: mimeType, - encoding: encoding, - baseUrl: baseUrl, - allowingReadAccessTo: allowingReadAccessToURL) - } - else if let initialUrlRequest = initialUrlRequest { - let urlRequest = URLRequest.init(fromPluginMap: initialUrlRequest) - var allowingReadAccessToURL: URL? = nil - if let allowingReadAccessTo = webView.settings?.allowingReadAccessTo, let url = urlRequest.url, url.scheme == "file" { - allowingReadAccessToURL = URL(string: allowingReadAccessTo) - if allowingReadAccessToURL?.scheme != "file" { - allowingReadAccessToURL = nil - } - } - webView.loadUrl(urlRequest: urlRequest, allowingReadAccessTo: allowingReadAccessToURL) - } - } - - // method added to fix: - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1837 - public func dispose(removeFromSuperview: Bool) { - if keepAliveId == nil { - if let webView = webView() { - webView.dispose() - if removeFromSuperview { - webView.removeFromSuperview() - } - } - if removeFromSuperview { - myView?.removeFromSuperview() - } - myView = nil - } - } - - public func dispose() { - dispose(removeFromSuperview: false) - } - - deinit { - debugPrint("FlutterWebViewController - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/FlutterWebViewFactory.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/FlutterWebViewFactory.swift deleted file mode 100755 index 013de7b95f..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/FlutterWebViewFactory.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// FlutterWebViewFactory.swift -// flutter_inappwebview -// -// Created by Lorenzo on 13/11/18. -// - -import Flutter -import Foundation - -public class FlutterWebViewFactory: NSObject, FlutterPlatformViewFactory { - static let VIEW_TYPE_ID = "com.pichillilorenzo/flutter_inappwebview" - - private var plugin: InAppWebViewFlutterPlugin - - init(plugin: InAppWebViewFlutterPlugin) { - self.plugin = plugin - super.init() - } - - public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol { - return FlutterStandardMessageCodec.sharedInstance() - } - - public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView { - let arguments = args as? NSDictionary - var flutterWebView: FlutterWebViewController? - var id: Any = viewId - - let keepAliveId = arguments?["keepAliveId"] as? String - let headlessWebViewId = arguments?["headlessWebViewId"] as? String - let preventGestureDelay = arguments?["preventGestureDelay"] as? Bool ?? false - - if let headlessWebViewId = headlessWebViewId, - let headlessWebView = plugin.headlessInAppWebViewManager?.webViews[headlessWebViewId], - let platformView = headlessWebView?.disposeAndGetFlutterWebView(withFrame: frame) { - flutterWebView = platformView - flutterWebView?.keepAliveId = keepAliveId - } - - if let keepAliveId = keepAliveId, - flutterWebView == nil, - let keepAliveWebView = plugin.inAppWebViewManager?.keepAliveWebViews[keepAliveId] { - flutterWebView = keepAliveWebView - if let view = flutterWebView?.view() { - // remove from parent - view.removeFromSuperview() - } - } - - let shouldMakeInitialLoad = flutterWebView == nil - if flutterWebView == nil { - if let keepAliveId = keepAliveId { - id = keepAliveId - } - flutterWebView = FlutterWebViewController(plugin: plugin, - withFrame: frame, - viewIdentifier: id, - params: arguments!) - } - - if let keepAliveId = keepAliveId { - plugin.inAppWebViewManager?.keepAliveWebViews[keepAliveId] = flutterWebView! - } - - flutterWebView?.webView()?.preventGestureDelay = preventGestureDelay - - if shouldMakeInitialLoad { - flutterWebView?.makeInitialLoad(params: arguments!) - } - - return flutterWebView! - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/InAppWebView.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/InAppWebView.swift deleted file mode 100755 index 09f244da5e..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/InAppWebView.swift +++ /dev/null @@ -1,3596 +0,0 @@ -// -// InAppWebView.swift -// flutter_inappwebview -// -// Created by Lorenzo on 21/10/18. -// - -import Flutter -import Foundation -@preconcurrency import WebKit - -public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, - WKNavigationDelegate, WKScriptMessageHandler, UIGestureRecognizerDelegate, - WKDownloadDelegate, - PullToRefreshDelegate, - Disposable { - static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_" - - var id: Any? // viewId - var plugin: InAppWebViewFlutterPlugin? - var windowId: Int64? - var windowCreated = false - var windowBeforeCreatedCallbacks: [() -> ()] = [] - var inAppBrowserDelegate: InAppBrowserDelegate? - var channelDelegate: WebViewChannelDelegate? - var settings: InAppWebViewSettings? - var pullToRefreshControl: PullToRefreshControl? - var findInteractionController: FindInteractionController? - var webMessageChannels: [String: WebMessageChannel] = [:] - var webMessageListeners: [WebMessageListener] = [] - var currentOriginalUrl: URL? - var inFullscreen = false - weak var fullscreenWindow: UIWindow? // Track the window that entered fullscreen - var preventGestureDelay = false - - private static var sslCertificatesMap: [String: SslCertificate] = [:] // [URL host name : SslCertificate] - private static var credentialsProposed: [URLCredential] = [] - - var lastScrollX: CGFloat = 0 - var lastScrollY: CGFloat = 0 - - // Used to manage pauseTimers() and resumeTimers() - var isPausedTimers = false - var isPausedTimersCompletionHandler: (() -> Void)? - - var contextMenu: [String: Any]? - var initialUserScripts: [UserScript] = [] - - // https://github.com/mozilla-mobile/firefox-ios/blob/50531a7e9e4d459fb11d4fcb7d4322e08103501f/Client/Frontend/Browser/ContextMenuHelper.swift - fileprivate var nativeHighlightLongPressRecognizer: UILongPressGestureRecognizer? - fileprivate var nativeLoupeGesture: UILongPressGestureRecognizer? - var longPressRecognizer: UILongPressGestureRecognizer! - var recognizerForDisablingContextMenuOnLinks: UILongPressGestureRecognizer! - var lastLongPressTouchPoint: CGPoint? - - var panGestureRecognizer: UIPanGestureRecognizer! - - var lastTouchPoint: CGPoint? - var lastTouchPointTimestamp = Int64(Date().timeIntervalSince1970 * 1000) - - var contextMenuIsShowing = false - // flag used for the workaround to trigger onCreateContextMenu event as the same on Android - var onCreateContextMenuEventTriggeredWhenMenuDisabled = false - - var customIMPs: [IMP] = [] - - var callAsyncJavaScriptBelowIOS14Results: [String:((Any?) -> Void)] = [:] - - var oldZoomScale = Float(1.0) - - fileprivate var interceptOnlyAsyncAjaxRequestsPluginScript: PluginScript? - - private var exceptedBridgeSecret = NSUUID().uuidString - private var javaScriptBridgeEnabled = true - - init(id: Any?, plugin: InAppWebViewFlutterPlugin?, frame: CGRect, configuration: WKWebViewConfiguration, - contextMenu: [String: Any]?, userScripts: [UserScript] = []) { - super.init(frame: frame, configuration: configuration) - self.id = id - self.plugin = plugin - if let id = id, let registrar = plugin?.registrar { - let channel = FlutterMethodChannel(name: InAppWebView.METHOD_CHANNEL_NAME_PREFIX + String(describing: id), - binaryMessenger: registrar.messenger()) - self.channelDelegate = WebViewChannelDelegate(webView: self, channel: channel) - } - self.contextMenu = contextMenu - self.initialUserScripts = userScripts - uiDelegate = self - navigationDelegate = self - scrollView.delegate = self - longPressRecognizer = UILongPressGestureRecognizer() - longPressRecognizer.delegate = self - longPressRecognizer.addTarget(self, action: #selector(longPressGestureDetected)) - recognizerForDisablingContextMenuOnLinks = UILongPressGestureRecognizer() - recognizerForDisablingContextMenuOnLinks.delegate = self - recognizerForDisablingContextMenuOnLinks.addTarget(self, action: #selector(longPressGestureDetected)) - recognizerForDisablingContextMenuOnLinks?.minimumPressDuration = 0.45 - panGestureRecognizer = UIPanGestureRecognizer() - panGestureRecognizer.delegate = self - panGestureRecognizer.addTarget(self, action: #selector(endDraggingDetected)) - } - - override public var frame: CGRect { - get { - return super.frame - } - set { - super.frame = newValue - - scrollView.contentInset = .zero - if #available(iOS 11, *) { - // Above iOS 11, adjust contentInset to compensate the adjustedContentInset so the sum will - // always be 0. - if (scrollView.adjustedContentInset != .zero) { - let insetToAdjust = scrollView.adjustedContentInset - scrollView.contentInset = UIEdgeInsets(top: -insetToAdjust.top, left: -insetToAdjust.left, - bottom: -insetToAdjust.bottom, right: -insetToAdjust.right) - } - } - } - } - - // Fix https://github.com/pichillilorenzo/flutter_inappwebview/issues/1947 - private var _scrollViewContentInsetAdjusted = false - @objc func keyboardWillShow(notification: NSNotification) { - // UIResponder.keyboardWillShowNotification will be fired also - // when changing focus between HTML inputs with the keyboard already open - if (scrollView.adjustedContentInset != .zero) { - // if resizeToAvoidBottomInset is false on Flutter side, - // scrollView.adjustedContentInset.bottom will be > 0 - if scrollView.adjustedContentInset.bottom > 0 { - // if the scrollView.contentInset has already been fixed, do nothing - if !_scrollViewContentInsetAdjusted { - _scrollViewContentInsetAdjusted = true - let insetToAdjust = scrollView.adjustedContentInset - scrollView.contentInset = UIEdgeInsets(top: -insetToAdjust.top, left: -insetToAdjust.left, - bottom: -insetToAdjust.bottom, right: -insetToAdjust.right) - } - } else { - scrollView.contentInset = .zero - } - } - } - @objc func keyboardWillHide(notification: NSNotification) { - _scrollViewContentInsetAdjusted = false - } - - required public init(coder aDecoder: NSCoder) { - super.init(coder: aDecoder)! - } - - public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { - return true - } - - // BVC KVO events for all changes on the webview will call this. - // It is called frequently during a page load (particularly on progress changes and URL changes). - // As of iOS 12, WKContentView gesture setup is async, but it has been called by the time - // the webview is ready to load an URL. After this has happened, we can override the gesture. - func replaceGestureHandlerIfNeeded() { - DispatchQueue.main.async { - if self.gestureRecognizerWithDescriptionFragment("InAppWebView") == nil { - self.replaceWebViewLongPress() - } - } - } - - private func replaceWebViewLongPress() { - // WebKit installs gesture handlers async. If `replaceWebViewLongPress` is called after a wkwebview in most cases a small delay is sufficient - // See also https://bugs.webkit.org/show_bug.cgi?id=193366 - nativeHighlightLongPressRecognizer = gestureRecognizerWithDescriptionFragment("action=_highlightLongPressRecognized:") - nativeLoupeGesture = gestureRecognizerWithDescriptionFragment("action=loupeGesture:") - - if let nativeLongPressRecognizer = gestureRecognizerWithDescriptionFragment("action=_longPressRecognized:") { - nativeLongPressRecognizer.removeTarget(nil, action: nil) - nativeLongPressRecognizer.addTarget(self, action: #selector(self.longPressGestureDetected)) - } - } - - private func gestureRecognizerWithDescriptionFragment(_ descriptionFragment: String) -> UILongPressGestureRecognizer? { - let result = self.scrollView.subviews.compactMap({ $0.gestureRecognizers }).joined().first(where: { - return (($0 as? UILongPressGestureRecognizer) != nil) && $0.description.contains(descriptionFragment) - }) - return result as? UILongPressGestureRecognizer - } - - @objc func longPressGestureDetected(_ sender: UIGestureRecognizer) { - if sender.state == .cancelled { - return - } - - guard sender.state == .began else { - return - } - - if sender == recognizerForDisablingContextMenuOnLinks, - let settings = settings, !settings.disableLongPressContextMenuOnLinks { - return - } - - if sender == longPressRecognizer { - // To prevent the tapped link from proceeding with navigation, "cancel" the native WKWebView - // `_highlightLongPressRecognizer`. This preserves the original behavior as seen here: - // https://github.com/WebKit/webkit/blob/d591647baf54b4b300ca5501c21a68455429e182/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm#L1600-L1614 - if let nativeHighlightLongPressRecognizer = nativeHighlightLongPressRecognizer, - nativeHighlightLongPressRecognizer.isEnabled { - nativeHighlightLongPressRecognizer.isEnabled = false - nativeHighlightLongPressRecognizer.isEnabled = true - } - } - - //Finding actual touch location in webView - var touchLocation = sender.location(in: self) - touchLocation.x -= scrollView.contentInset.left - touchLocation.y -= scrollView.contentInset.top - touchLocation.x /= scrollView.zoomScale - touchLocation.y /= scrollView.zoomScale - - lastLongPressTouchPoint = touchLocation - - evaluateJavaScript("window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findElementsAtPoint(\(touchLocation.x),\(touchLocation.y))", completionHandler: {(value, error) in - if error != nil { - print("Long press gesture recognizer error: \(error?.localizedDescription ?? "")") - } else if let value = value as? [String: Any?] { - let hitTestResult = HitTestResult.fromMap(map: value)! - self.nativeLoupeGesture = self.gestureRecognizerWithDescriptionFragment("action=loupeGesture:") - - if sender == self.recognizerForDisablingContextMenuOnLinks, - hitTestResult.type.rawValue > HitTestResultType.unknownType.rawValue, - hitTestResult.type.rawValue < HitTestResultType.editTextType.rawValue { - self.nativeLoupeGesture?.isEnabled = false - self.nativeLoupeGesture?.isEnabled = true - } else { - self.channelDelegate?.onLongPressHitTestResult(hitTestResult: hitTestResult) - } - } else if sender == self.longPressRecognizer { - self.channelDelegate?.onLongPressHitTestResult(hitTestResult: HitTestResult(type: .unknownType, extra: nil)) - } - }) - } - - public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - lastTouchPoint = point - lastTouchPointTimestamp = Int64(Date().timeIntervalSince1970 * 1000) - SharedLastTouchPointTimestamp[self] = lastTouchPointTimestamp - - // re-build context menu items for the current webview - UIMenuController.shared.menuItems = [] - if let menu = self.contextMenu { - if let menuItems = menu["menuItems"] as? [[String : Any]] { - for menuItem in menuItems { - let id = menuItem["id"]! - let title = menuItem["title"] as! String - let targetMethodName = "onContextMenuActionItemClicked-" + String(self.hash) + "-" + - (id is Int64 ? String(id as! Int64) : id as! String) - if !self.responds(to: Selector(targetMethodName)) { - let customAction: () -> Void = { - self.channelDelegate?.onContextMenuActionItemClicked(id: id, title: title) - if #available(iOS 16.0, *) { - if #unavailable(iOS 16.4) { - self.onHideContextMenu() - } - } - } - let castedCustomAction: AnyObject = unsafeBitCast(customAction as @convention(block) () -> Void, to: AnyObject.self) - let swizzledImplementation = imp_implementationWithBlock(castedCustomAction) - class_addMethod(InAppWebView.self, Selector(targetMethodName), swizzledImplementation, nil) - self.customIMPs.append(swizzledImplementation) - } - let item = UIMenuItem(title: title, action: Selector(targetMethodName)) - UIMenuController.shared.menuItems!.append(item) - } - } - } - - // https://github.com/pichillilorenzo/flutter_inappwebview/pull/1665 - if preventGestureDelay, let gestures = superview?.superview?.gestureRecognizers { - for gesture in gestures { - let gestureType = NSStringFromClass(type(of: gesture)) - if gestureType == "DelayingGestureRecognizer" || gestureType == "FlutterDelayingGestureRecognizer" { - gesture.isEnabled = false - } - } - } - - return super.hitTest(point, with: event) - } - - @available(iOS 13.0, *) - public override func buildMenu(with builder: UIMenuBuilder) { - if #available(iOS 16.0, *) { - if let menu = contextMenu { - let contextMenuSettings = ContextMenuSettings() - if let contextMenuSettingsMap = menu["settings"] as? [String: Any?] { - let _ = contextMenuSettings.parse(settings: contextMenuSettingsMap) - if contextMenuSettings.hideDefaultSystemContextMenuItems { - builder.remove(menu: .lookup) - } - } - } - - if #unavailable(iOS 16.4), settings?.disableContextMenu == false { - contextMenuIsShowing = false - DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { - self.onCreateContextMenu() - } - } - } - super.buildMenu(with: builder) - } - - @available(iOS 16.4, *) - public func webView(_ webView: WKWebView, willPresentEditMenuWithAnimator animator: UIEditMenuInteractionAnimating) { - onCreateContextMenu() - } - - @available(iOS 16.4, *) - public func webView(_ webView: WKWebView, willDismissEditMenuWithAnimator animator: UIEditMenuInteractionAnimating) { - onHideContextMenu() - } - - public override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { - var needCheck = sender is UIMenuController - if #available(iOS 13.0, *) { - needCheck = sender is UIMenuElement || sender is UIMenuController - } - - if needCheck { - if settings?.disableContextMenu == true { - if !onCreateContextMenuEventTriggeredWhenMenuDisabled { - // workaround to trigger onCreateContextMenu event as the same on Android - onCreateContextMenu() - onCreateContextMenuEventTriggeredWhenMenuDisabled = true - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - self.onCreateContextMenuEventTriggeredWhenMenuDisabled = false - } - } - return false - } - - if let menu = contextMenu { - let contextMenuSettings = ContextMenuSettings() - if let contextMenuSettingsMap = menu["settings"] as? [String: Any?] { - let _ = contextMenuSettings.parse(settings: contextMenuSettingsMap) - if !action.description.starts(with: "onContextMenuActionItemClicked-") && contextMenuSettings.hideDefaultSystemContextMenuItems { - return false - } - } - } - - if contextMenuIsShowing, !action.description.starts(with: "onContextMenuActionItemClicked-") { - let id = action.description.compactMap({ $0.asciiValue?.description }).joined() - channelDelegate?.onContextMenuActionItemClicked(id: id, title: action.description) - if #available(iOS 16.0, *) { - if #unavailable(iOS 16.4) { - onHideContextMenu() - } - } - } - } - return super.canPerformAction(action, withSender: sender) - } - - // For some reasons, using the scrollViewDidEndDragging event, in some rare cases, could block - // the scroll gesture - @objc func endDraggingDetected() { - // detect end dragging - if panGestureRecognizer.state == .ended { - // fix for pull-to-refresh jittering when the touch drag event is held - if let pullToRefreshControl = pullToRefreshControl, - pullToRefreshControl.shouldCallOnRefresh { - pullToRefreshControl.onRefresh() - } - } - } - - public func prepare() { - if #available(iOS 17.2, *) { - // Fix https://github.com/pichillilorenzo/flutter_inappwebview/issues/1947 - NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), - name: UIResponder.keyboardWillShowNotification, - object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), - name: UIResponder.keyboardWillHideNotification, - object: nil) - } - - scrollView.addGestureRecognizer(self.longPressRecognizer) - scrollView.addGestureRecognizer(self.recognizerForDisablingContextMenuOnLinks) - scrollView.addGestureRecognizer(self.panGestureRecognizer) - scrollView.addObserver(self, forKeyPath: #keyPath(UIScrollView.contentOffset), options: [.new, .old], context: nil) - scrollView.addObserver(self, forKeyPath: #keyPath(UIScrollView.zoomScale), options: [.new, .old], context: nil) - scrollView.addObserver(self, forKeyPath: #keyPath(UIScrollView.contentSize), options: [.new, .old], context: nil) - - addObserver(self, - forKeyPath: #keyPath(WKWebView.estimatedProgress), - options: .new, - context: nil) - - addObserver(self, - forKeyPath: #keyPath(WKWebView.url), - options: [.new, .old], - context: nil) - - addObserver(self, - forKeyPath: #keyPath(WKWebView.title), - options: [.new, .old], - context: nil) - - if #available(iOS 15.0, *) { - addObserver(self, - forKeyPath: #keyPath(WKWebView.cameraCaptureState), - options: [.new, .old], - context: nil) - - addObserver(self, - forKeyPath: #keyPath(WKWebView.microphoneCaptureState), - options: [.new, .old], - context: nil) - } - - if #unavailable(iOS 16.0) { - NotificationCenter.default.addObserver( - self, - selector: #selector(onCreateContextMenu), - name: UIMenuController.willShowMenuNotification, - object: nil) - - NotificationCenter.default.addObserver( - self, - selector: #selector(onHideContextMenu), - name: UIMenuController.didHideMenuNotification, - object: nil) - } - - // KVO observer for fullscreenState on iOS 16.0+ - // NOTE: As of iOS 26, KVO for fullscreenState doesn't reliably fire. - // The UIWindow notifications below serve as the primary fullscreen detection mechanism. - if #available(iOS 16.0, *) { - addObserver(self, - forKeyPath: #keyPath(WKWebView.fullscreenState), - options: [.new, .old], - context: nil) - } - - // Also listen for UIWindow notifications as a fallback for fullscreen detection - // (works for iframe-based video fullscreen like YouTube) - NotificationCenter.default.addObserver(self, - selector: #selector(onEnterFullscreen(_:)), - name: UIWindow.didBecomeVisibleNotification, - object: nil) - - NotificationCenter.default.addObserver(self, - selector: #selector(onExitFullscreen(_:)), - name: UIWindow.didBecomeHiddenNotification, - object: nil) - - if let settings = settings { - isUserInteractionEnabled = settings.isUserInteractionEnabled - - if let viewAlpha = settings.alpha { - alpha = CGFloat(viewAlpha) - } - - javaScriptBridgeEnabled = settings.javaScriptBridgeEnabled - if let javaScriptBridgeOriginAllowList = settings.javaScriptBridgeOriginAllowList, javaScriptBridgeOriginAllowList.isEmpty { - // an empty list means that the JavaScript Bridge is not allowed for any origin. - javaScriptBridgeEnabled = false - } - - if settings.transparentBackground { - isOpaque = false - backgroundColor = UIColor.clear - scrollView.backgroundColor = UIColor.clear - } - - // prevent webView from bouncing - if settings.disallowOverScroll { - if responds(to: #selector(getter: scrollView)) { - scrollView.bounces = false - } - else { - for subview: UIView in subviews { - if subview is UIScrollView { - (subview as! UIScrollView).bounces = false - } - } - } - } - - if #available(iOS 11.0, *) { - accessibilityIgnoresInvertColors = settings.accessibilityIgnoresInvertColors - scrollView.contentInsetAdjustmentBehavior = - UIScrollView.ContentInsetAdjustmentBehavior.init(rawValue: settings.contentInsetAdjustmentBehavior)! - } - - allowsBackForwardNavigationGestures = settings.allowsBackForwardNavigationGestures - if #available(iOS 9.0, *) { - allowsLinkPreview = settings.allowsLinkPreview - if !settings.userAgent.isEmpty { - customUserAgent = settings.userAgent - } - } - - if #available(iOS 13.0, *) { - scrollView.automaticallyAdjustsScrollIndicatorInsets = settings.automaticallyAdjustsScrollIndicatorInsets - } - - scrollView.showsVerticalScrollIndicator = !settings.disableVerticalScroll - scrollView.showsHorizontalScrollIndicator = !settings.disableHorizontalScroll - scrollView.showsVerticalScrollIndicator = settings.verticalScrollBarEnabled - scrollView.showsHorizontalScrollIndicator = settings.horizontalScrollBarEnabled - scrollView.isScrollEnabled = !(settings.disableVerticalScroll && settings.disableHorizontalScroll) - scrollView.isDirectionalLockEnabled = settings.isDirectionalLockEnabled - - scrollView.decelerationRate = Util.getDecelerationRate(type: settings.decelerationRate) - scrollView.alwaysBounceVertical = settings.alwaysBounceVertical - scrollView.alwaysBounceHorizontal = settings.alwaysBounceHorizontal - scrollView.scrollsToTop = settings.scrollsToTop - scrollView.isPagingEnabled = settings.isPagingEnabled - scrollView.maximumZoomScale = CGFloat(settings.maximumZoomScale) - scrollView.minimumZoomScale = CGFloat(settings.minimumZoomScale) - - if #available(iOS 14.0, *) { - mediaType = settings.mediaType - pageZoom = CGFloat(settings.pageZoom) - } - - if #available(iOS 15.0, *) { - if let underPageBackgroundColor = settings.underPageBackgroundColor, !underPageBackgroundColor.isEmpty { - self.underPageBackgroundColor = UIColor(hexString: underPageBackgroundColor) - } - } - - if #available(iOS 15.5, *) { - if let minViewportInset = settings.minimumViewportInset, let maxViewportInset = settings.maximumViewportInset { - setMinimumViewportInset(minViewportInset, maximumViewportInset: maxViewportInset) - } - } - - if #available(iOS 16.0, *) { - isFindInteractionEnabled = settings.isFindInteractionEnabled - } - - if #available(iOS 16.4, *) { - isInspectable = settings.isInspectable - } - - if settings.clearCache { - clearCache() - } - } - - prepareAndAddUserScripts() - - if windowId != nil { - // The new created window webview has the same WKWebViewConfiguration variable reference. - // So, we cannot set another WKWebViewConfiguration for it unfortunately! - // This is a limitation of the official WebKit API. - return - } - - configuration.preferences = WKPreferences() - if let settings = settings { - if #available(iOS 9.0, *) { - configuration.allowsAirPlayForMediaPlayback = settings.allowsAirPlayForMediaPlayback - configuration.allowsPictureInPictureMediaPlayback = settings.allowsPictureInPictureMediaPlayback - } - - configuration.preferences.javaScriptCanOpenWindowsAutomatically = settings.javaScriptCanOpenWindowsAutomatically - configuration.preferences.minimumFontSize = CGFloat(settings.minimumFontSize) - - if #available(iOS 13.0, *) { - configuration.preferences.isFraudulentWebsiteWarningEnabled = settings.isFraudulentWebsiteWarningEnabled - configuration.defaultWebpagePreferences.preferredContentMode = WKWebpagePreferences.ContentMode(rawValue: settings.preferredContentMode)! - } - - configuration.preferences.javaScriptEnabled = settings.javaScriptEnabled - if #available(iOS 14.0, *) { - configuration.defaultWebpagePreferences.allowsContentJavaScript = settings.javaScriptEnabled - } - - if #available(iOS 15.0, *) { - configuration.preferences.isTextInteractionEnabled = settings.isTextInteractionEnabled - } - if #available(iOS 15.4, *) { - configuration.preferences.isSiteSpecificQuirksModeEnabled = settings.isSiteSpecificQuirksModeEnabled - configuration.preferences.isElementFullscreenEnabled = settings.isElementFullscreenEnabled - } - if #available(iOS 16.4, *) { - configuration.preferences.shouldPrintBackgrounds = settings.shouldPrintBackgrounds - } - } - } - - public func prepareAndAddUserScripts() -> Void { - if windowId != nil { - // The new created window webview has the same WKWebViewConfiguration variable reference. - // So, we cannot set another WKWebViewConfiguration for it unfortunately! - // This is a limitation of the official WebKit API. - return - } - configuration.userContentController.initialize() - - if let applePayAPIEnabled = settings?.applePayAPIEnabled, applePayAPIEnabled { - return - } - - if javaScriptBridgeEnabled { - let pluginScriptsOriginAllowList = settings?.pluginScriptsOriginAllowList - let pluginScriptsForMainFrameOnly = settings?.pluginScriptsForMainFrameOnly ?? true - - let javaScriptBridgeOriginAllowList = settings?.javaScriptBridgeOriginAllowList ?? pluginScriptsOriginAllowList - let javaScriptBridgeForMainFrameOnly = settings?.javaScriptBridgeForMainFrameOnly ?? pluginScriptsForMainFrameOnly - - configuration.userContentController.addPluginScript(PromisePolyfillJS.PROMISE_POLYFILL_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList, forMainFrameOnly: pluginScriptsForMainFrameOnly)) - configuration.userContentController.addPluginScript(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT(expectedBridgeSecret: exceptedBridgeSecret, allowedOriginRules: javaScriptBridgeOriginAllowList, forMainFrameOnly: javaScriptBridgeForMainFrameOnly)) - configuration.userContentController.addPluginScript(ConsoleLogJS.CONSOLE_LOG_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - configuration.userContentController.addPluginScript(PrintJS.PRINT_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList, forMainFrameOnly: pluginScriptsForMainFrameOnly)) - configuration.userContentController.addPluginScript(OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - configuration.userContentController.addPluginScript(OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - configuration.userContentController.addPluginScript(FindElementsAtPointJS.FIND_ELEMENTS_AT_POINT_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - configuration.userContentController.addPluginScript(LastTouchedAnchorOrImageJS.LAST_TOUCHED_ANCHOR_OR_IMAGE_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - configuration.userContentController.addPluginScript(FindTextHighlightJS.FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - configuration.userContentController.addPluginScript(OriginalViewPortMetaTagContentJS.ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - if let settings = settings { - interceptOnlyAsyncAjaxRequestsPluginScript = InterceptAjaxRequestJS.createInterceptOnlyAsyncAjaxRequestsPluginScript(onlyAsync: settings.interceptOnlyAsyncAjaxRequests, - allowedOriginRules: pluginScriptsOriginAllowList, forMainFrameOnly: pluginScriptsForMainFrameOnly) - if settings.useShouldInterceptAjaxRequest { - if let interceptOnlyAsyncAjaxRequestsPluginScript = interceptOnlyAsyncAjaxRequestsPluginScript { - configuration.userContentController.addPluginScript(interceptOnlyAsyncAjaxRequestsPluginScript) - } - configuration.userContentController.addPluginScript(InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList, - forMainFrameOnly: pluginScriptsForMainFrameOnly, - initialUseOnAjaxReadyStateChange: settings.useOnAjaxReadyStateChange, - initialUseOnAjaxProgress: settings.useOnAjaxProgress)) - } - if settings.useShouldInterceptFetchRequest { - configuration.userContentController.addPluginScript(InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList, forMainFrameOnly: pluginScriptsForMainFrameOnly)) - } - if settings.useOnLoadResource { - configuration.userContentController.addPluginScript(OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList, forMainFrameOnly: pluginScriptsForMainFrameOnly)) - } - if !settings.supportZoom { - configuration.userContentController.addPluginScript(SupportZoomJS.NOT_SUPPORT_ZOOM_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - } else if settings.enableViewportScale { - configuration.userContentController.addPluginScript(EnableViewportScaleJS.ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - } - } - } - configuration.userContentController.addUserOnlyScripts(initialUserScripts) - configuration.userContentController.sync(scriptMessageHandler: self) - } - - public static func preWKWebViewConfiguration(settings: InAppWebViewSettings?) -> WKWebViewConfiguration { - let configuration = WKWebViewConfiguration() - // initialzie WKUserContentController here to fix possible "undefined is not an object (evaluating 'window.webkit.messageHandlers')" javascript error - configuration.userContentController = WKUserContentController() - configuration.processPool = WKProcessPoolManager.sharedProcessPool - - if let settings = settings { - configuration.allowsInlineMediaPlayback = settings.allowsInlineMediaPlayback - configuration.suppressesIncrementalRendering = settings.suppressesIncrementalRendering - configuration.selectionGranularity = WKSelectionGranularity.init(rawValue: settings.selectionGranularity)! - - if settings.allowUniversalAccessFromFileURLs { - configuration.setValue(settings.allowUniversalAccessFromFileURLs, forKey: "allowUniversalAccessFromFileURLs") - } - - if settings.allowFileAccessFromFileURLs { - configuration.preferences.setValue(settings.allowFileAccessFromFileURLs, forKey: "allowFileAccessFromFileURLs") - } - - if #available(iOS 9.0, *) { - if settings.incognito { - configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent() - } else if settings.cacheEnabled { - configuration.websiteDataStore = WKWebsiteDataStore.default() - } - if !settings.applicationNameForUserAgent.isEmpty { - if let applicationNameForUserAgent = configuration.applicationNameForUserAgent { - configuration.applicationNameForUserAgent = applicationNameForUserAgent + " " + settings.applicationNameForUserAgent - } - } - } - - if #available(iOS 10.0, *) { - configuration.ignoresViewportScaleLimits = settings.ignoresViewportScaleLimits - - var dataDetectorTypes = WKDataDetectorTypes.init(rawValue: 0) - for type in settings.dataDetectorTypes { - let dataDetectorType = Util.getDataDetectorType(type: type) - dataDetectorTypes = WKDataDetectorTypes(rawValue: dataDetectorTypes.rawValue | dataDetectorType.rawValue) - } - configuration.dataDetectorTypes = dataDetectorTypes - - configuration.mediaTypesRequiringUserActionForPlayback = settings.mediaPlaybackRequiresUserGesture ? .all : [] - } else { - // Fallback on earlier versions - configuration.mediaPlaybackRequiresUserAction = settings.mediaPlaybackRequiresUserGesture - } - - if #available(iOS 11.0, *) { - for scheme in settings.resourceCustomSchemes { - configuration.setURLSchemeHandler(CustomSchemeHandler(), forURLScheme: scheme) - } - if settings.sharedCookiesEnabled { - // More info to sending cookies with WKWebView - // https://stackoverflow.com/questions/26573137/can-i-set-the-cookies-to-be-used-by-a-wkwebview/26577303#26577303 - // Set Cookies in iOS 11 and above, initialize websiteDataStore before setting cookies - // See also https://forums.developer.apple.com/thread/97194 - // check if websiteDataStore has not been initialized before - if(!settings.incognito && !settings.cacheEnabled) { - configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent() - } - for cookie in HTTPCookieStorage.shared.cookies ?? [] { - configuration.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil) - } - } - } - - if #available(iOS 14.0, *) { - configuration.limitsNavigationsToAppBoundDomains = settings.limitsNavigationsToAppBoundDomains - } - - if #available(iOS 15.0, *) { - configuration.upgradeKnownHostsToHTTPS = settings.upgradeKnownHostsToHTTPS - } - } - - return configuration - } - - @objc func onCreateContextMenu() { - let mapSorted = SharedLastTouchPointTimestamp.sorted { $0.value > $1.value } - if (mapSorted.first?.key != self) { - return - } - - contextMenuIsShowing = true - - let hitTestResult = HitTestResult(type: .unknownType, extra: nil) - - if let lastLongPressTouhLocation = lastLongPressTouchPoint { - if configuration.preferences.javaScriptEnabled { - self.evaluateJavaScript("window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findElementsAtPoint(\(lastLongPressTouhLocation.x),\(lastLongPressTouhLocation.y))", completionHandler: {(value, error) in - if error != nil { - print("Long press gesture recognizer error: \(error?.localizedDescription ?? "")") - } else if let value = value as? [String: Any?] { - self.channelDelegate?.onCreateContextMenu(hitTestResult: HitTestResult.fromMap(map: value) ?? hitTestResult) - } else { - self.channelDelegate?.onCreateContextMenu(hitTestResult: hitTestResult) - } - }) - } else { - channelDelegate?.onCreateContextMenu(hitTestResult: hitTestResult) - } - } else { - channelDelegate?.onCreateContextMenu(hitTestResult: hitTestResult) - } - } - - @objc func onHideContextMenu() { - if contextMenuIsShowing == false { - return - } - contextMenuIsShowing = false - channelDelegate?.onHideContextMenu() - } - - override public func observeValue(forKeyPath keyPath: String?, of object: Any?, - change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { - if keyPath == #keyPath(WKWebView.estimatedProgress) { - initializeWindowIdJS() - let progress = Int(estimatedProgress * 100) - channelDelegate?.onProgressChanged(progress: progress) - inAppBrowserDelegate?.didChangeProgress(progress: estimatedProgress) - } else if keyPath == #keyPath(WKWebView.url) && change?[.newKey] is URL { - initializeWindowIdJS() - let newUrl = change?[NSKeyValueChangeKey.newKey] as? URL - channelDelegate?.onUpdateVisitedHistory(url: newUrl?.absoluteString, isReload: nil) - inAppBrowserDelegate?.didUpdateVisitedHistory(url: newUrl) - } else if keyPath == #keyPath(WKWebView.title) && change?[.newKey] is String { - let newTitle = change?[.newKey] as? String - channelDelegate?.onTitleChanged(title: newTitle) - inAppBrowserDelegate?.didChangeTitle(title: newTitle) - } else if keyPath == #keyPath(UIScrollView.contentOffset) { - let newContentOffset = change?[.newKey] as? CGPoint - let oldContentOffset = change?[.oldKey] as? CGPoint - let startedByUser = scrollView.isDragging || scrollView.isDecelerating - if newContentOffset != oldContentOffset { - DispatchQueue.main.async { - self.onScrollChanged(startedByUser: startedByUser, oldContentOffset: oldContentOffset) - } - } - } else if keyPath == #keyPath(UIScrollView.contentSize) { - if let newContentSize = change?[.newKey] as? CGSize, - let oldContentSize = change?[.oldKey] as? CGSize, - newContentSize != oldContentSize { - DispatchQueue.main.async { - self.onContentSizeChanged(oldContentSize: oldContentSize) - } - } - } - else { - if #available(iOS 15.0, *) { - if keyPath == #keyPath(WKWebView.cameraCaptureState) || keyPath == #keyPath(WKWebView.microphoneCaptureState) { - var oldState: WKMediaCaptureState? = nil - if let oldValue = change?[.oldKey] as? Int { - oldState = WKMediaCaptureState.init(rawValue: oldValue) - } - var newState: WKMediaCaptureState? = nil - if let newValue = change?[.newKey] as? Int { - newState = WKMediaCaptureState.init(rawValue: newValue) - } - if oldState != newState { - if keyPath == #keyPath(WKWebView.cameraCaptureState) { - channelDelegate?.onCameraCaptureStateChanged(oldState: oldState, newState: newState) - } else { - channelDelegate?.onMicrophoneCaptureStateChanged(oldState: oldState, newState: newState) - } - } - } - } - // fullscreenState KVO - kept for potential future WebKit fixes, - // but currently UIWindow notifications are the reliable detection mechanism. - if #available(iOS 16.0, *) { - if keyPath == #keyPath(WKWebView.fullscreenState) { - if fullscreenState == .enteringFullscreen && !inFullscreen { - channelDelegate?.onEnterFullscreen() - inFullscreen = true - } else if fullscreenState == .exitingFullscreen && inFullscreen { - fullscreenWindow = nil - channelDelegate?.onExitFullscreen() - inFullscreen = false - } - } - } - } - replaceGestureHandlerIfNeeded() - } - - public func initializeWindowIdJS() { - if let windowId = windowId { - if #available(iOS 14.0, *) { - let contentWorlds = configuration.userContentController.getContentWorlds(with: windowId) - for contentWorld in contentWorlds { - let source = WindowIdJS.WINDOW_ID_INITIALIZE_JS_SOURCE().replacingOccurrences(of: PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, with: String(windowId)) - evaluateJavascript(source: source, contentWorld: contentWorld) - } - } else { - let source = WindowIdJS.WINDOW_ID_INITIALIZE_JS_SOURCE().replacingOccurrences(of: PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, with: String(windowId)) - evaluateJavascript(source: source) - } - } - } - - public func goBackOrForward(steps: Int) { - if canGoBackOrForward(steps: steps) { - if (steps > 0) { - let index = steps - 1 - go(to: self.backForwardList.forwardList[index]) - } - else if (steps < 0){ - let backListLength = self.backForwardList.backList.count - let index = backListLength + steps - go(to: self.backForwardList.backList[index]) - } - } - } - - public func canGoBackOrForward(steps: Int) -> Bool { - let currentIndex = self.backForwardList.backList.count - return (steps >= 0) - ? steps <= self.backForwardList.forwardList.count - : currentIndex + steps >= 0 - } - - @available(iOS 11.0, *) - public func takeScreenshot (with: [String: Any?]?, completionHandler: @escaping (_ screenshot: Data?) -> Void) { - var snapshotConfiguration: WKSnapshotConfiguration? = nil - if let with = with { - snapshotConfiguration = WKSnapshotConfiguration() - if let rect = with["rect"] as? [String: Double] { - snapshotConfiguration!.rect = CGRect.fromMap(map: rect) - } - if let snapshotWidth = with["snapshotWidth"] as? Double { - snapshotConfiguration!.snapshotWidth = NSNumber(value: snapshotWidth) - } - if #available(iOS 13.0, *), let afterScreenUpdates = with["afterScreenUpdates"] as? Bool { - snapshotConfiguration!.afterScreenUpdates = afterScreenUpdates - } - } - takeSnapshot(with: snapshotConfiguration, completionHandler: {(image, error) -> Void in - var imageData: Data? = nil - if let screenshot = image { - if let with = with { - switch with["compressFormat"] as! String { - case "JPEG": - let quality = Float(with["quality"] as! Int) / 100 - imageData = screenshot.jpegData(compressionQuality: CGFloat(quality)) - break - case "PNG": - imageData = screenshot.pngData() - break - default: - imageData = screenshot.pngData() - } - } - else { - imageData = screenshot.pngData() - } - } - completionHandler(imageData) - }) - } - - @available(iOS 14.0, *) - public func createPdf (configuration: [String: Any?]?, completionHandler: @escaping (_ pdf: Data?) -> Void) { - let pdfConfiguration: WKPDFConfiguration = .init() - if let configuration = configuration { - if let rect = configuration["rect"] as? [String: Double] { - pdfConfiguration.rect = CGRect.fromMap(map: rect) - } - } - createPDF(configuration: pdfConfiguration) { (result) in - switch (result) { - case .success(let data): - completionHandler(data) - return - case .failure(let error): - print(error.localizedDescription) - completionHandler(nil) - return - } - } - } - - @available(iOS 14.0, *) - public func createWebArchiveData (dataCompletionHandler: @escaping (_ webArchiveData: Data?) -> Void) { - createWebArchiveData(completionHandler: { (result) in - switch (result) { - case .success(let data): - dataCompletionHandler(data) - return - case .failure(let error): - print(error.localizedDescription) - dataCompletionHandler(nil) - return - } - }) - } - - @available(iOS 14.0, *) - public func saveWebArchive (filePath: String, autoname: Bool, completionHandler: @escaping (_ path: String?) -> Void) { - createWebArchiveData(dataCompletionHandler: { (webArchiveData) in - if let webArchiveData = webArchiveData { - var localUrl = URL(fileURLWithPath: filePath) - if autoname { - if let url = self.url { - // tries to mimic Android saveWebArchive method - let invalidCharacters = CharacterSet(charactersIn: "\\/:*?\"<>|") - .union(.newlines) - .union(.illegalCharacters) - .union(.controlCharacters) - - let currentPageUrlFileName = url.path - .components(separatedBy: invalidCharacters) - .joined(separator: "") - - let fullPath = filePath + "/" + currentPageUrlFileName + ".webarchive" - localUrl = URL(fileURLWithPath: fullPath) - } else { - completionHandler(nil) - return - } - } - do { - try webArchiveData.write(to: localUrl) - completionHandler(localUrl.path) - } catch { - // Catch any errors - print(error.localizedDescription) - completionHandler(nil) - } - } else { - completionHandler(nil) - } - }) - } - - public func loadUrl(urlRequest: URLRequest, allowingReadAccessTo: URL?) { - let url = urlRequest.url! - - if #available(iOS 9.0, *), let allowingReadAccessTo = allowingReadAccessTo, url.scheme == "file", allowingReadAccessTo.scheme == "file" { - loadFileURL(url, allowingReadAccessTo: allowingReadAccessTo) - } else { - load(urlRequest) - } - } - - public func postUrl(url: URL, postData: Data) { - var request = URLRequest(url: url) - - request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") - request.httpMethod = "POST" - request.httpBody = postData - load(request) - } - - public func loadData(data: String, mimeType: String, encoding: String, baseUrl: URL, allowingReadAccessTo: URL?) { - if #available(iOS 9.0, *), let allowingReadAccessTo = allowingReadAccessTo, baseUrl.scheme == "file", allowingReadAccessTo.scheme == "file" { - loadFileURL(baseUrl, allowingReadAccessTo: allowingReadAccessTo) - } - - if #available(iOS 9.0, *) { - load(data.data(using: .utf8)!, mimeType: mimeType, characterEncodingName: encoding, baseURL: baseUrl) - } else { - loadHTMLString(data, baseURL: baseUrl) - } - } - - public func loadFile(assetFilePath: String) throws { - if let plugin = plugin { - let assetURL = try Util.getUrlAsset(plugin: plugin, assetFilePath: assetFilePath) - let urlRequest = URLRequest(url: assetURL) - loadUrl(urlRequest: urlRequest, allowingReadAccessTo: nil) - } - } - - func setSettings(newSettings: InAppWebViewSettings, newSettingsMap: [String: Any]) { - - // MUST be the first! In this way, all the settings that uses evaluateJavaScript can be applied/blocked! - if #available(iOS 13.0, *) { - if newSettingsMap["applePayAPIEnabled"] != nil && settings?.applePayAPIEnabled != newSettings.applePayAPIEnabled { - if let settings = settings { - settings.applePayAPIEnabled = newSettings.applePayAPIEnabled - } - if !newSettings.applePayAPIEnabled { - // re-add WKUserScripts for the next page load - prepareAndAddUserScripts() - } else { - configuration.userContentController.removeAllUserScripts() - } - } - } - - if newSettingsMap["isUserInteractionEnabled"] != nil && settings?.isUserInteractionEnabled != newSettings.isUserInteractionEnabled { - isUserInteractionEnabled = newSettings.isUserInteractionEnabled - } - - if newSettingsMap["alpha"] != nil, settings?.alpha != newSettings.alpha, let viewAlpha = newSettings.alpha { - alpha = CGFloat(viewAlpha) - } - - if newSettingsMap["transparentBackground"] != nil && settings?.transparentBackground != newSettings.transparentBackground { - if newSettings.transparentBackground { - isOpaque = false - backgroundColor = UIColor.clear - scrollView.backgroundColor = UIColor.clear - } else { - isOpaque = true - backgroundColor = nil - scrollView.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1) - } - } - - if newSettingsMap["disallowOverScroll"] != nil && settings?.disallowOverScroll != newSettings.disallowOverScroll { - if responds(to: #selector(getter: scrollView)) { - scrollView.bounces = !newSettings.disallowOverScroll - } - else { - for subview: UIView in subviews { - if subview is UIScrollView { - (subview as! UIScrollView).bounces = !newSettings.disallowOverScroll - } - } - } - } - - if #available(iOS 9.0, *) { - if (newSettingsMap["incognito"] != nil && settings?.incognito != newSettings.incognito && newSettings.incognito) { - configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent() - } else if (newSettingsMap["cacheEnabled"] != nil && settings?.cacheEnabled != newSettings.cacheEnabled && newSettings.cacheEnabled) { - configuration.websiteDataStore = WKWebsiteDataStore.default() - } - } - - if #available(iOS 11.0, *) { - if (newSettingsMap["sharedCookiesEnabled"] != nil && settings?.sharedCookiesEnabled != newSettings.sharedCookiesEnabled && newSettings.sharedCookiesEnabled) { - if(!newSettings.incognito && !newSettings.cacheEnabled) { - configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent() - } - for cookie in HTTPCookieStorage.shared.cookies ?? [] { - configuration.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil) - } - } - if newSettingsMap["accessibilityIgnoresInvertColors"] != nil && settings?.accessibilityIgnoresInvertColors != newSettings.accessibilityIgnoresInvertColors { - accessibilityIgnoresInvertColors = newSettings.accessibilityIgnoresInvertColors - } - if newSettingsMap["contentInsetAdjustmentBehavior"] != nil && settings?.contentInsetAdjustmentBehavior != newSettings.contentInsetAdjustmentBehavior { - scrollView.contentInsetAdjustmentBehavior = - UIScrollView.ContentInsetAdjustmentBehavior.init(rawValue: newSettings.contentInsetAdjustmentBehavior)! - } - } - - if newSettingsMap["enableViewportScale"] != nil && settings?.enableViewportScale != newSettings.enableViewportScale { - if !newSettings.enableViewportScale { - if configuration.userContentController.containsPluginScript(with: EnableViewportScaleJS.ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT_GROUP_NAME) { - configuration.userContentController.removePluginScripts(with: EnableViewportScaleJS.ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT_GROUP_NAME, shouldAddPreviousScripts: false) - evaluateJavaScript(EnableViewportScaleJS.NOT_ENABLE_VIEWPORT_SCALE_JS_SOURCE()) - } - } else { - evaluateJavaScript(EnableViewportScaleJS.ENABLE_VIEWPORT_SCALE_JS_SOURCE) - if javaScriptBridgeEnabled { - configuration.userContentController.addPluginScript(EnableViewportScaleJS.ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT(allowedOriginRules: newSettings.pluginScriptsOriginAllowList)) - } - } - } - - if newSettingsMap["supportZoom"] != nil && settings?.supportZoom != newSettings.supportZoom { - if newSettings.supportZoom { - if configuration.userContentController.containsPluginScript(with: SupportZoomJS.NOT_SUPPORT_ZOOM_JS_PLUGIN_SCRIPT_GROUP_NAME) { - configuration.userContentController.removePluginScripts(with: SupportZoomJS.NOT_SUPPORT_ZOOM_JS_PLUGIN_SCRIPT_GROUP_NAME, shouldAddPreviousScripts: false) - evaluateJavaScript(SupportZoomJS.SUPPORT_ZOOM_JS_SOURCE()) - } - } else { - evaluateJavaScript(SupportZoomJS.NOT_SUPPORT_ZOOM_JS_SOURCE) - if javaScriptBridgeEnabled { - configuration.userContentController.addPluginScript(SupportZoomJS.NOT_SUPPORT_ZOOM_JS_PLUGIN_SCRIPT(allowedOriginRules: newSettings.pluginScriptsOriginAllowList)) - } - } - } - - if newSettingsMap["useOnLoadResource"] != nil && settings?.useOnLoadResource != newSettings.useOnLoadResource { - if let applePayAPIEnabled = settings?.applePayAPIEnabled, !applePayAPIEnabled { - if javaScriptBridgeEnabled { - enablePluginScriptAtRuntime(flagVariable: OnLoadResourceJS.FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE(), - enable: newSettings.useOnLoadResource, - pluginScript: OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT(allowedOriginRules: newSettings.pluginScriptsOriginAllowList, - forMainFrameOnly: newSettings.pluginScriptsForMainFrameOnly)) - } - } else { - newSettings.useOnLoadResource = false - } - } - - if newSettingsMap["useShouldInterceptAjaxRequest"] != nil && settings?.useShouldInterceptAjaxRequest != newSettings.useShouldInterceptAjaxRequest { - if let applePayAPIEnabled = settings?.applePayAPIEnabled, !applePayAPIEnabled { - if javaScriptBridgeEnabled { - enablePluginScriptAtRuntime(flagVariable: InterceptAjaxRequestJS.FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE(), - enable: newSettings.useShouldInterceptAjaxRequest, - pluginScript: InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT(allowedOriginRules: newSettings.pluginScriptsOriginAllowList, - forMainFrameOnly: newSettings.pluginScriptsForMainFrameOnly, - initialUseOnAjaxReadyStateChange: newSettings.useOnAjaxReadyStateChange, - initialUseOnAjaxProgress: newSettings.useOnAjaxProgress)) - } - } else { - newSettings.useShouldInterceptAjaxRequest = false - } - } - - if newSettingsMap["useOnAjaxReadyStateChange"] != nil && settings?.useOnAjaxReadyStateChange != newSettings.useOnAjaxReadyStateChange { - if let applePayAPIEnabled = settings?.applePayAPIEnabled, !applePayAPIEnabled { - if javaScriptBridgeEnabled { - evaluateJavaScript("\(InterceptAjaxRequestJS.FLAG_VARIABLE_FOR_ON_AJAX_READY_STATE_CHANGE()) = \(newSettings.useOnAjaxReadyStateChange);") - } - } else { - newSettings.useOnAjaxReadyStateChange = false - } - } - - if newSettingsMap["useOnAjaxProgress"] != nil && settings?.useOnAjaxProgress != newSettings.useOnAjaxProgress { - if let applePayAPIEnabled = settings?.applePayAPIEnabled, !applePayAPIEnabled { - if javaScriptBridgeEnabled { - evaluateJavaScript("\(InterceptAjaxRequestJS.FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS()) = \(newSettings.useOnAjaxProgress);") - } - } else { - newSettings.useOnAjaxProgress = false - } - } - - if newSettingsMap["interceptOnlyAsyncAjaxRequests"] != nil && settings?.interceptOnlyAsyncAjaxRequests != newSettings.interceptOnlyAsyncAjaxRequests { - if let applePayAPIEnabled = settings?.applePayAPIEnabled, !applePayAPIEnabled, - let interceptOnlyAsyncAjaxRequestsPluginScript = interceptOnlyAsyncAjaxRequestsPluginScript { - if javaScriptBridgeEnabled { - enablePluginScriptAtRuntime(flagVariable: InterceptAjaxRequestJS.FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE(), - enable: newSettings.interceptOnlyAsyncAjaxRequests, - pluginScript: interceptOnlyAsyncAjaxRequestsPluginScript) - } - } - } - - if newSettingsMap["useShouldInterceptFetchRequest"] != nil && settings?.useShouldInterceptFetchRequest != newSettings.useShouldInterceptFetchRequest { - if let applePayAPIEnabled = settings?.applePayAPIEnabled, !applePayAPIEnabled { - if javaScriptBridgeEnabled { - enablePluginScriptAtRuntime(flagVariable: InterceptFetchRequestJS.FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE(), - enable: newSettings.useShouldInterceptFetchRequest, - pluginScript: InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT(allowedOriginRules: newSettings.pluginScriptsOriginAllowList, - forMainFrameOnly: newSettings.pluginScriptsForMainFrameOnly)) - } - } else { - newSettings.useShouldInterceptFetchRequest = false - } - } - - if newSettingsMap["mediaPlaybackRequiresUserGesture"] != nil && settings?.mediaPlaybackRequiresUserGesture != newSettings.mediaPlaybackRequiresUserGesture { - if #available(iOS 10.0, *) { - configuration.mediaTypesRequiringUserActionForPlayback = (newSettings.mediaPlaybackRequiresUserGesture) ? .all : [] - } else { - // Fallback on earlier versions - configuration.mediaPlaybackRequiresUserAction = newSettings.mediaPlaybackRequiresUserGesture - } - } - - if newSettingsMap["allowsInlineMediaPlayback"] != nil && settings?.allowsInlineMediaPlayback != newSettings.allowsInlineMediaPlayback { - configuration.allowsInlineMediaPlayback = newSettings.allowsInlineMediaPlayback - } - - if newSettingsMap["suppressesIncrementalRendering"] != nil && settings?.suppressesIncrementalRendering != newSettings.suppressesIncrementalRendering { - configuration.suppressesIncrementalRendering = newSettings.suppressesIncrementalRendering - } - - if newSettingsMap["allowsBackForwardNavigationGestures"] != nil && settings?.allowsBackForwardNavigationGestures != newSettings.allowsBackForwardNavigationGestures { - allowsBackForwardNavigationGestures = newSettings.allowsBackForwardNavigationGestures - } - - if newSettingsMap["javaScriptCanOpenWindowsAutomatically"] != nil && settings?.javaScriptCanOpenWindowsAutomatically != newSettings.javaScriptCanOpenWindowsAutomatically { - configuration.preferences.javaScriptCanOpenWindowsAutomatically = newSettings.javaScriptCanOpenWindowsAutomatically - } - - if newSettingsMap["minimumFontSize"] != nil && settings?.minimumFontSize != newSettings.minimumFontSize { - configuration.preferences.minimumFontSize = CGFloat(newSettings.minimumFontSize) - } - - if newSettingsMap["selectionGranularity"] != nil && settings?.selectionGranularity != newSettings.selectionGranularity { - configuration.selectionGranularity = WKSelectionGranularity.init(rawValue: newSettings.selectionGranularity)! - } - - if #available(iOS 10.0, *) { - if newSettingsMap["ignoresViewportScaleLimits"] != nil && settings?.ignoresViewportScaleLimits != newSettings.ignoresViewportScaleLimits { - configuration.ignoresViewportScaleLimits = newSettings.ignoresViewportScaleLimits - } - - if newSettingsMap["dataDetectorTypes"] != nil && settings?.dataDetectorTypes != newSettings.dataDetectorTypes { - var dataDetectorTypes = WKDataDetectorTypes.init(rawValue: 0) - for type in newSettings.dataDetectorTypes { - let dataDetectorType = Util.getDataDetectorType(type: type) - dataDetectorTypes = WKDataDetectorTypes(rawValue: dataDetectorTypes.rawValue | dataDetectorType.rawValue) - } - configuration.dataDetectorTypes = dataDetectorTypes - } - } - - if #available(iOS 13.0, *) { - if newSettingsMap["isFraudulentWebsiteWarningEnabled"] != nil && settings?.isFraudulentWebsiteWarningEnabled != newSettings.isFraudulentWebsiteWarningEnabled { - configuration.preferences.isFraudulentWebsiteWarningEnabled = newSettings.isFraudulentWebsiteWarningEnabled - } - if newSettingsMap["preferredContentMode"] != nil && settings?.preferredContentMode != newSettings.preferredContentMode { - configuration.defaultWebpagePreferences.preferredContentMode = WKWebpagePreferences.ContentMode(rawValue: newSettings.preferredContentMode)! - } - if newSettingsMap["automaticallyAdjustsScrollIndicatorInsets"] != nil && settings?.automaticallyAdjustsScrollIndicatorInsets != newSettings.automaticallyAdjustsScrollIndicatorInsets { - scrollView.automaticallyAdjustsScrollIndicatorInsets = newSettings.automaticallyAdjustsScrollIndicatorInsets - } - } - - if newSettingsMap["disableVerticalScroll"] != nil && settings?.disableVerticalScroll != newSettings.disableVerticalScroll { - scrollView.showsVerticalScrollIndicator = !newSettings.disableVerticalScroll - } - if newSettingsMap["disableHorizontalScroll"] != nil && settings?.disableHorizontalScroll != newSettings.disableHorizontalScroll { - scrollView.showsHorizontalScrollIndicator = !newSettings.disableHorizontalScroll - } - - if newSettingsMap["verticalScrollBarEnabled"] != nil && settings?.verticalScrollBarEnabled != newSettings.verticalScrollBarEnabled { - scrollView.showsVerticalScrollIndicator = newSettings.verticalScrollBarEnabled - } - if newSettingsMap["horizontalScrollBarEnabled"] != nil && settings?.horizontalScrollBarEnabled != newSettings.horizontalScrollBarEnabled { - scrollView.showsHorizontalScrollIndicator = newSettings.horizontalScrollBarEnabled - } - - if newSettingsMap["isDirectionalLockEnabled"] != nil && settings?.isDirectionalLockEnabled != newSettings.isDirectionalLockEnabled { - scrollView.isDirectionalLockEnabled = newSettings.isDirectionalLockEnabled - } - - if newSettingsMap["decelerationRate"] != nil && settings?.decelerationRate != newSettings.decelerationRate { - scrollView.decelerationRate = Util.getDecelerationRate(type: newSettings.decelerationRate) - } - if newSettingsMap["alwaysBounceVertical"] != nil && settings?.alwaysBounceVertical != newSettings.alwaysBounceVertical { - scrollView.alwaysBounceVertical = newSettings.alwaysBounceVertical - } - if newSettingsMap["alwaysBounceHorizontal"] != nil && settings?.alwaysBounceHorizontal != newSettings.alwaysBounceHorizontal { - scrollView.alwaysBounceHorizontal = newSettings.alwaysBounceHorizontal - } - if newSettingsMap["scrollsToTop"] != nil && settings?.scrollsToTop != newSettings.scrollsToTop { - scrollView.scrollsToTop = newSettings.scrollsToTop - } - if newSettingsMap["isPagingEnabled"] != nil && settings?.isPagingEnabled != newSettings.isPagingEnabled { - scrollView.scrollsToTop = newSettings.isPagingEnabled - } - if newSettingsMap["maximumZoomScale"] != nil && settings?.maximumZoomScale != newSettings.maximumZoomScale { - scrollView.maximumZoomScale = CGFloat(newSettings.maximumZoomScale) - } - if newSettingsMap["minimumZoomScale"] != nil && settings?.minimumZoomScale != newSettings.minimumZoomScale { - scrollView.minimumZoomScale = CGFloat(newSettings.minimumZoomScale) - } - - if #available(iOS 9.0, *) { - if newSettingsMap["allowsLinkPreview"] != nil && settings?.allowsLinkPreview != newSettings.allowsLinkPreview { - allowsLinkPreview = newSettings.allowsLinkPreview - } - if newSettingsMap["allowsAirPlayForMediaPlayback"] != nil && settings?.allowsAirPlayForMediaPlayback != newSettings.allowsAirPlayForMediaPlayback { - configuration.allowsAirPlayForMediaPlayback = newSettings.allowsAirPlayForMediaPlayback - } - if newSettingsMap["allowsPictureInPictureMediaPlayback"] != nil && settings?.allowsPictureInPictureMediaPlayback != newSettings.allowsPictureInPictureMediaPlayback { - configuration.allowsPictureInPictureMediaPlayback = newSettings.allowsPictureInPictureMediaPlayback - } - if newSettingsMap["applicationNameForUserAgent"] != nil && settings?.applicationNameForUserAgent != newSettings.applicationNameForUserAgent && newSettings.applicationNameForUserAgent != "" { - configuration.applicationNameForUserAgent = newSettings.applicationNameForUserAgent - } - if newSettingsMap["userAgent"] != nil && settings?.userAgent != newSettings.userAgent && newSettings.userAgent != "" { - customUserAgent = newSettings.userAgent - } - } - - if newSettingsMap["allowUniversalAccessFromFileURLs"] != nil && settings?.allowUniversalAccessFromFileURLs != newSettings.allowUniversalAccessFromFileURLs { - configuration.setValue(newSettings.allowUniversalAccessFromFileURLs, forKey: "allowUniversalAccessFromFileURLs") - } - - if newSettingsMap["allowFileAccessFromFileURLs"] != nil && settings?.allowFileAccessFromFileURLs != newSettings.allowFileAccessFromFileURLs { - configuration.preferences.setValue(newSettings.allowFileAccessFromFileURLs, forKey: "allowFileAccessFromFileURLs") - } - - if newSettingsMap["clearCache"] != nil && newSettings.clearCache { - clearCache() - } - - if newSettingsMap["javaScriptEnabled"] != nil && settings?.javaScriptEnabled != newSettings.javaScriptEnabled { - configuration.preferences.javaScriptEnabled = newSettings.javaScriptEnabled - } - - if #available(iOS 14.0, *) { - if settings?.mediaType != newSettings.mediaType { - mediaType = newSettings.mediaType - } - - if newSettingsMap["pageZoom"] != nil && settings?.pageZoom != newSettings.pageZoom { - pageZoom = CGFloat(newSettings.pageZoom) - } - - if newSettingsMap["limitsNavigationsToAppBoundDomains"] != nil && settings?.limitsNavigationsToAppBoundDomains != newSettings.limitsNavigationsToAppBoundDomains { - configuration.limitsNavigationsToAppBoundDomains = newSettings.limitsNavigationsToAppBoundDomains - } - - if newSettingsMap["javaScriptEnabled"] != nil && settings?.javaScriptEnabled != newSettings.javaScriptEnabled { - configuration.defaultWebpagePreferences.allowsContentJavaScript = newSettings.javaScriptEnabled - } - } - - if #available(iOS 11.0, *), newSettingsMap["contentBlockers"] != nil { - configuration.userContentController.removeAllContentRuleLists() - let contentBlockers = newSettings.contentBlockers - if contentBlockers.count > 0 { - do { - let jsonData = try JSONSerialization.data(withJSONObject: contentBlockers, options: []) - let blockRules = String(data: jsonData, encoding: .utf8) - WKContentRuleListStore.default().compileContentRuleList( - forIdentifier: "ContentBlockingRules", - encodedContentRuleList: blockRules) { (contentRuleList, error) in - if let error = error { - print(error.localizedDescription) - return - } - self.configuration.userContentController.add(contentRuleList!) - } - } catch { - print(error.localizedDescription) - } - } - } - - if #available(iOS 15.0, *) { - if newSettingsMap["upgradeKnownHostsToHTTPS"] != nil && settings?.upgradeKnownHostsToHTTPS != newSettings.upgradeKnownHostsToHTTPS { - configuration.upgradeKnownHostsToHTTPS = newSettings.upgradeKnownHostsToHTTPS - } - if newSettingsMap["isTextInteractionEnabled"] != nil && settings?.isTextInteractionEnabled != newSettings.isTextInteractionEnabled { - configuration.preferences.isTextInteractionEnabled = newSettings.isTextInteractionEnabled - } - if newSettingsMap["underPageBackgroundColor"] != nil, settings?.underPageBackgroundColor != newSettings.underPageBackgroundColor, - let underPageBackgroundColor = newSettings.underPageBackgroundColor, !underPageBackgroundColor.isEmpty { - self.underPageBackgroundColor = UIColor(hexString: underPageBackgroundColor) - } - } - if #available(iOS 15.4, *) { - if newSettingsMap["isSiteSpecificQuirksModeEnabled"] != nil, settings?.isSiteSpecificQuirksModeEnabled != newSettings.isSiteSpecificQuirksModeEnabled { - configuration.preferences.isSiteSpecificQuirksModeEnabled = newSettings.isSiteSpecificQuirksModeEnabled - } - } - if #available(iOS 15.5, *) { - if ((newSettingsMap["minimumViewportInset"] != nil && settings?.minimumViewportInset != newSettings.minimumViewportInset) || - (newSettingsMap["maximumViewportInset"] != nil && settings?.maximumViewportInset != newSettings.maximumViewportInset)), - let minViewportInset = newSettings.minimumViewportInset, let maxViewportInset = newSettings.maximumViewportInset { - setMinimumViewportInset(minViewportInset, maximumViewportInset: maxViewportInset) - } - } - if #available(iOS 16.0, *) { - if newSettingsMap["isFindInteractionEnabled"] != nil, settings?.isFindInteractionEnabled != newSettings.isFindInteractionEnabled { - isFindInteractionEnabled = newSettings.isFindInteractionEnabled - } - } - if #available(iOS 16.4, *) { - if newSettingsMap["isInspectable"] != nil, settings?.isInspectable != newSettings.isInspectable { - isInspectable = newSettings.isInspectable - } - if newSettingsMap["shouldPrintBackgrounds"] != nil, settings?.shouldPrintBackgrounds != newSettings.shouldPrintBackgrounds { - configuration.preferences.shouldPrintBackgrounds = newSettings.shouldPrintBackgrounds - } - } - - scrollView.isScrollEnabled = !(newSettings.disableVerticalScroll && newSettings.disableHorizontalScroll) - - self.settings = newSettings - } - - func getSettings() -> [String: Any?]? { - if (self.settings == nil) { - return nil - } - return self.settings!.getRealSettings(obj: self) - } - - public func enablePluginScriptAtRuntime(flagVariable: String, enable: Bool, pluginScript: PluginScript) { - evaluateJavascript(source: flagVariable) { (alreadyLoaded) in - if let alreadyLoaded = alreadyLoaded as? Bool, alreadyLoaded { - let enableSource = "\(flagVariable) = \(enable);" - if #available(iOS 14.0, *), pluginScript.requiredInAllContentWorlds { - for contentWorld in self.configuration.userContentController.contentWorlds { - self.evaluateJavaScript(enableSource, frame: nil, contentWorld: contentWorld, completionHandler: nil) - } - } else { - self.evaluateJavaScript(enableSource, completionHandler: nil) - } - if !enable { - self.configuration.userContentController.removePluginScripts(with: pluginScript.groupName!) - } - } - else if enable { - if #available(iOS 14.0, *), pluginScript.requiredInAllContentWorlds { - for contentWorld in self.configuration.userContentController.contentWorlds { - self.evaluateJavaScript(pluginScript.source, frame: nil, contentWorld: contentWorld, completionHandler: nil) - self.configuration.userContentController.addPluginScript(pluginScript) - } - } else { - self.evaluateJavaScript(pluginScript.source, completionHandler: nil) - self.configuration.userContentController.addPluginScript(pluginScript) - } - self.configuration.userContentController.sync(scriptMessageHandler: self) - } - } - } - - @available(*, deprecated, message: "Use InAppWebViewManager.clearAllCache instead.") - public func clearCache() { - if #available(iOS 9.0, *) { - let date = NSDate(timeIntervalSince1970: 0) - WKWebsiteDataStore.default().removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), modifiedSince: date as Date, completionHandler:{ }) - } else { - var libraryPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.libraryDirectory, FileManager.SearchPathDomainMask.userDomainMask, false).first! - libraryPath += "/Cookies" - - do { - try FileManager.default.removeItem(atPath: libraryPath) - } catch { - print("can't clear cache") - } - URLCache.shared.removeAllCachedResponses() - } - } - - public func injectDeferredObject(source: String, withWrapper jsWrapper: String?, completionHandler: ((Any?) -> Void)? = nil) { - var jsToInject = source - if let wrapper = jsWrapper { - let jsonData: Data? = try? JSONSerialization.data(withJSONObject: [source], options: []) - let sourceArrayString = String(data: jsonData!, encoding: .utf8) - let sourceString: String? = (sourceArrayString! as NSString).substring(with: NSRange(location: 1, length: (sourceArrayString?.count ?? 0) - 2)) - jsToInject = String(format: wrapper, sourceString!) - } - - evaluateJavaScript(jsToInject) { (value, error) in - guard let completionHandler = completionHandler else { - return - } - - if let error = error { - let userInfo = (error as NSError).userInfo - let errorMessage = userInfo["WKJavaScriptExceptionMessage"] ?? - userInfo["NSLocalizedDescription"] as? String ?? - error.localizedDescription - self.channelDelegate?.onConsoleMessage(message: String(describing: errorMessage), messageLevel: 3) - } - - if value == nil { - completionHandler(nil) - return - } - - completionHandler(value) - } - } - - @available(iOS 14.0, *) - public func injectDeferredObject(source: String, contentWorld: WKContentWorld, withWrapper jsWrapper: String?, completionHandler: ((Any?) -> Void)? = nil) { - var jsToInject = source - if let wrapper = jsWrapper { - let jsonData: Data? = try? JSONSerialization.data(withJSONObject: [source], options: []) - let sourceArrayString = String(data: jsonData!, encoding: .utf8) - let sourceString: String? = (sourceArrayString! as NSString).substring(with: NSRange(location: 1, length: (sourceArrayString?.count ?? 0) - 2)) - jsToInject = String(format: wrapper, sourceString!) - } - - jsToInject = configuration.userContentController.generateCodeForScriptEvaluation(scriptMessageHandler: self, source: jsToInject, contentWorld: contentWorld) - - evaluateJavaScript(jsToInject, frame: nil, contentWorld: contentWorld) { (evalResult) in - guard let completionHandler = completionHandler else { - return - } - - switch (evalResult) { - case .success(let value): - completionHandler(value) - return - case .failure(let error): - let userInfo = (error as NSError).userInfo - let errorMessage = userInfo["WKJavaScriptExceptionMessage"] ?? - userInfo["NSLocalizedDescription"] as? String ?? - error.localizedDescription - self.channelDelegate?.onConsoleMessage(message: String(describing: errorMessage), messageLevel: 3) - break - } - - completionHandler(nil) - } - } - -#if compiler(>=6.0) - public override func evaluateJavaScript(_ javaScriptString: String, completionHandler: (@MainActor @Sendable (Any?, (any Error)?) -> Void)? = nil) { - if let applePayAPIEnabled = settings?.applePayAPIEnabled, applePayAPIEnabled { - if let completionHandler = completionHandler { - completionHandler(nil, nil) - } - return - } - super.evaluateJavaScript(javaScriptString, completionHandler: completionHandler) - } -#else - public override func evaluateJavaScript(_ javaScriptString: String, completionHandler: ((Any?, Error?) -> Void)? = nil) { - if let applePayAPIEnabled = settings?.applePayAPIEnabled, applePayAPIEnabled { - if let completionHandler = completionHandler { - completionHandler(nil, nil) - } - return - } - super.evaluateJavaScript(javaScriptString, completionHandler: completionHandler) - } -#endif - - @available(iOS 14.0, *) - public func evaluateJavaScript(_ javaScript: String, frame: WKFrameInfo? = nil, contentWorld: WKContentWorld, completionHandler: ((Result) -> Void)? = nil) { - if let applePayAPIEnabled = settings?.applePayAPIEnabled, applePayAPIEnabled { - return - } - super.evaluateJavaScript(javaScript, in: frame, in: contentWorld, completionHandler: completionHandler) - } - - public func evaluateJavascript(source: String, completionHandler: ((Any?) -> Void)? = nil) { - injectDeferredObject(source: source, withWrapper: nil, completionHandler: completionHandler) - } - - @available(iOS 14.0, *) - public func evaluateJavascript(source: String, contentWorld: WKContentWorld, completionHandler: ((Any?) -> Void)? = nil) { - injectDeferredObject(source: source, contentWorld: contentWorld, withWrapper: nil, completionHandler: completionHandler) - } - - @available(iOS 14.0, *) - public func callAsyncJavaScript(_ functionBody: String, arguments: [String : Any] = [:], frame: WKFrameInfo? = nil, contentWorld: WKContentWorld, completionHandler: ((Result) -> Void)? = nil) { - if let applePayAPIEnabled = settings?.applePayAPIEnabled, applePayAPIEnabled { - return - } - super.callAsyncJavaScript(functionBody, arguments: arguments, in: frame, in: contentWorld, completionHandler: completionHandler) - } - - @available(iOS 14.0, *) - public func callAsyncJavaScript(functionBody: String, arguments: [String:Any], contentWorld: WKContentWorld, completionHandler: ((Any?) -> Void)? = nil) { - let jsToInject = configuration.userContentController.generateCodeForScriptEvaluation(scriptMessageHandler: self, source: functionBody, contentWorld: contentWorld) - - callAsyncJavaScript(jsToInject, arguments: arguments, frame: nil, contentWorld: contentWorld) { (evalResult) in - guard let completionHandler = completionHandler else { - return - } - - var body: [String: Any?] = [ - "value": nil, - "error": nil - ] - - switch (evalResult) { - case .success(let value): - body["value"] = value - break - case .failure(let error): - let userInfo = (error as NSError).userInfo - body["error"] = userInfo["WKJavaScriptExceptionMessage"] ?? - userInfo["NSLocalizedDescription"] as? String ?? - error.localizedDescription - self.channelDelegate?.onConsoleMessage(message: String(describing: body["error"]), messageLevel: 3) - break - } - - completionHandler(body) - } - } - - @available(iOS 10.3, *) - public func callAsyncJavaScript(functionBody: String, arguments: [String:Any], completionHandler: ((Any?) -> Void)? = nil) { - if let applePayAPIEnabled = settings?.applePayAPIEnabled, applePayAPIEnabled { - completionHandler?(nil) - } - - var jsToInject = functionBody - - let resultUuid = NSUUID().uuidString - if let completionHandler = completionHandler { - callAsyncJavaScriptBelowIOS14Results[resultUuid] = completionHandler - } - - var functionArgumentNamesList: [String] = [] - var functionArgumentValuesList: [String] = [] - let keys = arguments.keys - keys.forEach { (key) in - functionArgumentNamesList.append(key) - functionArgumentValuesList.append("obj.\(key)") - } - - let functionArgumentNames = functionArgumentNamesList.joined(separator: ", ") - let functionArgumentValues = functionArgumentValuesList.joined(separator: ", ") - - jsToInject = CallAsyncJavaScriptBelowIOS14WrapperJS.CALL_ASYNC_JAVASCRIPT_BELOW_IOS_14_WRAPPER_JS() - .replacingOccurrences(of: PluginScriptsUtil.VAR_FUNCTION_ARGUMENT_NAMES, with: functionArgumentNames) - .replacingOccurrences(of: PluginScriptsUtil.VAR_FUNCTION_ARGUMENT_VALUES, with: functionArgumentValues) - .replacingOccurrences(of: PluginScriptsUtil.VAR_FUNCTION_ARGUMENTS_OBJ, with: Util.JSONStringify(value: arguments)) - .replacingOccurrences(of: PluginScriptsUtil.VAR_FUNCTION_BODY, with: jsToInject) - .replacingOccurrences(of: PluginScriptsUtil.VAR_RESULT_UUID, with: resultUuid) - - evaluateJavaScript(jsToInject) { (value, error) in - if let error = error { - let userInfo = (error as NSError).userInfo - let errorMessage = userInfo["WKJavaScriptExceptionMessage"] ?? - userInfo["NSLocalizedDescription"] as? String ?? - error.localizedDescription - self.channelDelegate?.onConsoleMessage(message: String(describing: errorMessage), messageLevel: 3) - completionHandler?(nil) - self.callAsyncJavaScriptBelowIOS14Results.removeValue(forKey: resultUuid) - } - } - } - - public func injectJavascriptFileFromUrl(urlFile: String, scriptHtmlTagAttributes: [String:Any?]?) { - var scriptAttributes = "" - if let scriptHtmlTagAttributes = scriptHtmlTagAttributes { - if let typeAttr = scriptHtmlTagAttributes["type"] as? String { - scriptAttributes += " script.type = '\(typeAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let idAttr = scriptHtmlTagAttributes["id"] as? String { - let scriptIdEscaped = idAttr.replacingOccurrences(of: "\'", with: "\\'") - scriptAttributes += " script.id = '\(scriptIdEscaped)'; " - scriptAttributes += """ - script.onload = function() { - if (window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()) != null) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onInjectedScriptLoaded', '\(scriptIdEscaped)'); - } - }; - """ - scriptAttributes += """ - script.onerror = function() { - if (window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()) != null) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onInjectedScriptError', '\(scriptIdEscaped)'); - } - }; - """ - } - if let asyncAttr = scriptHtmlTagAttributes["async"] as? Bool, asyncAttr { - scriptAttributes += " script.async = true; " - } - if let deferAttr = scriptHtmlTagAttributes["defer"] as? Bool, deferAttr { - scriptAttributes += " script.defer = true; " - } - if let crossOriginAttr = scriptHtmlTagAttributes["crossOrigin"] as? String { - scriptAttributes += " script.crossOrigin = '\(crossOriginAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let integrityAttr = scriptHtmlTagAttributes["integrity"] as? String { - scriptAttributes += " script.integrity = '\(integrityAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let noModuleAttr = scriptHtmlTagAttributes["noModule"] as? Bool, noModuleAttr { - scriptAttributes += " script.noModule = true; " - } - if let nonceAttr = scriptHtmlTagAttributes["nonce"] as? String { - scriptAttributes += " script.nonce = '\(nonceAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let referrerPolicyAttr = scriptHtmlTagAttributes["referrerPolicy"] as? String { - scriptAttributes += " script.referrerPolicy = '\(referrerPolicyAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - } - let jsWrapper = "(function(d) { var script = d.createElement('script'); \(scriptAttributes) script.src = %@; d.body.appendChild(script); })(document);" - injectDeferredObject(source: urlFile, withWrapper: jsWrapper, completionHandler: nil) - } - - public func injectCSSCode(source: String) { - let jsWrapper = "(function(d) { var style = d.createElement('style'); style.innerHTML = %@; d.head.appendChild(style); })(document);" - injectDeferredObject(source: source, withWrapper: jsWrapper, completionHandler: nil) - } - - public func injectCSSFileFromUrl(urlFile: String, cssLinkHtmlTagAttributes: [String:Any?]?) { - var cssLinkAttributes = "" - var alternateStylesheet = "" - if let cssLinkHtmlTagAttributes = cssLinkHtmlTagAttributes { - if let idAttr = cssLinkHtmlTagAttributes["id"] as? String { - cssLinkAttributes += " link.id = '\(idAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let mediaAttr = cssLinkHtmlTagAttributes["media"] as? String { - cssLinkAttributes += " link.media = '\(mediaAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let crossOriginAttr = cssLinkHtmlTagAttributes["crossOrigin"] as? String { - cssLinkAttributes += " link.crossOrigin = '\(crossOriginAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let integrityAttr = cssLinkHtmlTagAttributes["integrity"] as? String { - cssLinkAttributes += " link.integrity = '\(integrityAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let referrerPolicyAttr = cssLinkHtmlTagAttributes["referrerPolicy"] as? String { - cssLinkAttributes += " link.referrerPolicy = '\(referrerPolicyAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let disabledAttr = cssLinkHtmlTagAttributes["disabled"] as? Bool, disabledAttr { - cssLinkAttributes += " link.disabled = true; " - } - if let alternateAttr = cssLinkHtmlTagAttributes["alternate"] as? Bool, alternateAttr { - alternateStylesheet = "alternate " - } - if let titleAttr = cssLinkHtmlTagAttributes["title"] as? String { - cssLinkAttributes += " link.title = '\(titleAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - } - let jsWrapper = "(function(d) { var link = d.createElement('link'); link.rel='\(alternateStylesheet)stylesheet', link.type='text/css'; \(cssLinkAttributes) link.href = %@; d.head.appendChild(link); })(document);" - injectDeferredObject(source: urlFile, withWrapper: jsWrapper, completionHandler: nil) - } - - public func getCopyBackForwardList() -> [String: Any] { - let currentList = backForwardList - let currentIndex = currentList.backList.count - var completeList = currentList.backList - if currentList.currentItem != nil { - completeList.append(currentList.currentItem!) - } - completeList.append(contentsOf: currentList.forwardList) - - var history: [[String: Any]] = [] - - for (i, historyItem) in completeList.enumerated() { - var historyItemMap: [String: Any] = [:] - historyItemMap["originalUrl"] = historyItem.initialURL.absoluteString - historyItemMap["title"] = historyItem.title - historyItemMap["url"] = historyItem.url.absoluteString - historyItemMap["index"] = i - historyItemMap["offset"] = i - currentIndex - history.append(historyItemMap) - } - - var result: [String: Any] = [:] - result["list"] = history - result["currentIndex"] = currentIndex - - return result; - } - - @available(iOS 15.0, *) - public func webView(_ webView: WKWebView, - requestMediaCapturePermissionFor origin: WKSecurityOrigin, - initiatedByFrame frame: WKFrameInfo, - type: WKMediaCaptureType, - decisionHandler: @escaping (WKPermissionDecision) -> Void) { - let origin = "\(origin.protocol)://\(origin.host)\(origin.port != 0 ? ":" + String(origin.port) : "")" - let permissionRequest = PermissionRequest(origin: origin, resources: [type.rawValue], frame: frame) - - var decisionHandlerCalled = false - let callback = WebViewChannelDelegate.PermissionRequestCallback() - callback.nonNullSuccess = { (response: PermissionResponse) in - if let action = response.action { - decisionHandlerCalled = true - switch action { - case 1: - decisionHandler(.grant) - break - case 2: - decisionHandler(.prompt) - break - default: - decisionHandler(.deny) - } - return false - } - return true - } - callback.defaultBehaviour = { (response: PermissionResponse?) in - if !decisionHandlerCalled { - decisionHandlerCalled = true - decisionHandler(.deny) - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - if let channelDelegate = channelDelegate { - channelDelegate.onPermissionRequest(request: permissionRequest, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - @available(iOS 15.0, *) - public func webView(_ webView: WKWebView, - requestDeviceOrientationAndMotionPermissionFor origin: WKSecurityOrigin, - initiatedByFrame frame: WKFrameInfo, - decisionHandler: @escaping (WKPermissionDecision) -> Void) { - let origin = "\(origin.protocol)://\(origin.host)\(origin.port != 0 ? ":" + String(origin.port) : "")" - let permissionRequest = PermissionRequest(origin: origin, resources: ["deviceOrientationAndMotion"], frame: frame) - - var decisionHandlerCalled = false - let callback = WebViewChannelDelegate.PermissionRequestCallback() - callback.nonNullSuccess = { (response: PermissionResponse) in - if let action = response.action { - decisionHandlerCalled = true - switch action { - case 1: - decisionHandler(.grant) - break - case 2: - decisionHandler(.prompt) - break - default: - decisionHandler(.deny) - } - return false - } - return true - } - callback.defaultBehaviour = { (response: PermissionResponse?) in - if !decisionHandlerCalled { - decisionHandlerCalled = true - decisionHandler(.deny) - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - if let channelDelegate = channelDelegate { - channelDelegate.onPermissionRequest(request: permissionRequest, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - @available(iOS 13.0, *) - public func webView(_ webView: WKWebView, - decidePolicyFor navigationAction: WKNavigationAction, - preferences: WKWebpagePreferences, - decisionHandler: @escaping (WKNavigationActionPolicy, WKWebpagePreferences) -> Void) { - self.webView(webView, decidePolicyFor: navigationAction, decisionHandler: {(navigationActionPolicy) -> Void in - decisionHandler(navigationActionPolicy, preferences) - }) - } - - @available(iOS 14.5, *) - public func download(_ download: WKDownload, decideDestinationUsing response: URLResponse, suggestedFilename: String, completionHandler: @escaping (URL?) -> Void) { - if let url = response.url, let useOnDownloadStart = settings?.useOnDownloadStart, useOnDownloadStart { - let downloadStartRequest = DownloadStartRequest(url: url.absoluteString, - userAgent: nil, - contentDisposition: nil, - mimeType: response.mimeType, - contentLength: response.expectedContentLength, - suggestedFilename: suggestedFilename, - textEncodingName: response.textEncodingName) - channelDelegate?.onDownloadStarting(request: downloadStartRequest) - } - download.delegate = nil - // cancel the download - completionHandler(nil) - } - - @available(iOS 14.5, *) - public func webView(_ webView: WKWebView, navigationResponse: WKNavigationResponse, didBecome download: WKDownload) { - let response = navigationResponse.response - if let url = response.url, let useOnDownloadStart = settings?.useOnDownloadStart, useOnDownloadStart { - let downloadStartRequest = DownloadStartRequest(url: url.absoluteString, - userAgent: nil, - contentDisposition: nil, - mimeType: response.mimeType, - contentLength: response.expectedContentLength, - suggestedFilename: response.suggestedFilename, - textEncodingName: response.textEncodingName) - channelDelegate?.onDownloadStarting(request: downloadStartRequest) - } - download.delegate = nil - } - - public func webView(_ webView: WKWebView, - decidePolicyFor navigationAction: WKNavigationAction, - decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { - var decisionHandlerCalled = false - let callback = WebViewChannelDelegate.ShouldOverrideUrlLoadingCallback() - callback.nonNullSuccess = { (response: WKNavigationActionPolicy) in - decisionHandlerCalled = true - decisionHandler(response) - return false - } - callback.defaultBehaviour = { (response: WKNavigationActionPolicy?) in - if !decisionHandlerCalled { - decisionHandlerCalled = true - decisionHandler(.allow) - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - let runCallback = { - if let useShouldOverrideUrlLoading = self.settings?.useShouldOverrideUrlLoading, useShouldOverrideUrlLoading, let channelDelegate = self.channelDelegate { - channelDelegate.shouldOverrideUrlLoading(navigationAction: navigationAction, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - if windowId != nil, !windowCreated { - windowBeforeCreatedCallbacks.append(runCallback) - } else { - runCallback() - } - } - - public func webView(_ webView: WKWebView, - decidePolicyFor navigationResponse: WKNavigationResponse, - decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) { - if let response = navigationResponse.response as? HTTPURLResponse, response.statusCode >= 400 { - let request = WebResourceRequest.init(fromWKNavigationResponse: navigationResponse) - let errorResponse = WebResourceResponse.init(fromWKNavigationResponse: navigationResponse) - channelDelegate?.onReceivedHttpError(request: request, errorResponse: errorResponse) - } - - let useOnNavigationResponse = settings?.useOnNavigationResponse - - if useOnNavigationResponse != nil, useOnNavigationResponse! { - var decisionHandlerCalled = false - let callback = WebViewChannelDelegate.NavigationResponseCallback() - callback.nonNullSuccess = { (response: WKNavigationResponsePolicy) in - decisionHandlerCalled = true - decisionHandler(response) - return false - } - callback.defaultBehaviour = { (response: WKNavigationResponsePolicy?) in - if !decisionHandlerCalled { - decisionHandlerCalled = true - decisionHandler(.allow) - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - if let channelDelegate = channelDelegate { - channelDelegate.onNavigationResponse(navigationResponse: navigationResponse, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - if let useOnDownloadStart = settings?.useOnDownloadStart, useOnDownloadStart { - if #available(iOS 14.5, *), !navigationResponse.canShowMIMEType, useOnNavigationResponse == nil || !useOnNavigationResponse! { - decisionHandler(.download) - return - } else { - let mimeType = navigationResponse.response.mimeType - if let url = navigationResponse.response.url, navigationResponse.isForMainFrame { - if url.scheme != "file", mimeType != nil, !mimeType!.starts(with: "text/") { - let downloadStartRequest = DownloadStartRequest(url: url.absoluteString, - userAgent: nil, - contentDisposition: nil, - mimeType: mimeType, - contentLength: navigationResponse.response.expectedContentLength, - suggestedFilename: navigationResponse.response.suggestedFilename, - textEncodingName: navigationResponse.response.textEncodingName) - channelDelegate?.onDownloadStarting(request: downloadStartRequest) - if useOnNavigationResponse == nil || !useOnNavigationResponse! { - decisionHandler(.cancel) - } - return - } - } - } - } - - if useOnNavigationResponse == nil || !useOnNavigationResponse! { - decisionHandler(.allow) - } - } - - public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { - currentOriginalUrl = url - lastTouchPoint = nil - - disposeWebMessageChannels() - initializeWindowIdJS() - - if #available(iOS 14.0, *) { - configuration.userContentController.resetContentWorlds(windowId: windowId) - } - - channelDelegate?.onLoadStart(url: url?.absoluteString) - - inAppBrowserDelegate?.didStartNavigation(url: url) - } - - public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { - initializeWindowIdJS() - - InAppWebView.credentialsProposed = [] - evaluateJavaScript(JavaScriptBridgeJS.PLATFORM_READY_JS_SOURCE, completionHandler: nil) - - // sometimes scrollView.contentSize doesn't fit all the frame.size available - // so, we call setNeedsLayout to redraw the layout - let webViewFrameSize = frame.size - let scrollViewSize = scrollView.contentSize - if (scrollViewSize.width < webViewFrameSize.width || scrollViewSize.height < webViewFrameSize.height) { - setNeedsLayout() - } - - channelDelegate?.onLoadStop(url: url?.absoluteString) - - inAppBrowserDelegate?.didFinishNavigation(url: url) - } - - public func webView(_ view: WKWebView, - didFailProvisionalNavigation navigation: WKNavigation!, - withError error: Error) { - webView(view, didFail: navigation, withError: error) - } - - public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { - InAppWebView.credentialsProposed = [] - - var urlError: URL = url ?? URL(string: "about:blank")! - var errorCode = -1 - var errorDescription = "domain=\(error._domain), code=\(error._code), \(error.localizedDescription)" - - if let info = error as? URLError { - if let failingURL = info.failingURL { - urlError = failingURL - } - errorCode = info.code.rawValue - errorDescription = info.localizedDescription - } - else if let info = error._userInfo as? [String: Any] { - if let failingUrl = info[NSURLErrorFailingURLErrorKey] as? URL { - urlError = failingUrl - } - if let failingUrlString = info[NSURLErrorFailingURLStringErrorKey] as? String, - let failingUrl = URL(string: failingUrlString) { - urlError = failingUrl - } - } - - let webResourceRequest = WebResourceRequest(url: urlError, headers: nil) - let webResourceError = WebResourceError(type: errorCode, errorDescription: errorDescription) - - channelDelegate?.onReceivedError(request: webResourceRequest, error: webResourceError) - - inAppBrowserDelegate?.didFailNavigation(url: url, error: error) - } - - public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { - var completionHandlerCalled = false - if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic || - challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodDefault || - challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPDigest || - challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodNegotiate || - challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodNTLM { - let host = challenge.protectionSpace.host - let prot = challenge.protectionSpace.protocol - let realm = challenge.protectionSpace.realm - let port = challenge.protectionSpace.port - - let callback = WebViewChannelDelegate.ReceivedHttpAuthRequestCallback() - callback.nonNullSuccess = { (response: HttpAuthResponse) in - if let action = response.action { - completionHandlerCalled = true - switch action { - case 0: - InAppWebView.credentialsProposed = [] - // used .performDefaultHandling to maintain consistency with Android - // because .cancelAuthenticationChallenge will call webView(_:didFail:withError:) - completionHandler(.performDefaultHandling, nil) - //completionHandler(.cancelAuthenticationChallenge, nil) - break - case 1: - let username = response.username - let password = response.password - let permanentPersistence = response.permanentPersistence - let persistence = (permanentPersistence) ? URLCredential.Persistence.permanent : URLCredential.Persistence.forSession - let credential = URLCredential(user: username, password: password, persistence: persistence) - completionHandler(.useCredential, credential) - break - case 2: - if InAppWebView.credentialsProposed.count == 0 { - for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { - if protectionSpace.host == host && protectionSpace.realm == realm && - protectionSpace.protocol == prot && protectionSpace.port == port { - for credential in credentials { - InAppWebView.credentialsProposed.append(credential.value) - } - break - } - } - } - if InAppWebView.credentialsProposed.count == 0, let credential = challenge.proposedCredential { - InAppWebView.credentialsProposed.append(credential) - } - - if let credential = InAppWebView.credentialsProposed.popLast() { - completionHandler(.useCredential, credential) - } - else { - completionHandler(.performDefaultHandling, nil) - } - break - default: - InAppWebView.credentialsProposed = [] - completionHandler(.performDefaultHandling, nil) - } - return false - } - return true - } - callback.defaultBehaviour = { (response: HttpAuthResponse?) in - if !completionHandlerCalled { - completionHandlerCalled = true - completionHandler(.performDefaultHandling, nil) - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - let runCallback = { - if let channelDelegate = self.channelDelegate { - channelDelegate.onReceivedHttpAuthRequest(challenge: HttpAuthenticationChallenge(fromChallenge: challenge), callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - if windowId != nil, !windowCreated { - windowBeforeCreatedCallbacks.append(runCallback) - } else { - runCallback() - } - } - else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { - guard let serverTrust = challenge.protectionSpace.serverTrust else { - completionHandler(.performDefaultHandling, nil) - return - } - - if let scheme = challenge.protectionSpace.protocol, scheme == "https" { - // workaround for ProtectionSpace SSL Certificate - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global().async { - if let sslCertificate = challenge.protectionSpace.sslCertificate { - DispatchQueue.main.async { - InAppWebView.sslCertificatesMap[challenge.protectionSpace.host] = sslCertificate - } - } - } - } - - let callback = WebViewChannelDelegate.ReceivedServerTrustAuthRequestCallback() - callback.nonNullSuccess = { (response: ServerTrustAuthResponse) in - if let action = response.action { - completionHandlerCalled = true - switch action { - case 0: - InAppWebView.credentialsProposed = [] - completionHandler(.cancelAuthenticationChallenge, nil) - break - case 1: - // workaround for https://github.com/pichillilorenzo/flutter_inappwebview/issues/1924 - DispatchQueue.global().async { - let exceptions = SecTrustCopyExceptions(serverTrust) - SecTrustSetExceptions(serverTrust, exceptions) - let credential = URLCredential(trust: serverTrust) - completionHandler(.useCredential, credential) - } - break - default: - InAppWebView.credentialsProposed = [] - completionHandler(.performDefaultHandling, nil) - } - return false - } - return true - } - callback.defaultBehaviour = { (response: ServerTrustAuthResponse?) in - if !completionHandlerCalled { - completionHandlerCalled = true - completionHandler(.performDefaultHandling, nil) - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - let runCallback = { - if let channelDelegate = self.channelDelegate { - channelDelegate.onReceivedServerTrustAuthRequest(challenge: ServerTrustChallenge(fromChallenge: challenge), callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - if windowId != nil, !windowCreated { - windowBeforeCreatedCallbacks.append(runCallback) - } else { - runCallback() - } - } - else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate { - let callback = WebViewChannelDelegate.ReceivedClientCertRequestCallback() - callback.nonNullSuccess = { (response: ClientCertResponse) in - if let action = response.action { - completionHandlerCalled = true - switch action { - case 0: - completionHandler(.cancelAuthenticationChallenge, nil) - break - case 1: - let certificatePath = response.certificatePath - let certificatePassword = response.certificatePassword ?? ""; - - var path: String = certificatePath - do { - if let plugin = self.plugin { - path = try Util.getAbsPathAsset(plugin: plugin, assetFilePath: certificatePath) - } - } catch {} - - if let PKCS12Data = NSData(contentsOfFile: path), - let identityAndTrust: IdentityAndTrust = self.extractIdentity(PKCS12Data: PKCS12Data, password: certificatePassword) { - let urlCredential: URLCredential = URLCredential( - identity: identityAndTrust.identityRef, - certificates: identityAndTrust.certArray as? [AnyObject], - persistence: URLCredential.Persistence.forSession); - completionHandler(.useCredential, urlCredential) - } else { - completionHandler(.performDefaultHandling, nil) - } - - break - case 2: - completionHandler(.cancelAuthenticationChallenge, nil) - break - default: - completionHandler(.performDefaultHandling, nil) - } - return false - } - return true - } - callback.defaultBehaviour = { (response: ClientCertResponse?) in - if !completionHandlerCalled { - completionHandlerCalled = true - completionHandler(.performDefaultHandling, nil) - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - let runCallback = { - if let channelDelegate = self.channelDelegate { - channelDelegate.onReceivedClientCertRequest(challenge: ClientCertChallenge(fromChallenge: challenge), callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - if windowId != nil, !windowCreated { - windowBeforeCreatedCallbacks.append(runCallback) - } else { - runCallback() - } - } - else { - completionHandler(.performDefaultHandling, nil) - } - } - - struct IdentityAndTrust { - var identityRef: SecIdentity - var trust: SecTrust - var certArray: AnyObject - } - - func extractIdentity(PKCS12Data: NSData, password: String) -> IdentityAndTrust? { - var identityAndTrust: IdentityAndTrust? - var securityError: OSStatus = errSecSuccess - - var importResult: CFArray? - securityError = SecPKCS12Import( - PKCS12Data as NSData, - [kSecImportExportPassphrase as String: password] as NSDictionary, - &importResult - ) - - if securityError == errSecSuccess { - let certItems: CFArray = importResult! as CFArray - let certItemsArray: Array = certItems as Array - let dict: AnyObject? = certItemsArray.first - if let certEntry: Dictionary = dict as? Dictionary { - // grab the identity - let identityPointer: AnyObject? = certEntry["identity"] - let secIdentityRef:SecIdentity = (identityPointer as! SecIdentity?)! - // grab the trust - let trustPointer: AnyObject? = certEntry["trust"] - let trustRef:SecTrust = trustPointer as! SecTrust - // grab the cert - let chainPointer: AnyObject? = certEntry["chain"] - identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef, trust: trustRef, certArray: chainPointer!) - } - } else { - print("Security Error: " + securityError.description) - if #available(iOS 11.3, *) { - print(SecCopyErrorMessageString(securityError, nil) ?? "") - } - } - return identityAndTrust - } - - func createAlertDialog(message: String?, responseMessage: String?, confirmButtonTitle: String?, completionHandler: @escaping () -> Void) { - let title = responseMessage != nil && !responseMessage!.isEmpty ? responseMessage : message - let okButton = confirmButtonTitle != nil && !confirmButtonTitle!.isEmpty ? confirmButtonTitle : NSLocalizedString("Ok", comment: "") - let alertController = UIAlertController(title: title, message: nil, - preferredStyle: UIAlertController.Style.alert); - - alertController.addAction(UIAlertAction(title: okButton, style: UIAlertAction.Style.default) { - _ in completionHandler()} - ) - - guard let presentingViewController = inAppBrowserDelegate != nil ? inAppBrowserDelegate as? InAppBrowserWebViewController : window?.rootViewController else { - completionHandler() - return - } - presentingViewController.present(alertController, animated: true, completion: {}) - } - - public func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, - initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { - - if (isPausedTimers) { - isPausedTimersCompletionHandler = completionHandler - return - } - - var completionHandlerCalled = false - - let callback = WebViewChannelDelegate.JsAlertCallback() - callback.nonNullSuccess = { (response: JsAlertResponse) in - if response.handledByClient { - completionHandlerCalled = true - let action = response.action ?? 1 - switch action { - case 0: - completionHandler() - break - default: - completionHandler() - } - return false - } - return true - } - callback.defaultBehaviour = { [weak self] (response: JsAlertResponse?) in - if !completionHandlerCalled { - completionHandlerCalled = true - let responseMessage = response?.message - let confirmButtonTitle = response?.confirmButtonTitle - self?.createAlertDialog(message: message, responseMessage: responseMessage, - confirmButtonTitle: confirmButtonTitle, completionHandler: completionHandler) - } - } - callback.error = { (code: String, message: String?, details: Any?) in - if !completionHandlerCalled { - completionHandlerCalled = true - print(code + ", " + (message ?? "")) - completionHandler() - } - } - - if let channelDelegate = channelDelegate { - channelDelegate.onJsAlert(url: frame.request.url, message: message, isMainFrame: frame.isMainFrame, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - func createConfirmDialog(message: String?, responseMessage: String?, confirmButtonTitle: String?, cancelButtonTitle: String?, completionHandler: @escaping (Bool) -> Void) { - let dialogMessage = responseMessage != nil && !responseMessage!.isEmpty ? responseMessage : message - let okButton = confirmButtonTitle != nil && !confirmButtonTitle!.isEmpty ? confirmButtonTitle : NSLocalizedString("Ok", comment: "") - let cancelButton = cancelButtonTitle != nil && !cancelButtonTitle!.isEmpty ? cancelButtonTitle : NSLocalizedString("Cancel", comment: "") - - let confirmController = UIAlertController(title: nil, message: dialogMessage, preferredStyle: .alert) - - confirmController.addAction(UIAlertAction(title: okButton, style: .default, handler: { (action) in - completionHandler(true) - })) - - confirmController.addAction(UIAlertAction(title: cancelButton, style: .cancel, handler: { (action) in - completionHandler(false) - })) - - guard let presentingViewController = inAppBrowserDelegate != nil ? inAppBrowserDelegate as? InAppBrowserWebViewController : window?.rootViewController else { - completionHandler(false) - return - } - presentingViewController.present(confirmController, animated: true, completion: nil) - } - - public func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, - completionHandler: @escaping (Bool) -> Void) { - var completionHandlerCalled = false - - let callback = WebViewChannelDelegate.JsConfirmCallback() - callback.nonNullSuccess = { (response: JsConfirmResponse) in - if response.handledByClient { - completionHandlerCalled = true - let action = response.action ?? 1 - switch action { - case 0: - completionHandler(true) - break - case 1: - completionHandler(false) - break - default: - completionHandler(false) - } - return false - } - return true - } - callback.defaultBehaviour = { [weak self] (response: JsConfirmResponse?) in - if !completionHandlerCalled { - completionHandlerCalled = true - let responseMessage = response?.message - let confirmButtonTitle = response?.confirmButtonTitle - let cancelButtonTitle = response?.cancelButtonTitle - self?.createConfirmDialog(message: message, responseMessage: responseMessage, confirmButtonTitle: confirmButtonTitle, cancelButtonTitle: cancelButtonTitle, completionHandler: completionHandler) - } - } - callback.error = { (code: String, message: String?, details: Any?) in - if !completionHandlerCalled { - completionHandlerCalled = true - print(code + ", " + (message ?? "")) - completionHandler(false) - } - } - - if let channelDelegate = channelDelegate { - channelDelegate.onJsConfirm(url: frame.request.url, message: message, isMainFrame: frame.isMainFrame, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - func createPromptDialog(message: String, defaultValue: String?, responseMessage: String?, confirmButtonTitle: String?, cancelButtonTitle: String?, value: String?, completionHandler: @escaping (String?) -> Void) { - let dialogMessage = responseMessage != nil && !responseMessage!.isEmpty ? responseMessage : message - let okButton = confirmButtonTitle != nil && !confirmButtonTitle!.isEmpty ? confirmButtonTitle : NSLocalizedString("Ok", comment: "") - let cancelButton = cancelButtonTitle != nil && !cancelButtonTitle!.isEmpty ? cancelButtonTitle : NSLocalizedString("Cancel", comment: "") - - let promptController = UIAlertController(title: nil, message: dialogMessage, preferredStyle: .alert) - - promptController.addTextField { (textField) in - textField.text = defaultValue - } - - promptController.addAction(UIAlertAction(title: okButton, style: .default, handler: { (action) in - if let v = value { - completionHandler(v) - } - else if let text = promptController.textFields?.first?.text { - completionHandler(text) - } else { - completionHandler("") - } - })) - - promptController.addAction(UIAlertAction(title: cancelButton, style: .cancel, handler: { (action) in - completionHandler(nil) - })) - - guard let presentingViewController = inAppBrowserDelegate != nil ? inAppBrowserDelegate as? InAppBrowserWebViewController : window?.rootViewController else { - completionHandler(nil) - return - } - presentingViewController.present(promptController, animated: true, completion: nil) - } - - public func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt message: String, defaultText defaultValue: String?, initiatedByFrame frame: WKFrameInfo, - completionHandler: @escaping (String?) -> Void) { - - var completionHandlerCalled = false - - let callback = WebViewChannelDelegate.JsPromptCallback() - callback.nonNullSuccess = { (response: JsPromptResponse) in - if response.handledByClient { - completionHandlerCalled = true - let action = response.action ?? 1 - switch action { - case 0: - completionHandler(response.value) - break - case 1: - completionHandler(nil) - break - default: - completionHandler(nil) - } - return false - } - return true - } - callback.defaultBehaviour = { [weak self] (response: JsPromptResponse?) in - if !completionHandlerCalled { - completionHandlerCalled = true - let responseMessage = response?.message - let confirmButtonTitle = response?.confirmButtonTitle - let cancelButtonTitle = response?.cancelButtonTitle - let value = response?.value - self?.createPromptDialog(message: message, defaultValue: defaultValue, responseMessage: responseMessage, confirmButtonTitle: confirmButtonTitle, - cancelButtonTitle: cancelButtonTitle, value: value, completionHandler: completionHandler) - } - } - callback.error = { (code: String, message: String?, details: Any?) in - if !completionHandlerCalled { - completionHandlerCalled = true - print(code + ", " + (message ?? "")) - completionHandler(nil) - } - } - - if let channelDelegate = channelDelegate { - channelDelegate.onJsPrompt(url: frame.request.url, message: message, defaultValue: defaultValue, isMainFrame: frame.isMainFrame, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - /// UIScrollViewDelegate is somehow bugged: - /// if InAppWebView implements the UIScrollViewDelegate protocol and implement the scrollViewDidScroll event, - /// then, when the user scrolls the content, the webview content is not rendered (just white space). - /// Calling setNeedsLayout() resolves this problem, but, for some reason, the bounce effect is canceled. - /// - /// So, to track the same event, without implementing the scrollViewDidScroll event, we create - /// an observer that observes the scrollView.contentOffset property. - /// This way, we don't need to call setNeedsLayout() and all works fine. - public func onScrollChanged(startedByUser: Bool, oldContentOffset: CGPoint?) { - let disableVerticalScroll = settings?.disableVerticalScroll ?? false - let disableHorizontalScroll = settings?.disableHorizontalScroll ?? false - if startedByUser { - if disableVerticalScroll && disableHorizontalScroll { - scrollView.contentOffset = CGPoint(x: lastScrollX, y: lastScrollY) - } - else if disableVerticalScroll { - if scrollView.contentOffset.y >= 0 || scrollView.contentOffset.y < 0 { - scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x, y: lastScrollY) - } - } - else if disableHorizontalScroll { - if scrollView.contentOffset.x >= 0 || scrollView.contentOffset.x < 0 { - scrollView.contentOffset = CGPoint(x: lastScrollX, y: scrollView.contentOffset.y) - } - } - } - if (!disableVerticalScroll && !disableHorizontalScroll) || - (disableVerticalScroll && scrollView.contentOffset.x != oldContentOffset?.x) || - (disableHorizontalScroll && scrollView.contentOffset.y != oldContentOffset?.y) { - let x = Int(scrollView.contentOffset.x / scrollView.contentScaleFactor) - let y = Int(scrollView.contentOffset.y / scrollView.contentScaleFactor) - channelDelegate?.onScrollChanged(x: x, y: y) - } - lastScrollX = scrollView.contentOffset.x - lastScrollY = scrollView.contentOffset.y - - let overScrolledHorizontally = lastScrollX < 0 || lastScrollX > (scrollView.contentSize.width - scrollView.frame.size.width) - let overScrolledVertically = lastScrollY < 0 || lastScrollY > (scrollView.contentSize.height - scrollView.frame.size.height) - if overScrolledHorizontally || overScrolledVertically { - let x = Int(lastScrollX / scrollView.contentScaleFactor) - let y = Int(lastScrollY / scrollView.contentScaleFactor) - channelDelegate?.onOverScrolled(x: x, y: y, - clampedX: overScrolledHorizontally, - clampedY: overScrolledVertically) - } - } - - public func onContentSizeChanged(oldContentSize: CGSize) { - channelDelegate?.onContentSizeChanged(oldContentSize: oldContentSize, - newContentSize: scrollView.contentSize) - } - - public func scrollViewDidZoom(_ scrollView: UIScrollView) { - let newScale = Float(scrollView.zoomScale) - if newScale != oldZoomScale { - channelDelegate?.onZoomScaleChanged(newScale: newScale, oldScale: oldZoomScale) - oldZoomScale = newScale - } - } - - public func webView(_ webView: WKWebView, - createWebViewWith configuration: WKWebViewConfiguration, - for navigationAction: WKNavigationAction, - windowFeatures: WKWindowFeatures) -> WKWebView? { - - var windowId: Int64 = 0 - let inAppWebViewManager = plugin?.inAppWebViewManager - if let inAppWebViewManager = inAppWebViewManager { - inAppWebViewManager.windowAutoincrementId += 1 - windowId = inAppWebViewManager.windowAutoincrementId - } - - let windowWebView = InAppWebView(id: nil, plugin: nil, frame: self.bounds, configuration: configuration, contextMenu: nil) - windowWebView.windowId = windowId - - let webViewTransport = WebViewTransport( - webView: windowWebView, - request: navigationAction.request - ) - - inAppWebViewManager?.windowWebViews[windowId] = webViewTransport - - let createWindowAction = CreateWindowAction(navigationAction: navigationAction, windowId: windowId, windowFeatures: windowFeatures, isDialog: nil) - - let callback = WebViewChannelDelegate.CreateWindowCallback() - callback.nonNullSuccess = { (handledByClient: Bool) in - return !handledByClient - } - callback.defaultBehaviour = { [weak self] (handledByClient: Bool?) in - if inAppWebViewManager?.windowWebViews[windowId] != nil { - inAppWebViewManager?.windowWebViews.removeValue(forKey: windowId) - } - self?.loadUrl(urlRequest: navigationAction.request, allowingReadAccessTo: nil) - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - if let channelDelegate = channelDelegate { - channelDelegate.onCreateWindow(createWindowAction: createWindowAction, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - - return windowWebView - } - - public func webView(_ webView: WKWebView, - authenticationChallenge challenge: URLAuthenticationChallenge, - shouldAllowDeprecatedTLS decisionHandler: @escaping (Bool) -> Void) { - var decisionHandlerCalled = false - let callback = WebViewChannelDelegate.ShouldAllowDeprecatedTLSCallback() - callback.nonNullSuccess = { (action: Bool) in - decisionHandlerCalled = true - decisionHandler(action) - return false - } - callback.defaultBehaviour = { (action: Bool?) in - if !decisionHandlerCalled { - decisionHandlerCalled = true - decisionHandler(false) - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - let runCallback = { - if let channelDelegate = self.channelDelegate { - channelDelegate.shouldAllowDeprecatedTLS(challenge: challenge, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - if windowId != nil, !windowCreated { - windowBeforeCreatedCallbacks.append(runCallback) - } else { - runCallback() - } - } - - public func webViewDidClose(_ webView: WKWebView) { - channelDelegate?.onCloseWindow() - } - - public func webViewWebContentProcessDidTerminate(_ webView: WKWebView) { - channelDelegate?.onWebContentProcessDidTerminate() - } - - public func webView(_ webView: WKWebView, - didCommit navigation: WKNavigation!) { - channelDelegate?.onPageCommitVisible(url: url?.absoluteString) - } - - public func webView(_ webView: WKWebView, - didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) { - channelDelegate?.onDidReceiveServerRedirectForProvisionalNavigation() - } - -// @available(iOS 13.0, *) -// public func webView(_ webView: WKWebView, -// contextMenuConfigurationForElement elementInfo: WKContextMenuElementInfo, -// completionHandler: @escaping (UIContextMenuConfiguration?) -> Void) { -// print("contextMenuConfigurationForElement") -// let actionProvider: UIContextMenuActionProvider = { _ in -// let editMenu = UIMenu(title: "Edit...", children: [ -// UIAction(title: "Copy") { action in -// -// }, -// UIAction(title: "Duplicate") { action in -// -// } -// ]) -// return UIMenu(title: "Title", children: [ -// UIAction(title: "Share") { action in -// -// }, -// editMenu -// ]) -// } -// let contextMenuConfiguration = UIContextMenuConfiguration(identifier: nil, previewProvider: nil, actionProvider: actionProvider) -// //completionHandler(contextMenuConfiguration) -// completionHandler(nil) -//// onContextMenuConfigurationForElement(linkURL: elementInfo.linkURL?.absoluteString, result: nil/*{(result) -> Void in -//// if result is FlutterError { -//// print((result as! FlutterError).message ?? "") -//// } -//// else if (result as? NSObject) == FlutterMethodNotImplemented { -//// completionHandler(nil) -//// } -//// else { -//// var response: [String: Any] -//// if let r = result { -//// response = r as! [String: Any] -//// var action = response["action"] as? Int -//// action = action != nil ? action : 0; -//// switch action { -//// case 0: -//// break -//// case 1: -//// break -//// default: -//// completionHandler(nil) -//// } -//// return; -//// } -//// completionHandler(nil) -//// } -//// }*/) -// } -//// -// @available(iOS 13.0, *) -// public func webView(_ webView: WKWebView, -// contextMenuDidEndForElement elementInfo: WKContextMenuElementInfo) { -// print("contextMenuDidEndForElement") -// print(elementInfo) -// //onContextMenuDidEndForElement(linkURL: elementInfo.linkURL?.absoluteString) -// } -// -// @available(iOS 13.0, *) -// public func webView(_ webView: WKWebView, -// contextMenuForElement elementInfo: WKContextMenuElementInfo, -// willCommitWithAnimator animator: UIContextMenuInteractionCommitAnimating) { -// print("willCommitWithAnimator") -// print(elementInfo) -//// onWillCommitWithAnimator(linkURL: elementInfo.linkURL?.absoluteString, result: nil/*{(result) -> Void in -//// if result is FlutterError { -//// print((result as! FlutterError).message ?? "") -//// } -//// else if (result as? NSObject) == FlutterMethodNotImplemented { -//// -//// } -//// else { -//// var response: [String: Any] -//// if let r = result { -//// response = r as! [String: Any] -//// var action = response["action"] as? Int -//// action = action != nil ? action : 0; -////// switch action { -////// case 0: -////// break -////// case 1: -////// break -////// default: -////// -////// } -//// return; -//// } -//// -//// } -//// }*/) -// } -// -// @available(iOS 13.0, *) -// public func webView(_ webView: WKWebView, -// contextMenuWillPresentForElement elementInfo: WKContextMenuElementInfo) { -// print("contextMenuWillPresentForElement") -// print(elementInfo.linkURL) -// //onContextMenuWillPresentForElement(linkURL: elementInfo.linkURL?.absoluteString) -// } - - - /// Determines if the window notification is likely for a fullscreen video/media presentation - /// that originated from THIS specific WebView instance. - /// Uses heuristics based on window properties rather than private class names to avoid App Store rejection. - /// See: https://github.com/pichillilorenzo/flutter_inappwebview/issues/2754 - private func isFullscreenMediaWindow(_ notificationObject: AnyObject?) -> Bool { - guard let fullscreenWindow = notificationObject as? UIWindow else { - return false - } - - // First, check if this WebView is still in the view hierarchy and has a window - guard let myWindow = self.window else { - return false - } - - // Check if the fullscreen window is in the same window scene as our WebView (iOS 13+) - // This helps ensure the fullscreen event is related to our app/scene - if #available(iOS 13.0, *) { - if fullscreenWindow.windowScene != myWindow.windowScene { - return false - } - } - - let screenBounds = UIScreen.main.bounds - let windowFrame = fullscreenWindow.frame - - // Check if the window is full screen or close to it (allowing small margins) - let isFullScreenSize = windowFrame.width >= screenBounds.width * 0.9 && - windowFrame.height >= screenBounds.height * 0.9 - - // Fullscreen video windows typically have an elevated window level - let hasElevatedWindowLevel = fullscreenWindow.windowLevel >= .normal - - // Exclude obvious non-media windows by checking type description - let windowTypeDescription = NSStringFromClass(type(of: fullscreenWindow)) - let isLikelySystemWindow = windowTypeDescription.contains("Keyboard") || - windowTypeDescription.contains("TextEffects") || - windowTypeDescription.contains("Alert") || - windowTypeDescription.contains("StatusBar") || - windowTypeDescription.contains("Accessibility") - - if isLikelySystemWindow { - return false - } - - // For a valid fullscreen from our WebView: - // 1. Must be fullscreen size - // 2. Must have elevated window level (typical for video fullscreen overlays) - // 3. Should be in the same window scene - return isFullScreenSize && hasElevatedWindowLevel - } - - @objc func onEnterFullscreen(_ notification: Notification) { - // Check if already in fullscreen to avoid double-firing - // (both KVO observer and UIWindow notification might trigger this) - guard !inFullscreen else { return } - - if isFullscreenMediaWindow(notification.object as AnyObject?) { - fullscreenWindow = notification.object as? UIWindow - channelDelegate?.onEnterFullscreen() - inFullscreen = true - } - } - - @objc func onExitFullscreen(_ notification: Notification) { - // Check if not in fullscreen to avoid double-firing - // (both KVO observer and UIWindow notification might trigger this) - guard inFullscreen else { return } - - // Check if this is the same window that entered fullscreen - // or if it's a fullscreen-like media window being hidden - let hiddenWindow = notification.object as? UIWindow - let isTrackedFullscreenWindow = fullscreenWindow != nil && fullscreenWindow === hiddenWindow - let isLikelyFullscreenExit = isTrackedFullscreenWindow || isFullscreenMediaWindow(notification.object as AnyObject?) - - if isLikelyFullscreenExit { - fullscreenWindow = nil - channelDelegate?.onExitFullscreen() - inFullscreen = false - } - } - -// public func onContextMenuConfigurationForElement(linkURL: String?, result: FlutterResult?) { -// let arguments: [String: Any?] = ["linkURL": linkURL] -// channel?.invokeMethod("onContextMenuConfigurationForElement", arguments: arguments, result: result) -// } -// -// public func onContextMenuDidEndForElement(linkURL: String?) { -// let arguments: [String: Any?] = ["linkURL": linkURL] -// channel?.invokeMethod("onContextMenuDidEndForElement", arguments: arguments) -// } -// -// public func onWillCommitWithAnimator(linkURL: String?, result: FlutterResult?) { -// let arguments: [String: Any?] = ["linkURL": linkURL] -// channel?.invokeMethod("onWillCommitWithAnimator", arguments: arguments, result: result) -// } -// -// public func onContextMenuWillPresentForElement(linkURL: String?) { -// let arguments: [String: Any?] = ["linkURL": linkURL] -// channel?.invokeMethod("onContextMenuWillPresentForElement", arguments: arguments) -// } - - public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - guard javaScriptBridgeEnabled else { - return - } - - guard let body = message.body as? [String: Any?] else { - return - } - - guard let bridgeSecret = body["_bridgeSecret"] as? String, bridgeSecret == exceptedBridgeSecret else { - print("Bridge access attempt with wrong secret token, possibly from malicious code from origin \(message.frameInfo.securityOrigin)") - return - } - - var sourceOrigin: URL? = nil - let securityOrigin = message.frameInfo.securityOrigin - let scheme = securityOrigin.protocol - let host = securityOrigin.host - let port = securityOrigin.port - if !scheme.isEmpty, !host.isEmpty { - sourceOrigin = URL(string: "\(scheme)://\(host)\(port != 0 ? ":" + String(port) : "")") - } - let requestUrl = message.frameInfo.request.url - - var isOriginAllowed = false - if let javaScriptHandlersOriginAllowList = settings?.javaScriptHandlersOriginAllowList { - if let origin = sourceOrigin?.absoluteString { - for allowedOrigin in javaScriptHandlersOriginAllowList { - if origin.range(of: allowedOrigin, options: .regularExpression, range: nil, locale: nil) != nil { - isOriginAllowed = true - break - } - } - } - } else { - // origin is by default allowed if the allow list is null - isOriginAllowed = true - } - - if !isOriginAllowed { - print("Bridge access attempt from an origin not allowed: \(message.frameInfo.securityOrigin)") - return - } - - if message.name == "callHandler" { - guard let handlerName = body["handlerName"] as? String else { - print("handlerName is null or undefined") - return - } - - let _windowId = body["_windowId"] as? Int64 - var webView = self - if let wId = _windowId, let webViewTransport = plugin?.inAppWebViewManager?.windowWebViews[wId] { - webView = webViewTransport.webView - } - var isInternalHandler = true - switch (handlerName) { - case "onPrintRequest": - let settings = PrintJobSettings() - settings.handledByClient = true - if let printJobId = webView.printCurrentPage(settings: settings) { - let callback = WebViewChannelDelegate.PrintRequestCallback() - callback.nonNullSuccess = { (handledByClient: Bool) in - return !handledByClient - } - callback.defaultBehaviour = { (handledByClient: Bool?) in - if let printJob = webView.plugin?.printJobManager?.jobs[printJobId] { - printJob?.disposeNoDismiss() - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - webView.channelDelegate?.onPrintRequest(url: webView.url, printJobId: printJobId, callback: callback) - } - break - case "onConsoleMessage": - if let args = body["args"] as? String, let data = args.data(using: .utf8) { - let jsonArgs = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String: Any]] - if let jsonData = jsonArgs?.first { - var messageLevel = 1 - switch (jsonData["level"] as? String) { - case "log": - messageLevel = 1 - break - case "debug": - // on Android, console.debug is TIP - messageLevel = 0 - break - case "error": - messageLevel = 3 - break - case "info": - // on Android, console.info is LOG - messageLevel = 1 - break - case "warn": - messageLevel = 2 - break - default: - messageLevel = 1 - break - } - let consoleMessage = jsonData["message"] as? String ?? "" - - webView.channelDelegate?.onConsoleMessage(message: consoleMessage, messageLevel: messageLevel) - } - } - break - case "onFindResultReceived": - if let args = body["args"] as? String, let data = args.data(using: .utf8) { - let jsonArgs = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String: Any]] - if let jsonData = jsonArgs?.first, - let findResult = jsonData["findResult"] as? [String: Any], - let activeMatchOrdinal = findResult["activeMatchOrdinal"] as? Int, - let numberOfMatches = findResult["numberOfMatches"] as? Int, - let isDoneCounting = findResult["isDoneCounting"] as? Bool { - webView.findInteractionController?.channelDelegate?.onFindResultReceived(activeMatchOrdinal: activeMatchOrdinal, numberOfMatches: numberOfMatches, isDoneCounting: isDoneCounting) - webView.channelDelegate?.onFindResultReceived(activeMatchOrdinal: activeMatchOrdinal, numberOfMatches: numberOfMatches, isDoneCounting: isDoneCounting) - } - } - break - case "onCallAsyncJavaScriptResultBelowIOS14Received": - if let args = body["args"] as? String, let data = args.data(using: .utf8) { - let jsonArgs = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String: Any]] - if let jsonData = jsonArgs?.first, - let resultUuid = jsonData["resultUuid"] as? String, - let result = webView.callAsyncJavaScriptBelowIOS14Results[resultUuid] { - result([ - "value": jsonData["value"], - "error": jsonData["error"] - ]) - webView.callAsyncJavaScriptBelowIOS14Results.removeValue(forKey: resultUuid) - } - } - break - case "onWebMessagePortMessageReceived": - if let args = body["args"] as? String, let data = args.data(using: .utf8) { - let jsonArgs = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String: Any]] - if let jsonData = jsonArgs?.first, - let webMessageChannelId = jsonData["webMessageChannelId"] as? String, - let index = jsonData["index"] as? Int64 { - var webMessage: WebMessage? = nil - if let webMessageMap = jsonData["message"] as? [String : Any?] { - webMessage = WebMessage.fromMap(map: webMessageMap) - } - - if let webMessageChannel = webView.webMessageChannels[webMessageChannelId] { - webMessageChannel.channelDelegate?.onMessage(index: index, message: webMessage) - } - } - } - break - case "onWebMessageListenerPostMessageReceived": - if let args = body["args"] as? String, let data = args.data(using: .utf8) { - let jsonArgs = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String: Any]] - if let jsonData = jsonArgs?.first, let jsObjectName = jsonData["jsObjectName"] as? String { - var webMessage: WebMessage? = nil - if let webMessageMap = jsonData["message"] as? [String : Any?] { - webMessage = WebMessage.fromMap(map: webMessageMap) - } - - if let webMessageListener = webView.webMessageListeners.first(where: ({($0.jsObjectName == jsObjectName)})) { - let isMainFrame = message.frameInfo.isMainFrame - - var scheme: String? = nil - var host: String? = nil - var port: Int? = nil - if #available(iOS 9.0, *) { - let sourceOrigin = message.frameInfo.securityOrigin - scheme = sourceOrigin.protocol - host = sourceOrigin.host - port = sourceOrigin.port - } else if let url = message.frameInfo.request.url { - scheme = url.scheme - host = url.host - port = url.port - } - - if !webMessageListener.isOriginAllowed(scheme: scheme, host: host, port: port) { - return - } - - var sourceOrigin: URL? = nil - if let scheme = scheme, !scheme.isEmpty, let host = host, !host.isEmpty { - sourceOrigin = URL(string: "\(scheme)://\(host)\(port != nil && port != 0 ? ":" + String(port!) : "")") - } - webMessageListener.channelDelegate?.onPostMessage(message: webMessage, sourceOrigin: sourceOrigin, isMainFrame: isMainFrame) - } - } - } - break - default: - isInternalHandler = false - break - } - - let _callHandlerID = body["_callHandlerID"] as? Int64 ?? 0 - - if isInternalHandler { - evaluateJavaScript(""" -if(window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)] != null) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)].resolve(); - delete window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)]; -} -""", completionHandler: nil) - return - } - - let args = body["args"] as? String ?? "" - - let callback = WebViewChannelDelegate.CallJsHandlerCallback() - callback.defaultBehaviour = { (response: Any?) in - var json = "null" - if let r = response as? String { - json = r - } - - webView.evaluateJavaScript(""" -if(window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)] != null) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)].resolve(\(json)); - delete window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)]; -} -""", completionHandler: nil) - } - callback.error = { (code: String, message: String?, details: Any?) in - let errorMessage = code + (message != nil ? ", " + (message ?? "") : "") - print(errorMessage) - - webView.evaluateJavaScript(""" -if(window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)] != null) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)].reject(new Error('\(errorMessage.replacingOccurrences(of: "\'", with: "\\'"))')); - delete window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)]; -} -""", completionHandler: nil) - } - - if let channelDelegate = webView.channelDelegate { - let data = JavaScriptHandlerFunctionData( - args: args, isMainFrame: message.frameInfo.isMainFrame, - origin: sourceOrigin?.absoluteString ?? "", - requestUrl: requestUrl?.absoluteString ?? "" - ) - channelDelegate.onCallJsHandler(handlerName: handlerName, data: data, callback: callback) - } - } - } - - public func scrollTo(x: Int, y: Int, animated: Bool) { - scrollView.setContentOffset(CGPoint(x: x, y: y), animated: animated) - } - - public func scrollBy(x: Int, y: Int, animated: Bool) { - let newX = CGFloat(x) + scrollView.contentOffset.x - let newY = CGFloat(y) + scrollView.contentOffset.y - scrollView.setContentOffset(CGPoint(x: newX, y: newY), animated: animated) - } - - - public func pauseTimers() { - if !isPausedTimers { - isPausedTimers = true - let script = "alert();"; - self.evaluateJavaScript(script, completionHandler: nil) - } - } - - public func resumeTimers() { - if isPausedTimers { - if let completionHandler = isPausedTimersCompletionHandler { - self.isPausedTimersCompletionHandler = nil - completionHandler() - } - isPausedTimers = false - } - } - - public func printCurrentPage(settings: PrintJobSettings? = nil, - completionHandler: UIPrintInteractionController.CompletionHandler? = nil) -> String? { - var printJobId: String? = nil - if let settings = settings, settings.handledByClient { - printJobId = NSUUID().uuidString - } - - let printController = UIPrintInteractionController.shared - let printFormatter = self.viewPrintFormatter() - if let settings = settings { - if let margins = settings.margins { - printFormatter.perPageContentInsets = margins - } - if let maximumContentHeight = settings.maximumContentHeight { - printFormatter.maximumContentHeight = maximumContentHeight - } - if let maximumContentWidth = settings.maximumContentWidth { - printFormatter.maximumContentWidth = maximumContentWidth - } - } - printController.printFormatter = printFormatter - - printController.printInfo = UIPrintInfo(dictionary: nil) - if let printInfo = printController.printInfo { - printInfo.jobName = settings?.jobName ?? (title ?? url?.absoluteString ?? "") + " Document" - if let settings = settings { - if let orientationValue = settings.orientation, - let orientation = UIPrintInfo.Orientation.init(rawValue: orientationValue) { - printInfo.orientation = orientation - } - if let duplexModeValue = settings.duplexMode, - let duplexMode = UIPrintInfo.Duplex.init(rawValue: duplexModeValue) { - printInfo.duplex = duplexMode - } - if let outputTypeValue = settings.outputType, - let outputType = UIPrintInfo.OutputType.init(rawValue: outputTypeValue) { - printInfo.outputType = outputType - } - } - } - - // initialize print renderer and set its formatter - let printRenderer = CustomUIPrintPageRenderer(numberOfPage: settings?.numberOfPages, - forceRenderingQuality: settings?.forceRenderingQuality) - printRenderer.addPrintFormatter(printFormatter, startingAtPageAt: 0) - if let settings = settings { - if let footerHeight = settings.footerHeight { - printRenderer.footerHeight = footerHeight - } - if let headerHeight = settings.headerHeight { - printRenderer.headerHeight = headerHeight - } - } - printController.printPageRenderer = printRenderer - - if let settings = settings { - printController.showsNumberOfCopies = settings.showsNumberOfCopies - printController.showsPaperSelectionForLoadedPapers = settings.showsPaperSelectionForLoadedPapers - if #available(iOS 15.0, *) { - printController.showsPaperOrientation = settings.showsPaperOrientation - } - } - - let animated = settings?.animated ?? true - if let id = printJobId, let plugin = plugin { - let printJob = PrintJobController(plugin: plugin, id: id, job: printController, settings: settings) - plugin.printJobManager?.jobs[id] = printJob - printJob.present(animated: animated, completionHandler: completionHandler) - } else { - printController.present(animated: animated, completionHandler: completionHandler) - } - - return printJobId - } - - public func getContentHeight() -> Int64 { - return Int64(scrollView.contentSize.height) - } - - public func getContentWidth() -> Int64 { - return Int64(scrollView.contentSize.width) - } - - public func zoomBy(zoomFactor: Float, animated: Bool) { - let currentZoomScale = scrollView.zoomScale - scrollView.setZoomScale(currentZoomScale * CGFloat(zoomFactor), animated: animated) - } - - public func getOriginalUrl() -> URL? { - return currentOriginalUrl - } - - public func getZoomScale() -> Float { - return Float(scrollView.zoomScale) - } - - public func getSelectedText(completionHandler: @escaping (Any?, Error?) -> Void) { - if configuration.preferences.javaScriptEnabled { - evaluateJavaScript(PluginScriptsUtil.GET_SELECTED_TEXT_JS_SOURCE, completionHandler: completionHandler) - } else { - completionHandler(nil, nil) - } - } - - public func getHitTestResult(completionHandler: @escaping (HitTestResult) -> Void) { - if configuration.preferences.javaScriptEnabled, let lastTouchLocation = lastTouchPoint { - self.evaluateJavaScript("window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findElementsAtPoint(\(lastTouchLocation.x),\(lastTouchLocation.y))", completionHandler: {(value, error) in - if error != nil { - print("getHitTestResult error: \(error?.localizedDescription ?? "")") - completionHandler(HitTestResult(type: .unknownType, extra: nil)) - } else if let value = value as? [String: Any?] { - let hitTestResult = HitTestResult.fromMap(map: value)! - completionHandler(hitTestResult) - } else { - completionHandler(HitTestResult(type: .unknownType, extra: nil)) - } - }) - } else { - completionHandler(HitTestResult(type: .unknownType, extra: nil)) - } - } - - public func requestFocusNodeHref(completionHandler: @escaping ([String: Any?]?, Error?) -> Void) { - if configuration.preferences.javaScriptEnabled { - // add some delay to make it sure _lastAnchorOrImageTouched is updated - DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) { - self.evaluateJavaScript("window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._lastAnchorOrImageTouched", completionHandler: {(value, error) in - let lastAnchorOrImageTouched = value as? [String: Any?] - completionHandler(lastAnchorOrImageTouched, error) - }) - } - } else { - completionHandler(nil, nil) - } - } - - public func requestImageRef(completionHandler: @escaping ([String: Any?]?, Error?) -> Void) { - if configuration.preferences.javaScriptEnabled { - // add some delay to make it sure _lastImageTouched is updated - DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) { - self.evaluateJavaScript("window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._lastImageTouched", completionHandler: {(value, error) in - let lastImageTouched = value as? [String: Any?] - completionHandler(lastImageTouched, error) - }) - } - } else { - completionHandler(nil, nil) - } - } - - public func clearFocus() -> Bool { - return self.scrollView.subviews.first?.resignFirstResponder() ?? false - } - - public func requestFocus() -> Bool { - return self.scrollView.subviews.first?.becomeFirstResponder() ?? false - } - - public func getCertificate() -> SslCertificate? { - guard let scheme = url?.scheme, - scheme == "https", - let host = url?.host, - let sslCertificate = InAppWebView.sslCertificatesMap[host] else { - return nil - } - return sslCertificate - } - - public func isSecureContext(completionHandler: @escaping (_ isSecureContext: Bool) -> Void) { - evaluateJavascript(source: "window.isSecureContext") { (isSecureContext) in - if let isSecureContext = isSecureContext { - completionHandler(isSecureContext as? Bool ?? false) - return - } - completionHandler(false) - } - } - - public func canScrollVertically() -> Bool { - return scrollView.contentSize.height > self.frame.height - } - - public func canScrollHorizontally() -> Bool { - return scrollView.contentSize.width > self.frame.width - } - - public func enablePullToRefresh() { - if let pullToRefreshControl = pullToRefreshControl { - if #available(iOS 10.0, *) { - scrollView.refreshControl = pullToRefreshControl - } else { - scrollView.addSubview(pullToRefreshControl) - } - } - } - - public func disablePullToRefresh() { - pullToRefreshControl?.removeFromSuperview() - if #available(iOS 10.0, *) { - scrollView.refreshControl = nil - } - } - - public func isPullToRefreshEnabled() -> Bool { - if #available(iOS 10.0, *) { - return scrollView.refreshControl != nil - } else { - return pullToRefreshControl?.superview != nil - } - } - - public func createWebMessageChannel(completionHandler: ((WebMessageChannel?) -> Void)? = nil) -> WebMessageChannel? { - guard let plugin = plugin else { - completionHandler?(nil) - return nil - } - let id = NSUUID().uuidString - let webMessageChannel = WebMessageChannel(plugin: plugin, id: id) - webMessageChannel.initJsInstance(webView: self, completionHandler: completionHandler) - webMessageChannels[id] = webMessageChannel - - return webMessageChannel - } - - public func postWebMessage(message: WebMessage, targetOrigin: String, completionHandler: ((Any?) -> Void)? = nil) throws { - var portsString = "null" - if let ports = message.ports { - var portArrayString: [String] = [] - for port in ports { - if port.isStarted { - throw NSError(domain: "Port is already started", code: 0) - } - if port.isClosed || port.isTransferred { - throw NSError(domain: "Port is already closed or transferred", code: 0) - } - port.isTransferred = true - portArrayString.append("\(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())['\(port.webMessageChannel!.id)'].\(port.name)") - } - portsString = "[" + portArrayString.joined(separator: ", ") + "]" - } - - let url = URL(string: targetOrigin)?.absoluteString ?? "*" - let source = """ - (function() { - window.postMessage(\(message.jsData), '\(url)', \(portsString)); - })(); - """ - evaluateJavascript(source: source, completionHandler: completionHandler) - message.dispose() - } - - public func addWebMessageListener(webMessageListener: WebMessageListener) throws { - if webMessageListeners.map({ ($0.jsObjectName) }).contains(webMessageListener.jsObjectName) { - throw NSError(domain: "jsObjectName \(webMessageListener.jsObjectName) was already added.", code: 0) - } - try webMessageListener.assertOriginRulesValid() - webMessageListener.initJsInstance(webView: self) - webMessageListeners.append(webMessageListener) - } - - public func disposeWebMessageChannels() { - for webMessageChannel in webMessageChannels.values { - webMessageChannel.dispose() - } - webMessageChannels.removeAll() - } - - // https://stackoverflow.com/a/58001395/4637638 - public override var inputAccessoryView: UIView? { - return settings?.disableInputAccessoryView ?? false ? nil : super.inputAccessoryView - } - - private var _inputMethodEnabled = true - public override var inputView: UIView? { - return _inputMethodEnabled ? super.inputView : UIView() - } - - public func setInputMethodEnabled(enabled: Bool) { - _inputMethodEnabled = enabled - for subview in self.scrollView.subviews { - subview.reloadInputViews() - } - } - - public func hideInputMethod() { - endEditing(true) - } - - @available(iOS 15.0, *) - public func saveState() -> Data? { - return interactionState is NSData || interactionState is Data ? interactionState as? Data : nil - } - - @available(iOS 15.0, *) - public func restoreState(state: Data) { - interactionState = state - } - - public func runWindowBeforeCreatedCallbacks() { - let callbacks = windowBeforeCreatedCallbacks - callbacks.forEach { (callback) in - callback() - } - windowBeforeCreatedCallbacks.removeAll() - } - - public func dispose() { - channelDelegate?.dispose() - channelDelegate = nil - runWindowBeforeCreatedCallbacks() - removeObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress)) - removeObserver(self, forKeyPath: #keyPath(WKWebView.url)) - removeObserver(self, forKeyPath: #keyPath(WKWebView.title)) - if #available(iOS 15.0, *) { - removeObserver(self, forKeyPath: #keyPath(WKWebView.cameraCaptureState)) - removeObserver(self, forKeyPath: #keyPath(WKWebView.microphoneCaptureState)) - } - if #available(iOS 16.0, *) { - removeObserver(self, forKeyPath: #keyPath(WKWebView.fullscreenState)) - } - scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.contentOffset)) - scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.zoomScale)) - scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.contentSize)) - resumeTimers() - stopLoading() - disposeWebMessageChannels() - for webMessageListener in webMessageListeners { - webMessageListener.dispose() - } - webMessageListeners.removeAll() - interceptOnlyAsyncAjaxRequestsPluginScript = nil - if windowId == nil { - configuration.userContentController.removeAllPluginScriptMessageHandlers() - configuration.userContentController.removeAllUserScripts() - if #available(iOS 11.0, *) { - configuration.userContentController.removeAllContentRuleLists() - } - } else if let wId = windowId, plugin?.inAppWebViewManager?.windowWebViews[wId] != nil { - plugin?.inAppWebViewManager?.windowWebViews.removeValue(forKey: wId) - } - configuration.userContentController.dispose(windowId: windowId) - NotificationCenter.default.removeObserver(self) - for imp in customIMPs { - imp_removeBlock(imp) - } - longPressRecognizer.removeTarget(self, action: #selector(longPressGestureDetected)) - longPressRecognizer.delegate = nil - scrollView.removeGestureRecognizer(longPressRecognizer) - recognizerForDisablingContextMenuOnLinks.removeTarget(self, action: #selector(longPressGestureDetected)) - recognizerForDisablingContextMenuOnLinks.delegate = nil - scrollView.removeGestureRecognizer(recognizerForDisablingContextMenuOnLinks) - panGestureRecognizer.removeTarget(self, action: #selector(endDraggingDetected)) - panGestureRecognizer.delegate = nil - scrollView.removeGestureRecognizer(panGestureRecognizer) - disablePullToRefresh() - pullToRefreshControl?.dispose() - pullToRefreshControl = nil - findInteractionController?.dispose() - findInteractionController = nil - uiDelegate = nil - navigationDelegate = nil - scrollView.delegate = nil - isPausedTimersCompletionHandler = nil - SharedLastTouchPointTimestamp.removeValue(forKey: self) - callAsyncJavaScriptBelowIOS14Results.removeAll() - plugin = nil - } - - deinit { - debugPrint("InAppWebView - dealloc") - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/InAppWebViewManager.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/InAppWebViewManager.swift deleted file mode 100755 index 2dd1aea2c3..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/InAppWebViewManager.swift +++ /dev/null @@ -1,137 +0,0 @@ -// -// InAppWebViewManager.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 08/12/2019. -// - -import Foundation -import WebKit -import Flutter - -public class InAppWebViewManager: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_manager" - var plugin: InAppWebViewFlutterPlugin? - var webViewForUserAgent: WKWebView? - var defaultUserAgent: String? - - var keepAliveWebViews: [String:FlutterWebViewController?] = [:] - var windowWebViews: [Int64:WebViewTransport] = [:] - var windowAutoincrementId: Int64 = 0 - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: InAppWebViewManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger())) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "getDefaultUserAgent": - getDefaultUserAgent(completionHandler: { (value) in - result(value) - }) - break - case "handlesURLScheme": - let urlScheme = arguments!["urlScheme"] as! String - if #available(iOS 11.0, *) { - result(WKWebView.handlesURLScheme(urlScheme)) - } else { - result(false) - } - break - case "disposeKeepAlive": - let keepAliveId = arguments!["keepAliveId"] as! String - disposeKeepAlive(keepAliveId: keepAliveId) - result(true) - break - case "clearAllCache": - let includeDiskFiles = arguments!["includeDiskFiles"] as! Bool - clearAllCache(includeDiskFiles: includeDiskFiles, completionHandler: { - result(true) - }) - case "setJavaScriptBridgeName": - let bridgeName = arguments!["bridgeName"] as! String - JavaScriptBridgeJS.set_JAVASCRIPT_BRIDGE_NAME(bridgeName: bridgeName) - result(true) - break - case "getJavaScriptBridgeName": - result(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func getDefaultUserAgent(completionHandler: @escaping (_ value: String?) -> Void) { - if defaultUserAgent == nil { - webViewForUserAgent = WKWebView() - webViewForUserAgent?.evaluateJavaScript("navigator.userAgent") { (value, error) in - - if error != nil { - print("Error occurred to get userAgent") - self.webViewForUserAgent = nil - completionHandler(nil) - return - } - - if let unwrappedUserAgent = value as? String { - self.defaultUserAgent = unwrappedUserAgent - completionHandler(self.defaultUserAgent) - } else { - print("Failed to get userAgent") - } - self.webViewForUserAgent = nil - } - } else { - completionHandler(defaultUserAgent) - } - } - - public func disposeKeepAlive(keepAliveId: String) { - if let flutterWebView = keepAliveWebViews[keepAliveId] as? FlutterWebViewController { - flutterWebView.keepAliveId = nil - flutterWebView.dispose(removeFromSuperview: true) - keepAliveWebViews[keepAliveId] = nil - } - } - - public func clearAllCache(includeDiskFiles: Bool, completionHandler: @escaping () -> Void) { - if #available(iOS 9.0, *) { - var websiteDataTypes = Set([WKWebsiteDataTypeMemoryCache]) - if includeDiskFiles { - websiteDataTypes.insert(WKWebsiteDataTypeDiskCache) - if #available(iOS 11.3, *) { - websiteDataTypes.insert(WKWebsiteDataTypeFetchCache) - } - websiteDataTypes.insert(WKWebsiteDataTypeOfflineWebApplicationCache) - } - let date = NSDate(timeIntervalSince1970: 0) - WKWebsiteDataStore.default().removeData(ofTypes: websiteDataTypes, modifiedSince: date as Date, completionHandler: completionHandler) - } else { - URLCache.shared.removeAllCachedResponses() - completionHandler() - } - } - - public override func dispose() { - super.dispose() - let keepAliveWebViewValues = keepAliveWebViews.values - keepAliveWebViewValues.forEach {(keepAliveWebView: FlutterWebViewController?) in - if let keepAliveId = keepAliveWebView?.keepAliveId { - disposeKeepAlive(keepAliveId: keepAliveId) - } - } - keepAliveWebViews.removeAll() - windowWebViews.removeAll() - webViewForUserAgent = nil - defaultUserAgent = nil - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/InAppWebViewSettings.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/InAppWebViewSettings.swift deleted file mode 100755 index dc65eb0fc2..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/InAppWebViewSettings.swift +++ /dev/null @@ -1,198 +0,0 @@ -// -// InAppWebViewSettings.swift -// flutter_inappwebview -// -// Created by Lorenzo on 21/10/18. -// - -import Foundation -import WebKit - -@objcMembers -public class InAppWebViewSettings: ISettings { - - var useShouldOverrideUrlLoading = false - var useOnLoadResource = false - var useOnDownloadStart = false - @available(*, deprecated, message: "Use InAppWebViewManager.clearAllCache instead.") - var clearCache = false - var userAgent = "" - var applicationNameForUserAgent = "" - var javaScriptEnabled = true - var javaScriptCanOpenWindowsAutomatically = false - var mediaPlaybackRequiresUserGesture = true - var verticalScrollBarEnabled = true - var horizontalScrollBarEnabled = true - var resourceCustomSchemes: [String] = [] - var contentBlockers: [[String: [String : Any]]] = [] - var minimumFontSize = 0 - var useShouldInterceptAjaxRequest = false - var useOnAjaxReadyStateChange = false - var useOnAjaxProgress = false - var interceptOnlyAsyncAjaxRequests = true - var useShouldInterceptFetchRequest = false - var incognito = false - var cacheEnabled = true - var transparentBackground = false - var disableVerticalScroll = false - var disableHorizontalScroll = false - var disableContextMenu = false - var supportZoom = true - var allowUniversalAccessFromFileURLs = false - var allowFileAccessFromFileURLs = false - - var disallowOverScroll = false - var enableViewportScale = false - var suppressesIncrementalRendering = false - var allowsAirPlayForMediaPlayback = true - var allowsBackForwardNavigationGestures = true - var allowsLinkPreview = true - var ignoresViewportScaleLimits = false - var allowsInlineMediaPlayback = false - var allowsPictureInPictureMediaPlayback = true - var isFraudulentWebsiteWarningEnabled = true - var selectionGranularity = 0 - var dataDetectorTypes: [String] = ["NONE"] // WKDataDetectorTypeNone - var preferredContentMode = 0 - var sharedCookiesEnabled = false - var automaticallyAdjustsScrollIndicatorInsets = false - var accessibilityIgnoresInvertColors = false - var decelerationRate = "NORMAL" // UIScrollView.DecelerationRate.normal - var alwaysBounceVertical = false - var alwaysBounceHorizontal = false - var scrollsToTop = true - var isPagingEnabled = false - var maximumZoomScale = 1.0 - var minimumZoomScale = 1.0 - var contentInsetAdjustmentBehavior = 2 // UIScrollView.ContentInsetAdjustmentBehavior.never - var isDirectionalLockEnabled = false - var mediaType: String? = nil - var pageZoom = 1.0 - var limitsNavigationsToAppBoundDomains = false - var useOnNavigationResponse = false - var applePayAPIEnabled = false - var allowingReadAccessTo: String? = nil - var disableLongPressContextMenuOnLinks = false - var disableInputAccessoryView = false - var underPageBackgroundColor: String? - var isTextInteractionEnabled = true - var isSiteSpecificQuirksModeEnabled = true - var upgradeKnownHostsToHTTPS = true - var isElementFullscreenEnabled = true - var isFindInteractionEnabled = false - var minimumViewportInset: UIEdgeInsets? = nil - var maximumViewportInset: UIEdgeInsets? = nil - var isInspectable = false - var shouldPrintBackgrounds = false - var javaScriptHandlersOriginAllowList: [String]? = nil - var javaScriptBridgeEnabled = true - var javaScriptBridgeOriginAllowList: [String]? = nil - var javaScriptBridgeForMainFrameOnly = false - var pluginScriptsOriginAllowList: [String]? = nil - var pluginScriptsForMainFrameOnly = false - var isUserInteractionEnabled = true - var alpha: Double? = nil - - override init(){ - super.init() - } - - override func parse(settings: [String: Any?]) -> InAppWebViewSettings { - var settings = settings // re-assing to be able to use removeValue - if let minimumViewportInsetMap = settings["minimumViewportInset"] as? [String : Double] { - minimumViewportInset = UIEdgeInsets.fromMap(map: minimumViewportInsetMap) - settings.removeValue(forKey: "minimumViewportInset") - } - if let maximumViewportInsetMap = settings["maximumViewportInset"] as? [String : Double] { - maximumViewportInset = UIEdgeInsets.fromMap(map: maximumViewportInsetMap) - settings.removeValue(forKey: "maximumViewportInset") - } - // nullable values with primitive type (Int, Double, etc.) - // must be handled here as super.parse will not work - if let alphaValue = settings["alpha"] as? Double { - alpha = alphaValue - settings.removeValue(forKey: "alpha") - } - let _ = super.parse(settings: settings) - if #available(iOS 13.0, *) {} else { - applePayAPIEnabled = false - } - return self - } - - override func getRealSettings(obj: InAppWebView?) -> [String: Any?] { - var realSettings: [String: Any?] = toMap() - if let webView = obj { - realSettings["isUserInteractionEnabled"] = webView.isUserInteractionEnabled - realSettings["alpha"] = Double(webView.alpha) - let configuration = webView.configuration - if #available(iOS 9.0, *) { - realSettings["userAgent"] = webView.customUserAgent - realSettings["applicationNameForUserAgent"] = configuration.applicationNameForUserAgent - realSettings["allowsAirPlayForMediaPlayback"] = configuration.allowsAirPlayForMediaPlayback - realSettings["allowsLinkPreview"] = webView.allowsLinkPreview - realSettings["allowsPictureInPictureMediaPlayback"] = configuration.allowsPictureInPictureMediaPlayback - } - realSettings["javaScriptCanOpenWindowsAutomatically"] = configuration.preferences.javaScriptCanOpenWindowsAutomatically - if #available(iOS 10.0, *) { - realSettings["mediaPlaybackRequiresUserGesture"] = configuration.mediaTypesRequiringUserActionForPlayback == .all - realSettings["ignoresViewportScaleLimits"] = configuration.ignoresViewportScaleLimits - realSettings["dataDetectorTypes"] = Util.getDataDetectorTypeString(type: configuration.dataDetectorTypes) - } else { - realSettings["mediaPlaybackRequiresUserGesture"] = configuration.mediaPlaybackRequiresUserAction - } - realSettings["minimumFontSize"] = Int(configuration.preferences.minimumFontSize) - realSettings["suppressesIncrementalRendering"] = configuration.suppressesIncrementalRendering - realSettings["allowsBackForwardNavigationGestures"] = webView.allowsBackForwardNavigationGestures - realSettings["allowsInlineMediaPlayback"] = configuration.allowsInlineMediaPlayback - if #available(iOS 13.0, *) { - realSettings["isFraudulentWebsiteWarningEnabled"] = configuration.preferences.isFraudulentWebsiteWarningEnabled - realSettings["preferredContentMode"] = configuration.defaultWebpagePreferences.preferredContentMode.rawValue - realSettings["automaticallyAdjustsScrollIndicatorInsets"] = webView.scrollView.automaticallyAdjustsScrollIndicatorInsets - } - realSettings["selectionGranularity"] = configuration.selectionGranularity.rawValue - if #available(iOS 11.0, *) { - realSettings["accessibilityIgnoresInvertColors"] = webView.accessibilityIgnoresInvertColors - realSettings["contentInsetAdjustmentBehavior"] = webView.scrollView.contentInsetAdjustmentBehavior.rawValue - } - realSettings["decelerationRate"] = Util.getDecelerationRateString(type: webView.scrollView.decelerationRate) - realSettings["alwaysBounceVertical"] = webView.scrollView.alwaysBounceVertical - realSettings["alwaysBounceHorizontal"] = webView.scrollView.alwaysBounceHorizontal - realSettings["scrollsToTop"] = webView.scrollView.scrollsToTop - realSettings["isPagingEnabled"] = webView.scrollView.isPagingEnabled - realSettings["maximumZoomScale"] = webView.scrollView.maximumZoomScale - realSettings["minimumZoomScale"] = webView.scrollView.minimumZoomScale - realSettings["allowUniversalAccessFromFileURLs"] = configuration.value(forKey: "allowUniversalAccessFromFileURLs") - realSettings["allowFileAccessFromFileURLs"] = configuration.preferences.value(forKey: "allowFileAccessFromFileURLs") - realSettings["isDirectionalLockEnabled"] = webView.scrollView.isDirectionalLockEnabled - realSettings["javaScriptEnabled"] = configuration.preferences.javaScriptEnabled - if #available(iOS 14.0, *) { - realSettings["mediaType"] = webView.mediaType - realSettings["pageZoom"] = Float(webView.pageZoom) - realSettings["limitsNavigationsToAppBoundDomains"] = configuration.limitsNavigationsToAppBoundDomains - realSettings["javaScriptEnabled"] = configuration.defaultWebpagePreferences.allowsContentJavaScript - } - if #available(iOS 15.0, *) { - realSettings["isTextInteractionEnabled"] = configuration.preferences.isTextInteractionEnabled - realSettings["upgradeKnownHostsToHTTPS"] = configuration.upgradeKnownHostsToHTTPS - realSettings["underPageBackgroundColor"] = webView.underPageBackgroundColor.hexString - } - if #available(iOS 15.4, *) { - realSettings["isSiteSpecificQuirksModeEnabled"] = configuration.preferences.isSiteSpecificQuirksModeEnabled - realSettings["isElementFullscreenEnabled"] = configuration.preferences.isElementFullscreenEnabled - } - if #available(iOS 15.5, *) { - realSettings["minimumViewportInset"] = webView.minimumViewportInset.toMap() - realSettings["maximumViewportInset"] = webView.maximumViewportInset.toMap() - } - if #available(iOS 16.0, *) { - realSettings["isFindInteractionEnabled"] = webView.isFindInteractionEnabled - } - if #available(iOS 16.4, *) { - realSettings["isInspectable"] = webView.isInspectable - realSettings["shouldPrintBackgrounds"] = configuration.preferences.shouldPrintBackgrounds - } - } - return realSettings - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebMessage/WebMessageChannel.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebMessage/WebMessageChannel.swift deleted file mode 100644 index 8b4df3e83c..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebMessage/WebMessageChannel.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// WebMessageChannel.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/03/21. -// - -import Foundation -import Flutter - -public class WebMessageChannel: FlutterMethodCallDelegate { - static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_web_message_channel_" - var id: String - var plugin: InAppWebViewFlutterPlugin? - var channelDelegate: WebMessageChannelChannelDelegate? - weak var webView: InAppWebView? - var ports: [WebMessagePort] = [] - - public init(plugin: InAppWebViewFlutterPlugin, id: String) { - self.id = id - self.plugin = plugin - super.init() - let channel = FlutterMethodChannel(name: WebMessageChannel.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: plugin.registrar.messenger()) - self.channelDelegate = WebMessageChannelChannelDelegate(webMessageChannel: self, channel: channel) - self.ports = [ - WebMessagePort(name: "port1", index: 0, webMessageChannelId: self.id, webMessageChannel: self), - WebMessagePort(name: "port2", index: 1, webMessageChannelId: self.id, webMessageChannel: self) - ] - } - - public func initJsInstance(webView: InAppWebView, completionHandler: ((WebMessageChannel?) -> Void)? = nil) { - self.webView = webView - if let webView = self.webView { - webView.evaluateJavascript(source: """ - (function() { - \(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())["\(id)"] = new MessageChannel(); - })(); - """) { (_) in - completionHandler?(self) - } - } else { - completionHandler?(nil) - } - } - - public func toMap() -> [String:Any?] { - return [ - "id": id - ] - } - - public func dispose() { - channelDelegate?.dispose() - channelDelegate = nil - for port in ports { - port.dispose() - } - ports.removeAll() - webView?.evaluateJavascript(source: """ - (function() { - var webMessageChannel = \(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())["\(id)"]; - if (webMessageChannel != null) { - webMessageChannel.port1.close(); - webMessageChannel.port2.close(); - delete \(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())["\(id)"]; - } - })(); - """) - webView = nil - plugin = nil - } - - deinit { - debugPrint("WebMessageChannel - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebMessage/WebMessageChannelChannelDelegate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebMessage/WebMessageChannelChannelDelegate.swift deleted file mode 100644 index 820b293243..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebMessage/WebMessageChannelChannelDelegate.swift +++ /dev/null @@ -1,103 +0,0 @@ -// -// WebMessageChannelChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation -import Flutter - -public class WebMessageChannelChannelDelegate: ChannelDelegate { - private weak var webMessageChannel: WebMessageChannel? - - public init(webMessageChannel: WebMessageChannel, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.webMessageChannel = webMessageChannel - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "setWebMessageCallback": - if let _ = webMessageChannel?.webView, let ports = webMessageChannel?.ports, ports.count > 0 { - let index = arguments!["index"] as! Int - let port = ports[index] - do { - try port.setWebMessageCallback { (_) in - result(true) - } - } catch let error as NSError { - result(FlutterError(code: "WebMessageChannel", message: error.domain, details: nil)) - } - - } else { - result(true) - } - break - case "postMessage": - if let webView = webMessageChannel?.webView, let ports = webMessageChannel?.ports, ports.count > 0 { - let index = arguments!["index"] as! Int - let port = ports[index] - let message = WebMessage.fromMap(map: arguments!["message"] as! [String: Any?]) - - var ports: [WebMessagePort] = [] - if let notConnectedPorts = message.ports { - for notConnectedPort in notConnectedPorts { - if let webMessageChannel = webView.webMessageChannels[notConnectedPort.webMessageChannelId] { - ports.append(webMessageChannel.ports[Int(notConnectedPort.index)]) - } - } - } - message.ports = ports - - do { - try port.postMessage(message: message) { (_) in - result(true) - } - } catch let error as NSError { - result(FlutterError(code: "WebMessageChannel", message: error.domain, details: nil)) - } - } else { - result(true) - } - break - case "close": - if let _ = webMessageChannel?.webView, let ports = webMessageChannel?.ports, ports.count > 0 { - let index = arguments!["index"] as! Int - let port = ports[index] - do { - try port.close { (_) in - result(true) - } - } catch let error as NSError { - result(FlutterError(code: "WebMessageChannel", message: error.domain, details: nil)) - } - } else { - result(true) - } - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func onMessage(index: Int64, message: WebMessage?) { - let arguments: [String:Any?] = [ - "index": index, - "message": message?.toMap() - ] - channel?.invokeMethod("onMessage", arguments: arguments) - } - - public override func dispose() { - super.dispose() - webMessageChannel = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebMessage/WebMessageListener.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebMessage/WebMessageListener.swift deleted file mode 100644 index 5ecb496255..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebMessage/WebMessageListener.swift +++ /dev/null @@ -1,278 +0,0 @@ -// -// WebMessageListener.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/03/21. -// - -import Foundation -import WebKit -import Flutter - -public class WebMessageListener: FlutterMethodCallDelegate { - static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_web_message_listener_" - var id: String - var jsObjectName: String - var allowedOriginRules: Set - var channelDelegate: WebMessageListenerChannelDelegate? - weak var webView: InAppWebView? - var plugin: InAppWebViewFlutterPlugin? - - public init(plugin: InAppWebViewFlutterPlugin, id: String, jsObjectName: String, allowedOriginRules: Set) { - self.id = id - self.plugin = plugin - self.jsObjectName = jsObjectName - self.allowedOriginRules = allowedOriginRules - super.init() - let channel = FlutterMethodChannel(name: WebMessageListener.METHOD_CHANNEL_NAME_PREFIX + self.id + "_" + self.jsObjectName, - binaryMessenger: plugin.registrar.messenger()) - self.channelDelegate = WebMessageListenerChannelDelegate(webMessageListener: self, channel: channel) - } - - public func assertOriginRulesValid() throws { - for (index, originRule) in allowedOriginRules.enumerated() { - if originRule.isEmpty { - throw NSError(domain: "allowedOriginRules[\(index)] is empty", code: 0) - } - if originRule == "*" { - continue - } - if let url = URL(string: originRule) { - guard let scheme = url.scheme else { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - if scheme == "http" || scheme == "https", url.host == nil || url.host!.isEmpty { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - if scheme != "http", scheme != "https", url.host != nil || url.port != nil { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - if url.host == nil || url.host!.isEmpty, url.port != nil { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - if !url.path.isEmpty { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - if let hostname = url.host { - if let firstIndex = hostname.firstIndex(of: "*") { - let distance = hostname.distance(from: hostname.startIndex, to: firstIndex) - if distance != 0 || (distance == 0 && hostname.prefix(2) != "*.") { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - } - if hostname.hasPrefix("[") { - if !hostname.hasSuffix("]") { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - let fromIndex = hostname.index(hostname.startIndex, offsetBy: 1) - let toIndex = hostname.index(hostname.startIndex, offsetBy: hostname.count - 1) - let indexRange = Range(uncheckedBounds: (lower: fromIndex, upper: toIndex)) - let ipv6 = String(hostname[indexRange]) - if !Util.isIPv6(address: ipv6) { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - } - } - } else { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - } - } - - public func initJsInstance(webView: InAppWebView) { - self.webView = webView - if let webView = self.webView { - let jsObjectNameEscaped = jsObjectName.replacingOccurrences(of: "\'", with: "\\'") - let allowedOriginRulesString = allowedOriginRules.map { (allowedOriginRule) -> String in - if allowedOriginRule == "*" { - return "'*'" - } - let rule = URL(string: allowedOriginRule)! - let host = rule.host != nil ? "'" + rule.host!.replacingOccurrences(of: "\'", with: "\\'") + "'" : "null" - return """ - {scheme: '\(rule.scheme!)', host: \(host), port: \(rule.port != nil ? String(rule.port!) : "null")} - """ - }.joined(separator: ", ") - let source = """ - (function() { - \(WebMessageListener.isOriginAllowedJs) - - var allowedOriginRules = [\(allowedOriginRulesString)]; - var isPageBlank = window.location.href === "about:blank"; - var scheme = !isPageBlank ? window.location.protocol.replace(":", "") : null; - var host = !isPageBlank ? window.location.hostname : null; - var port = !isPageBlank ? window.location.port : null; - if (_isOriginAllowed(allowedOriginRules, scheme, host, port)) { - window['\(jsObjectNameEscaped)'] = new FlutterInAppWebViewWebMessageListener('\(jsObjectNameEscaped)'); - } - })(); - """ - - let allowedOriginRules = webView.settings?.pluginScriptsOriginAllowList - let forMainFrameOnly = webView.settings?.pluginScriptsForMainFrameOnly ?? true - - webView.configuration.userContentController.addPluginScript(PluginScript( - groupName: "WebMessageListener-" + id + "-" + jsObjectName, - source: source, - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: [] - )) - webView.configuration.userContentController.sync(scriptMessageHandler: webView) - } - } - - public static func fromMap(plugin: InAppWebViewFlutterPlugin, map: [String:Any?]?) -> WebMessageListener? { - guard let map = map else { - return nil - } - return WebMessageListener( - plugin: plugin, - id: map["id"] as! String, - jsObjectName: map["jsObjectName"] as! String, - allowedOriginRules: Set(map["allowedOriginRules"] as! [String]) - ) - } - - public func isOriginAllowed(scheme: String?, host: String?, port: Int?) -> Bool { - for allowedOriginRule in allowedOriginRules { - if allowedOriginRule == "*" { - return true - } - if scheme == nil || scheme!.isEmpty { - continue - } - if scheme == nil || scheme!.isEmpty, host == nil || host!.isEmpty, port == nil || port == 0 { - continue - } - if let rule = URL(string: allowedOriginRule) { - let rulePort = rule.port == nil || rule.port == 0 ? (rule.scheme == "https" ? 443 : 80) : rule.port! - let currentPort = port == nil || port == 0 ? (scheme == "https" ? 443 : 80) : port! - var IPv6: String? = nil - if let hostname = rule.host, hostname.hasPrefix("[") { - let fromIndex = hostname.index(hostname.startIndex, offsetBy: 1) - let toIndex = hostname.index(hostname.startIndex, offsetBy: hostname.count - 1) - let indexRange = Range(uncheckedBounds: (lower: fromIndex, upper: toIndex)) - do { - IPv6 = try Util.normalizeIPv6(address: String(hostname[indexRange])) - } catch {} - } - var hostIPv6: String? = nil - if let host = host, Util.isIPv6(address: host) { - do { - hostIPv6 = try Util.normalizeIPv6(address: host) - } catch {} - } - - let schemeAllowed = scheme != nil && !scheme!.isEmpty && scheme == rule.scheme - - let hostAllowed = rule.host == nil || - rule.host!.isEmpty || - host == rule.host || - (rule.host!.hasPrefix("*") && host != nil && host!.hasSuffix(rule.host!.split(separator: "*", omittingEmptySubsequences: false)[1])) || - (hostIPv6 != nil && IPv6 != nil && hostIPv6 == IPv6) - - let portAllowed = rulePort == currentPort - - if schemeAllowed, hostAllowed, portAllowed { - return true - } - } - } - return false - } - - private static let isOriginAllowedJs = """ - var _normalizeIPv6 = function(ip_string) { - // replace ipv4 address if any - var ipv4 = ip_string.match(/(.*:)([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$)/); - if (ipv4) { - ip_string = ipv4[1]; - ipv4 = ipv4[2].match(/[0-9]+/g); - for (var i = 0;i < 4;i ++) { - var byte = parseInt(ipv4[i],10); - ipv4[i] = ("0" + byte.toString(16)).substr(-2); - } - ip_string += ipv4[0] + ipv4[1] + ':' + ipv4[2] + ipv4[3]; - } - - // take care of leading and trailing :: - ip_string = ip_string.replace(/^:|:$/g, ''); - - var ipv6 = ip_string.split(':'); - - for (var i = 0; i < ipv6.length; i ++) { - var hex = ipv6[i]; - if (hex != "") { - // normalize leading zeros - ipv6[i] = ("0000" + hex).substr(-4); - } - else { - // normalize grouped zeros :: - hex = []; - for (var j = ipv6.length; j <= 8; j ++) { - hex.push('0000'); - } - ipv6[i] = hex.join(':'); - } - } - - return ipv6.join(':'); - }; - - var _isOriginAllowed = function(allowedOriginRules, scheme, host, port) { - for (var rule of allowedOriginRules) { - if (rule === "*") { - return true; - } - if (scheme == null || scheme === "") { - continue; - } - if ((scheme == null || scheme === "") && (host == null || host === "") && (port === 0 || port === "" || port == null)) { - continue; - } - var rulePort = rule.port == null || rule.port === 0 ? (rule.scheme == "https" ? 443 : 80) : rule.port; - var currentPort = port === 0 || port === "" || port == null ? (scheme == "https" ? 443 : 80) : port; - var IPv6 = null; - if (rule.host != null && rule.host[0] === "[") { - try { - IPv6 = _normalizeIPv6(rule.host.substring(1, rule.host.length - 1)); - } catch {} - } - var hostIPv6 = null; - try { - hostIPv6 = _normalizeIPv6(host); - } catch {} - - var schemeAllowed = scheme == rule.scheme; - - var hostAllowed = rule.host == null || - rule.host === "" || - host === rule.host || - (rule.host[0] === "*" && host != null && host.indexOf(rule.host.split("*")[1]) >= 0) || - (hostIPv6 != null && IPv6 != null && hostIPv6 === IPv6); - - var portAllowed = rulePort === currentPort; - - if (schemeAllowed && hostAllowed && portAllowed) { - return true; - } - } - return false; - }; - """ - - public func dispose() { - channelDelegate?.dispose() - channelDelegate = nil - webView = nil - plugin = nil - } - - deinit { - debugPrint("WebMessageListener - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebMessage/WebMessageListenerChannelDelegate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebMessage/WebMessageListenerChannelDelegate.swift deleted file mode 100644 index ac9644590e..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebMessage/WebMessageListenerChannelDelegate.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// WebMessageListenerChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation -import Flutter - -public class WebMessageListenerChannelDelegate: ChannelDelegate { - private weak var webMessageListener: WebMessageListener? - - public init(webMessageListener: WebMessageListener, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.webMessageListener = webMessageListener - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "postMessage": - if let webView = webMessageListener?.webView, let jsObjectName = webMessageListener?.jsObjectName { - let jsObjectNameEscaped = jsObjectName.replacingOccurrences(of: "\'", with: "\\'") - let message = WebMessage.fromMap(map: arguments!["message"] as! [String: Any?]) - - let source = """ - (function() { - var webMessageListener = window['\(jsObjectNameEscaped)']; - if (webMessageListener != null) { - var event = {data: \(message.jsData)}; - if (webMessageListener.onmessage != null) { - webMessageListener.onmessage(event); - } - for (var listener of webMessageListener.listeners) { - listener(event); - } - } - })(); - """ - webView.evaluateJavascript(source: source) { (_) in - result(true) - } - } else { - result(true) - } - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func onPostMessage(message: WebMessage?, sourceOrigin: URL?, isMainFrame: Bool) { - let arguments: [String:Any?] = [ - "message": message?.toMap(), - "sourceOrigin": sourceOrigin?.absoluteString, - "isMainFrame": isMainFrame - ] - channel?.invokeMethod("onPostMessage", arguments: arguments) - } - - public override func dispose() { - super.dispose() - webMessageListener = nil - } - - deinit { - dispose() - } -} - diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebViewChannelDelegate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebViewChannelDelegate.swift deleted file mode 100644 index 44100622f2..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebViewChannelDelegate.swift +++ /dev/null @@ -1,1248 +0,0 @@ -// -// WebViewChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 06/05/22. -// - -import Foundation -import WebKit -import Flutter - -public class WebViewChannelDelegate: ChannelDelegate { - private weak var webView: InAppWebView? - - public init(webView: InAppWebView, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.webView = webView - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - guard let method = WebViewChannelDelegateMethods.init(rawValue: call.method) else { - result(FlutterMethodNotImplemented) - return - } - - switch method { - case .getUrl: - result(webView?.url?.absoluteString) - break - case .getTitle: - result(webView?.title) - break - case .getProgress: - result( (webView != nil) ? Int(webView!.estimatedProgress * 100) : nil ) - break - case .loadUrl: - let urlRequest = arguments!["urlRequest"] as! [String:Any?] - let allowingReadAccessTo = arguments!["allowingReadAccessTo"] as? String - var allowingReadAccessToURL: URL? = nil - if let allowingReadAccessTo = allowingReadAccessTo { - allowingReadAccessToURL = URL(string: allowingReadAccessTo) - } - webView?.loadUrl(urlRequest: URLRequest.init(fromPluginMap: urlRequest), allowingReadAccessTo: allowingReadAccessToURL) - result(true) - break - case .postUrl: - if let webView = webView { - let url = arguments!["url"] as! String - let postData = arguments!["postData"] as! FlutterStandardTypedData - webView.postUrl(url: URL(string: url)!, postData: postData.data) - } - result(true) - break - case .loadData: - let data = arguments!["data"] as! String - let mimeType = arguments!["mimeType"] as! String - let encoding = arguments!["encoding"] as! String - let baseUrl = URL(string: arguments!["baseUrl"] as! String)! - let allowingReadAccessTo = arguments!["allowingReadAccessTo"] as? String - var allowingReadAccessToURL: URL? = nil - if let allowingReadAccessTo = allowingReadAccessTo { - allowingReadAccessToURL = URL(string: allowingReadAccessTo) - } - webView?.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl, allowingReadAccessTo: allowingReadAccessToURL) - result(true) - break - case .loadFile: - let assetFilePath = arguments!["assetFilePath"] as! String - - do { - try webView?.loadFile(assetFilePath: assetFilePath) - } - catch let error as NSError { - result(FlutterError(code: "WebViewChannelDelegate", message: error.domain, details: nil)) - return - } - result(true) - break - case .evaluateJavascript: - if let webView = webView { - let source = arguments!["source"] as! String - let contentWorldMap = arguments!["contentWorld"] as? [String:Any?] - if #available(iOS 14.0, *), let contentWorldMap = contentWorldMap { - let contentWorld = WKContentWorld.fromMap(map: contentWorldMap, windowId: webView.windowId)! - webView.evaluateJavascript(source: source, contentWorld: contentWorld) { (value) in - result(value) - } - } else { - webView.evaluateJavascript(source: source) { (value) in - result(value) - } - } - } - else { - result(nil) - } - break - case .injectJavascriptFileFromUrl: - let urlFile = arguments!["urlFile"] as! String - let scriptHtmlTagAttributes = arguments!["scriptHtmlTagAttributes"] as? [String:Any?] - webView?.injectJavascriptFileFromUrl(urlFile: urlFile, scriptHtmlTagAttributes: scriptHtmlTagAttributes) - result(true) - break - case .injectCSSCode: - let source = arguments!["source"] as! String - webView?.injectCSSCode(source: source) - result(true) - break - case .injectCSSFileFromUrl: - let urlFile = arguments!["urlFile"] as! String - let cssLinkHtmlTagAttributes = arguments!["cssLinkHtmlTagAttributes"] as? [String:Any?] - webView?.injectCSSFileFromUrl(urlFile: urlFile, cssLinkHtmlTagAttributes: cssLinkHtmlTagAttributes) - result(true) - break - case .reload: - webView?.reload() - result(true) - break - case .goBack: - webView?.goBack() - result(true) - break - case .canGoBack: - result(webView?.canGoBack ?? false) - break - case .goForward: - webView?.goForward() - result(true) - break - case .canGoForward: - result(webView?.canGoForward ?? false) - break - case .goBackOrForward: - let steps = arguments!["steps"] as! Int - webView?.goBackOrForward(steps: steps) - result(true) - break - case .canGoBackOrForward: - let steps = arguments!["steps"] as! Int - result(webView?.canGoBackOrForward(steps: steps) ?? false) - break - case .stopLoading: - webView?.stopLoading() - result(true) - break - case .isLoading: - result(webView?.isLoading ?? false) - break - case .takeScreenshot: - if let webView = webView, #available(iOS 11.0, *) { - let screenshotConfiguration = arguments!["screenshotConfiguration"] as? [String: Any?] - webView.takeScreenshot(with: screenshotConfiguration, completionHandler: { (screenshot) -> Void in - result(screenshot) - }) - } - else { - result(nil) - } - break - case .setSettings: - if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController { - let inAppBrowserSettings = InAppBrowserSettings() - let inAppBrowserSettingsMap = arguments!["settings"] as! [String: Any] - let _ = inAppBrowserSettings.parse(settings: inAppBrowserSettingsMap) - iabController.setSettings(newSettings: inAppBrowserSettings, newSettingsMap: inAppBrowserSettingsMap) - } else { - let inAppWebViewSettings = InAppWebViewSettings() - let inAppWebViewSettingsMap = arguments!["settings"] as! [String: Any] - let _ = inAppWebViewSettings.parse(settings: inAppWebViewSettingsMap) - webView?.setSettings(newSettings: inAppWebViewSettings, newSettingsMap: inAppWebViewSettingsMap) - } - result(true) - break - case .getSettings: - if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController { - result(iabController.getSettings()) - } else { - result(webView?.getSettings()) - } - break - case .close: - if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController { - iabController.close { - result(true) - } - } else { - result(FlutterMethodNotImplemented) - } - break - case .show: - if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController { - iabController.show { - result(true) - } - } else { - result(FlutterMethodNotImplemented) - } - break - case .hide: - if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController { - iabController.hide { - result(true) - } - } else { - result(FlutterMethodNotImplemented) - } - break - case .isHidden: - if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController { - result(iabController.isHidden) - } else { - result(FlutterMethodNotImplemented) - } - break - case .getCopyBackForwardList: - result(webView?.getCopyBackForwardList()) - break - case .findAll: - if let webView = webView, let findInteractionController = webView.findInteractionController { - let find = arguments!["find"] as! String - findInteractionController.findAll(find: find, completionHandler: {(value, error) in - if error != nil { - result(FlutterError(code: "WebViewChannelDelegate", message: error?.localizedDescription, details: nil)) - return - } - result(true) - }) - } else { - result(false) - } - break - case .findNext: - if let webView = webView, let findInteractionController = webView.findInteractionController { - let forward = arguments!["forward"] as! Bool - findInteractionController.findNext(forward: forward, completionHandler: {(value, error) in - if error != nil { - result(FlutterError(code: "WebViewChannelDelegate", message: error?.localizedDescription, details: nil)) - return - } - result(true) - }) - } else { - result(false) - } - break - case .clearMatches: - if let webView = webView, let findInteractionController = webView.findInteractionController { - findInteractionController.clearMatches(completionHandler: {(value, error) in - if error != nil { - result(FlutterError(code: "WebViewChannelDelegate", message: error?.localizedDescription, details: nil)) - return - } - result(true) - }) - } else { - result(false) - } - break - case .clearCache: - webView?.clearCache() - result(true) - break - case .scrollTo: - let x = arguments!["x"] as! Int - let y = arguments!["y"] as! Int - let animated = arguments!["animated"] as! Bool - webView?.scrollTo(x: x, y: y, animated: animated) - result(true) - break - case .scrollBy: - let x = arguments!["x"] as! Int - let y = arguments!["y"] as! Int - let animated = arguments!["animated"] as! Bool - webView?.scrollBy(x: x, y: y, animated: animated) - result(true) - break - case .pauseTimers: - webView?.pauseTimers() - result(true) - break - case .resumeTimers: - webView?.resumeTimers() - result(true) - break - case .printCurrentPage: - if let webView = webView { - let settings = PrintJobSettings() - if let settingsMap = arguments!["settings"] as? [String: Any?] { - let _ = settings.parse(settings: settingsMap) - } - result(webView.printCurrentPage(settings: settings)) - } else { - result(nil) - } - break - case .getContentHeight: - result(webView?.getContentHeight()) - break - case .getContentWidth: - result(webView?.getContentWidth()) - break - case .zoomBy: - let zoomFactor = (arguments!["zoomFactor"] as! NSNumber).floatValue - let animated = arguments!["animated"] as! Bool - webView?.zoomBy(zoomFactor: zoomFactor, animated: animated) - result(true) - break - case .reloadFromOrigin: - webView?.reloadFromOrigin() - result(true) - break - case .getOriginalUrl: - result(webView?.getOriginalUrl()?.absoluteString) - break - case .getZoomScale: - result(webView?.getZoomScale()) - break - case .hasOnlySecureContent: - result(webView?.hasOnlySecureContent ?? false) - break - case .getSelectedText: - if let webView = webView { - webView.getSelectedText { (value, error) in - if let err = error { - print(err.localizedDescription) - result("") - return - } - result(value) - } - } - else { - result(nil) - } - break - case .getHitTestResult: - if let webView = webView { - webView.getHitTestResult { (hitTestResult) in - result(hitTestResult.toMap()) - } - } - else { - result(nil) - } - break - case .clearFocus: - result(webView?.clearFocus()) - break - case .requestFocus: - result(webView?.requestFocus()) - break - case .setContextMenu: - if let webView = webView { - let contextMenu = arguments!["contextMenu"] as? [String: Any] - webView.contextMenu = contextMenu - result(true) - } else { - result(false) - } - break - case .requestFocusNodeHref: - if let webView = webView { - webView.requestFocusNodeHref { (value, error) in - if let err = error { - print(err.localizedDescription) - result(nil) - return - } - result(value) - } - } else { - result(nil) - } - break - case .requestImageRef: - if let webView = webView { - webView.requestImageRef { (value, error) in - if let err = error { - print(err.localizedDescription) - result(nil) - return - } - result(value) - } - } else { - result(nil) - } - break - case .getScrollX: - if let webView = webView { - result(Int(webView.scrollView.contentOffset.x)) - } else { - result(nil) - } - break - case .getScrollY: - if let webView = webView { - result(Int(webView.scrollView.contentOffset.y)) - } else { - result(nil) - } - break - case .getCertificate: - result(webView?.getCertificate()?.toMap()) - break - case .addUserScript: - if let webView = webView { - let userScriptMap = arguments!["userScript"] as! [String: Any?] - let userScript = UserScript.fromMap(map: userScriptMap, windowId: webView.windowId)! - webView.configuration.userContentController.addUserOnlyScript(userScript) - webView.configuration.userContentController.sync(scriptMessageHandler: webView) - } - result(true) - break - case .removeUserScript: - let index = arguments!["index"] as! Int - let userScriptMap = arguments!["userScript"] as! [String: Any?] - let userScript = UserScript.fromMap(map: userScriptMap, windowId: webView?.windowId)! - webView?.configuration.userContentController.removeUserOnlyScript(at: index, injectionTime: userScript.injectionTime) - result(true) - break - case .removeUserScriptsByGroupName: - let groupName = arguments!["groupName"] as! String - webView?.configuration.userContentController.removeUserOnlyScripts(with: groupName) - result(true) - break - case .removeAllUserScripts: - webView?.configuration.userContentController.removeAllUserOnlyScripts() - result(true) - break - case .callAsyncJavaScript: - if let webView = webView, #available(iOS 10.3, *) { - if #available(iOS 14.3, *) { // on iOS 14.0, for some reason, it crashes - let functionBody = arguments!["functionBody"] as! String - let functionArguments = arguments!["arguments"] as! [String:Any] - var contentWorld = WKContentWorld.page - if let contentWorldMap = arguments!["contentWorld"] as? [String:Any?] { - contentWorld = WKContentWorld.fromMap(map: contentWorldMap, windowId: webView.windowId)! - } - webView.callAsyncJavaScript(functionBody: functionBody, arguments: functionArguments, contentWorld: contentWorld) { (value) in - result(value) - } - } else { - let functionBody = arguments!["functionBody"] as! String - let functionArguments = arguments!["arguments"] as! [String:Any] - webView.callAsyncJavaScript(functionBody: functionBody, arguments: functionArguments) { (value) in - result(value) - } - } - } - else { - result(nil) - } - break - case .createPdf: - if let webView = webView, #available(iOS 14.0, *) { - let configuration = arguments!["pdfConfiguration"] as? [String: Any?] - webView.createPdf(configuration: configuration, completionHandler: { (pdf) -> Void in - result(pdf) - }) - } - else { - result(nil) - } - break - case .createWebArchiveData: - if let webView = webView, #available(iOS 14.0, *) { - webView.createWebArchiveData(dataCompletionHandler: { (webArchiveData) -> Void in - result(webArchiveData) - }) - } - else { - result(nil) - } - break - case .saveWebArchive: - if let webView = webView, #available(iOS 14.0, *) { - let filePath = arguments!["filePath"] as! String - let autoname = arguments!["autoname"] as! Bool - webView.saveWebArchive(filePath: filePath, autoname: autoname, completionHandler: { (path) -> Void in - result(path) - }) - } - else { - result(nil) - } - break - case .isSecureContext: - if let webView = webView { - webView.isSecureContext(completionHandler: { (isSecureContext) in - result(isSecureContext) - }) - } - else { - result(false) - } - break - case .createWebMessageChannel: - if let webView = webView { - let _ = webView.createWebMessageChannel { (webMessageChannel) in - guard let webMessageChannel = webMessageChannel else { - result(nil) - return - } - result(webMessageChannel.toMap()) - } - } else { - result(nil) - } - break - case .postWebMessage: - if let webView = webView { - let message = WebMessage.fromMap(map: arguments!["message"] as! [String: Any?]) - let targetOrigin = arguments!["targetOrigin"] as! String - - var ports: [WebMessagePort] = [] - if let notConnectedPorts = message.ports { - for notConnectedPort in notConnectedPorts { - if let webMessageChannel = webView.webMessageChannels[notConnectedPort.webMessageChannelId] { - ports.append(webMessageChannel.ports[Int(notConnectedPort.index)]) - } - } - } - message.ports = ports - - do { - try webView.postWebMessage(message: message, targetOrigin: targetOrigin) { (_) in - result(true) - } - } catch let error as NSError { - result(FlutterError(code: "WebViewChannelDelegate", message: error.domain, details: nil)) - } - } else { - result(false) - } - break - case .addWebMessageListener: - if let webView = webView, let plugin = webView.plugin { - let webMessageListenerMap = arguments!["webMessageListener"] as! [String: Any?] - let webMessageListener = WebMessageListener.fromMap(plugin: plugin, map: webMessageListenerMap)! - do { - try webView.addWebMessageListener(webMessageListener: webMessageListener) - result(false) - } catch let error as NSError { - result(FlutterError(code: "WebViewChannelDelegate", message: error.domain, details: nil)) - } - } else { - result(false) - } - break - case .canScrollVertically: - if let webView = webView { - result(webView.canScrollVertically()) - } else { - result(false) - } - break - case .canScrollHorizontally: - if let webView = webView { - result(webView.canScrollHorizontally()) - } else { - result(false) - } - break - case .pauseAllMediaPlayback: - if let webView = webView, #available(iOS 15.0, *) { - webView.pauseAllMediaPlayback(completionHandler: { () -> Void in - result(true) - }) - } else { - result(false) - } - break - case .setAllMediaPlaybackSuspended: - if let webView = webView, #available(iOS 15.0, *) { - let suspended = arguments!["suspended"] as! Bool - webView.setAllMediaPlaybackSuspended(suspended, completionHandler: { () -> Void in - result(true) - }) - } else { - result(false) - } - break - case .closeAllMediaPresentations: - if let webView = self.webView, #available(iOS 14.5, *) { - // closeAllMediaPresentations with completionHandler v15.0 makes the app crash - // with error EXC_BAD_ACCESS, so use closeAllMediaPresentations v14.5 - if #available(iOS 16.0, *) { - webView.closeAllMediaPresentations { - result(true) - } - } else { - webView.closeAllMediaPresentations() - result(true) - } - } else { - result(false) - } - break - case .requestMediaPlaybackState: - if let webView = webView, #available(iOS 15.0, *) { - webView.requestMediaPlaybackState(completionHandler: { (state) -> Void in - result(state.rawValue) - }) - } else { - result(nil) - } - break - case .getMetaThemeColor: - if let webView = webView, #available(iOS 15.0, *) { - result(webView.themeColor?.hexString) - } else { - result(nil) - } - break - case .isInFullscreen: - if let webView = webView { - if #available(iOS 16.0, *) { - result(webView.fullscreenState == .inFullscreen) - } else { - result(webView.inFullscreen) - } - } - else { - result(false) - } - break - case .getCameraCaptureState: - if let webView = webView, #available(iOS 15.0, *) { - result(webView.cameraCaptureState.rawValue) - } else { - result(nil) - } - break - case .setCameraCaptureState: - if let webView = webView, #available(iOS 15.0, *) { - let state = WKMediaCaptureState.init(rawValue: arguments!["state"] as! Int) ?? WKMediaCaptureState.none - webView.setCameraCaptureState(state) { - result(true) - } - } else { - result(false) - } - break - case .getMicrophoneCaptureState: - if let webView = webView, #available(iOS 15.0, *) { - result(webView.microphoneCaptureState.rawValue) - } else { - result(nil) - } - break - case .setMicrophoneCaptureState: - if let webView = webView, #available(iOS 15.0, *) { - let state = WKMediaCaptureState.init(rawValue: arguments!["state"] as! Int) ?? WKMediaCaptureState.none - webView.setMicrophoneCaptureState(state) { - result(true) - } - } else { - result(false) - } - break - case .loadSimulatedRequest: - if let webView = webView, #available(iOS 15.0, *) { - let request = URLRequest.init(fromPluginMap: arguments!["urlRequest"] as! [String:Any?]) - let data = arguments!["data"] as! FlutterStandardTypedData - var response: URLResponse? = nil - if let urlResponse = arguments!["urlResponse"] as? [String:Any?] { - response = URLResponse.init(fromPluginMap: urlResponse) - } - if let response = response { - webView.loadSimulatedRequest(request, response: response, responseData: data.data) - } else { - webView.loadSimulatedRequest(request, responseHTML: String(decoding: data.data, as: UTF8.self)) - } - result(true) - } else { - result(false) - } - break - case .setInputMethodEnabled: - if let webView = webView { - let enabled = arguments!["enabled"] as! Bool - webView.setInputMethodEnabled(enabled: enabled) - } - result(true) - break - case .hideInputMethod: - if let webView = webView { - webView.hideInputMethod() - } - result(true) - break - case .saveState: - if let webView = webView, #available(iOS 15.0, *) { - result(webView.saveState()) - } else { - result(nil) - } - break - case .restoreState: - if let webView = webView, #available(iOS 15.0, *) { - let state = arguments!["state"] as! FlutterStandardTypedData - webView.restoreState(state: state.data) - result(true) - } else { - result(false) - } - break - } - } - - @available(*, deprecated, message: "Use FindInteractionChannelDelegate.onFindResultReceived instead.") - public func onFindResultReceived(activeMatchOrdinal: Int, numberOfMatches: Int, isDoneCounting: Bool) { - let arguments: [String : Any?] = [ - "activeMatchOrdinal": activeMatchOrdinal, - "numberOfMatches": numberOfMatches, - "isDoneCounting": isDoneCounting - ] - channel?.invokeMethod("onFindResultReceived", arguments: arguments) - } - - public func onLongPressHitTestResult(hitTestResult: HitTestResult) { - channel?.invokeMethod("onLongPressHitTestResult", arguments: hitTestResult.toMap()) - } - - public func onScrollChanged(x: Int, y: Int) { - let arguments: [String: Any?] = ["x": x, "y": y] - channel?.invokeMethod("onScrollChanged", arguments: arguments) - } - - public func onContentSizeChanged(oldContentSize: CGSize, newContentSize: CGSize) { - let arguments: [String: Any?] = [ - "oldContentSize": oldContentSize.toMap(), - "newContentSize": newContentSize.toMap() - ] - channel?.invokeMethod("onContentSizeChanged", arguments: arguments) - } - - public func onDownloadStarting(request: DownloadStartRequest) { - channel?.invokeMethod("onDownloadStarting", arguments: request.toMap()) - } - - public func onCreateContextMenu(hitTestResult: HitTestResult) { - channel?.invokeMethod("onCreateContextMenu", arguments: hitTestResult.toMap()) - } - - public func onOverScrolled(x: Int, y: Int, clampedX: Bool, clampedY: Bool) { - let arguments: [String: Any?] = ["x": x, "y": y, "clampedX": clampedX, "clampedY": clampedY] - channel?.invokeMethod("onOverScrolled", arguments: arguments) - } - - public func onContextMenuActionItemClicked(id: Any, title: String) { - let arguments: [String: Any?] = [ - "id": id, - "iosId": id is Int64 ? String(id as! Int64) : id as! String, - "androidId": nil, - "title": title - ] - channel?.invokeMethod("onContextMenuActionItemClicked", arguments: arguments) - } - - public func onHideContextMenu() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onHideContextMenu", arguments: arguments) - } - - public func onEnterFullscreen() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onEnterFullscreen", arguments: arguments) - } - - public func onExitFullscreen() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onExitFullscreen", arguments: arguments) - } - - public class JsAlertCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return JsAlertResponse.fromMap(map: obj as? [String:Any?]) - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func onJsAlert(url: URL?, message: String, isMainFrame: Bool, callback: JsAlertCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - let arguments: [String: Any?] = [ - "url": url?.absoluteString, - "message": message, - "isMainFrame": isMainFrame - ] - channel?.invokeMethod("onJsAlert", arguments: arguments, callback: callback) - } - - public class JsConfirmCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return JsConfirmResponse.fromMap(map: obj as? [String:Any?]) - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func onJsConfirm(url: URL?, message: String, isMainFrame: Bool, callback: JsConfirmCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - let arguments: [String: Any?] = [ - "url": url?.absoluteString, - "message": message, - "isMainFrame": isMainFrame - ] - channel?.invokeMethod("onJsConfirm", arguments: arguments, callback: callback) - } - - public class JsPromptCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return JsPromptResponse.fromMap(map: obj as? [String:Any?]) - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func onJsPrompt(url: URL?, message: String, defaultValue: String?, isMainFrame: Bool, callback: JsPromptCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - let arguments: [String: Any?] = [ - "url": url?.absoluteString, - "message": message, - "defaultValue": defaultValue, - "isMainFrame": isMainFrame - ] - channel?.invokeMethod("onJsPrompt", arguments: arguments, callback: callback) - } - - public class CreateWindowCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return obj is Bool && obj as! Bool - } - } - } - - public func onCreateWindow(createWindowAction: CreateWindowAction, callback: CreateWindowCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - channel?.invokeMethod("onCreateWindow", arguments: createWindowAction.toMap(), callback: callback) - } - - public func onCloseWindow() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onCloseWindow", arguments: arguments) - } - - public func onConsoleMessage(message: String, messageLevel: Int) { - let arguments: [String: Any?] = [ - "message": message, - "messageLevel": messageLevel - ] - channel?.invokeMethod("onConsoleMessage", arguments: arguments) - } - - public func onProgressChanged(progress: Int) { - let arguments: [String: Any?] = [ - "progress": progress - ] - channel?.invokeMethod("onProgressChanged", arguments: arguments) - } - - public func onTitleChanged(title: String?) { - let arguments: [String: Any?] = [ - "title": title - ] - channel?.invokeMethod("onTitleChanged", arguments: arguments) - } - - public class PermissionRequestCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return PermissionResponse.fromMap(map: obj as? [String:Any?]) - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func onPermissionRequest(request: PermissionRequest, callback: PermissionRequestCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - channel?.invokeMethod("onPermissionRequest", arguments: request.toMap(), callback: callback) - } - - public class ShouldOverrideUrlLoadingCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - if let action = obj as? Int { - return WKNavigationActionPolicy.init(rawValue: action) ?? WKNavigationActionPolicy.cancel - } - return WKNavigationActionPolicy.cancel - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func shouldOverrideUrlLoading(navigationAction: WKNavigationAction, callback: ShouldOverrideUrlLoadingCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - channel?.invokeMethod("shouldOverrideUrlLoading", arguments: navigationAction.toMap(), callback: callback) - } - - public func onLoadStart(url: String?) { - let arguments: [String: Any?] = ["url": url] - channel?.invokeMethod("onLoadStart", arguments: arguments) - } - - public func onLoadStop(url: String?) { - let arguments: [String: Any?] = ["url": url] - channel?.invokeMethod("onLoadStop", arguments: arguments) - } - - public func onUpdateVisitedHistory(url: String?, isReload: Bool?) { - let arguments: [String: Any?] = [ - "url": url, - "isReload": nil - ] - channel?.invokeMethod("onUpdateVisitedHistory", arguments: arguments) - } - - public func onReceivedError(request: WebResourceRequest, error: WebResourceError) { - let arguments: [String: Any?] = [ - "request": request.toMap(), - "error": error.toMap() - ] - channel?.invokeMethod("onReceivedError", arguments: arguments) - } - - public func onReceivedHttpError(request: WebResourceRequest, errorResponse: WebResourceResponse) { - let arguments: [String: Any?] = [ - "request": request.toMap(), - "errorResponse": errorResponse.toMap() - ] - channel?.invokeMethod("onReceivedHttpError", arguments: arguments) - } - - public class ReceivedHttpAuthRequestCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return HttpAuthResponse.fromMap(map: obj as? [String:Any?]) - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func onReceivedHttpAuthRequest(challenge: HttpAuthenticationChallenge, callback: ReceivedHttpAuthRequestCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - // workaround for ProtectionSpace.toMap() SSL Certificate - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global().async { - let arguments = challenge.toMap() - DispatchQueue.main.async { [weak self] in - if self?.channel == nil { - callback.defaultBehaviour(nil) - return - } - self?.channel?.invokeMethod("onReceivedHttpAuthRequest", arguments: arguments, callback: callback) - } - } - } - - public class ReceivedServerTrustAuthRequestCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return ServerTrustAuthResponse.fromMap(map: obj as? [String:Any?]) - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func onReceivedServerTrustAuthRequest(challenge: ServerTrustChallenge, callback: ReceivedServerTrustAuthRequestCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - // workaround for ProtectionSpace.toMap() SSL Certificate - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global().async { - let arguments = challenge.toMap() - DispatchQueue.main.async { [weak self] in - if self?.channel == nil { - callback.defaultBehaviour(nil) - return - } - self?.channel?.invokeMethod("onReceivedServerTrustAuthRequest", arguments: arguments, callback: callback) - } - } - } - - public class ReceivedClientCertRequestCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return ClientCertResponse.fromMap(map: obj as? [String:Any?]) - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func onReceivedClientCertRequest(challenge: ClientCertChallenge, callback: ReceivedClientCertRequestCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - // workaround for ProtectionSpace.toMap() SSL Certificate - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global().async { - let arguments = challenge.toMap() - DispatchQueue.main.async { [weak self] in - if self?.channel == nil { - callback.defaultBehaviour(nil) - return - } - self?.channel?.invokeMethod("onReceivedClientCertRequest", arguments: arguments, callback: callback) - } - } - } - - public func onZoomScaleChanged(newScale: Float, oldScale: Float) { - let arguments: [String: Any?] = [ - "newScale": newScale, - "oldScale": oldScale - ] - channel?.invokeMethod("onZoomScaleChanged", arguments: arguments) - } - - public func onPageCommitVisible(url: String?) { - let arguments: [String: Any?] = [ - "url": url - ] - channel?.invokeMethod("onPageCommitVisible", arguments: arguments) - } - - public class LoadResourceWithCustomSchemeCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return CustomSchemeResponse.fromMap(map: obj as? [String:Any?]) - } - } - } - - public func onLoadResourceWithCustomScheme(request: WebResourceRequest, callback: LoadResourceWithCustomSchemeCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - let arguments: [String: Any?] = ["request": request.toMap()] - channel?.invokeMethod("onLoadResourceWithCustomScheme", arguments: arguments, callback: callback) - } - - public class CallJsHandlerCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return obj - } - } - } - - public func onCallJsHandler(handlerName: String, data: JavaScriptHandlerFunctionData, callback: CallJsHandlerCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - let arguments: [String: Any?] = [ - "handlerName": handlerName, - "data": data.toMap() - ] - channel?.invokeMethod("onCallJsHandler", arguments: arguments, callback: callback) - } - - public class NavigationResponseCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - if let action = obj as? Int { - return WKNavigationResponsePolicy.init(rawValue: action) ?? WKNavigationResponsePolicy.cancel - } - return WKNavigationResponsePolicy.cancel - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func onNavigationResponse(navigationResponse: WKNavigationResponse, callback: NavigationResponseCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - channel?.invokeMethod("onNavigationResponse", arguments: navigationResponse.toMap(), callback: callback) - } - - public class ShouldAllowDeprecatedTLSCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - if let action = obj as? Int { - return action == 1 - } - return false - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func shouldAllowDeprecatedTLS(challenge: URLAuthenticationChallenge, callback: ShouldAllowDeprecatedTLSCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - // workaround for ProtectionSpace.toMap() SSL Certificate - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global().async { - let arguments = challenge.toMap() - DispatchQueue.main.async { [weak self] in - if self?.channel == nil { - callback.defaultBehaviour(nil) - return - } - self?.channel?.invokeMethod("shouldAllowDeprecatedTLS", arguments: arguments, callback: callback) - } - } - } - - public func onWebContentProcessDidTerminate() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onWebContentProcessDidTerminate", arguments: arguments) - } - - public func onDidReceiveServerRedirectForProvisionalNavigation() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onDidReceiveServerRedirectForProvisionalNavigation", arguments: arguments) - } - - @available(iOS 15.0, *) - public func onCameraCaptureStateChanged(oldState: WKMediaCaptureState?, newState: WKMediaCaptureState?) { - let arguments = [ - "oldState": oldState?.rawValue, - "newState": newState?.rawValue - ] - channel?.invokeMethod("onCameraCaptureStateChanged", arguments: arguments) - } - - @available(iOS 15.0, *) - public func onMicrophoneCaptureStateChanged(oldState: WKMediaCaptureState?, newState: WKMediaCaptureState?) { - let arguments = [ - "oldState": oldState?.rawValue, - "newState": newState?.rawValue - ] - channel?.invokeMethod("onMicrophoneCaptureStateChanged", arguments: arguments) - } - - public class PrintRequestCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return obj is Bool && obj as! Bool - } - } - } - - public func onPrintRequest(url: URL?, printJobId: String?, callback: PrintRequestCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - let arguments = [ - "url": url?.absoluteString, - "printJobId": printJobId, - ] - channel?.invokeMethod("onPrintRequest", arguments: arguments, callback: callback) - } - - public override func dispose() { - super.dispose() - webView = nil - } - - deinit { - debugPrint("WebViewChannelDelegate - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebViewChannelDelegateMethods.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebViewChannelDelegateMethods.swift deleted file mode 100644 index 5f01e22739..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebView/WebViewChannelDelegateMethods.swift +++ /dev/null @@ -1,98 +0,0 @@ -// -// WebViewChannelDelegateMethods.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 08/10/22. -// - -import Foundation - -public enum WebViewChannelDelegateMethods: String { - case getUrl = "getUrl" - case getTitle = "getTitle" - case getProgress = "getProgress" - case loadUrl = "loadUrl" - case postUrl = "postUrl" - case loadData = "loadData" - case loadFile = "loadFile" - case evaluateJavascript = "evaluateJavascript" - case injectJavascriptFileFromUrl = "injectJavascriptFileFromUrl" - case injectCSSCode = "injectCSSCode" - case injectCSSFileFromUrl = "injectCSSFileFromUrl" - case reload = "reload" - case goBack = "goBack" - case canGoBack = "canGoBack" - case goForward = "goForward" - case canGoForward = "canGoForward" - case goBackOrForward = "goBackOrForward" - case canGoBackOrForward = "canGoBackOrForward" - case stopLoading = "stopLoading" - case isLoading = "isLoading" - case takeScreenshot = "takeScreenshot" - case setSettings = "setSettings" - case getSettings = "getSettings" - case close = "close" - case show = "show" - case hide = "hide" - case isHidden = "isHidden" - case getCopyBackForwardList = "getCopyBackForwardList" - @available(*, deprecated, message: "Use FindInteractionController.findAll instead.") - case findAll = "findAll" - @available(*, deprecated, message: "Use FindInteractionController.findNext instead.") - case findNext = "findNext" - @available(*, deprecated, message: "Use FindInteractionController.clearMatches instead.") - case clearMatches = "clearMatches" - @available(*, deprecated, message: "Use InAppWebViewManager.clearAllCache instead.") - case clearCache = "clearCache" - case scrollTo = "scrollTo" - case scrollBy = "scrollBy" - case pauseTimers = "pauseTimers" - case resumeTimers = "resumeTimers" - case printCurrentPage = "printCurrentPage" - case getContentHeight = "getContentHeight" - case getContentWidth = "getContentWidth" - case zoomBy = "zoomBy" - case reloadFromOrigin = "reloadFromOrigin" - case getOriginalUrl = "getOriginalUrl" - case getZoomScale = "getZoomScale" - case hasOnlySecureContent = "hasOnlySecureContent" - case getSelectedText = "getSelectedText" - case getHitTestResult = "getHitTestResult" - case clearFocus = "clearFocus" - case requestFocus = "requestFocus" - case setContextMenu = "setContextMenu" - case requestFocusNodeHref = "requestFocusNodeHref" - case requestImageRef = "requestImageRef" - case getScrollX = "getScrollX" - case getScrollY = "getScrollY" - case getCertificate = "getCertificate" - case addUserScript = "addUserScript" - case removeUserScript = "removeUserScript" - case removeUserScriptsByGroupName = "removeUserScriptsByGroupName" - case removeAllUserScripts = "removeAllUserScripts" - case callAsyncJavaScript = "callAsyncJavaScript" - case createPdf = "createPdf" - case createWebArchiveData = "createWebArchiveData" - case saveWebArchive = "saveWebArchive" - case isSecureContext = "isSecureContext" - case createWebMessageChannel = "createWebMessageChannel" - case postWebMessage = "postWebMessage" - case addWebMessageListener = "addWebMessageListener" - case canScrollVertically = "canScrollVertically" - case canScrollHorizontally = "canScrollHorizontally" - case pauseAllMediaPlayback = "pauseAllMediaPlayback" - case setAllMediaPlaybackSuspended = "setAllMediaPlaybackSuspended" - case closeAllMediaPresentations = "closeAllMediaPresentations" - case requestMediaPlaybackState = "requestMediaPlaybackState" - case getMetaThemeColor = "getMetaThemeColor" - case isInFullscreen = "isInFullscreen" - case getCameraCaptureState = "getCameraCaptureState" - case setCameraCaptureState = "setCameraCaptureState" - case getMicrophoneCaptureState = "getMicrophoneCaptureState" - case setMicrophoneCaptureState = "setMicrophoneCaptureState" - case loadSimulatedRequest = "loadSimulatedRequest" - case setInputMethodEnabled = "setInputMethodEnabled" - case hideInputMethod = "hideInputMethod" - case saveState = "saveState" - case restoreState = "restoreState" -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebViewFlutterPlugin.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebViewFlutterPlugin.swift deleted file mode 100755 index 151a7c9d20..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/InAppWebViewFlutterPlugin.swift +++ /dev/null @@ -1,103 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -import Flutter -import UIKit -import WebKit -import Foundation -import AVFoundation -import SafariServices - -public class InAppWebViewFlutterPlugin: NSObject, FlutterPlugin { - - var registrar: FlutterPluginRegistrar - var platformUtil: PlatformUtil? - var inAppWebViewManager: InAppWebViewManager? - var myCookieManager: Any? - var myWebStorageManager: Any? - var credentialDatabase: CredentialDatabase? - var inAppBrowserManager: InAppBrowserManager? - var headlessInAppWebViewManager: HeadlessInAppWebViewManager? - var chromeSafariBrowserManager: ChromeSafariBrowserManager? - var webAuthenticationSessionManager: WebAuthenticationSessionManager? - var printJobManager: PrintJobManager? - var proxyManager: Any? - - var webViewControllers: [String: InAppBrowserWebViewController?] = [:] - var safariViewControllers: [String: Any?] = [:] - - public init(with registrar: FlutterPluginRegistrar) { - self.registrar = registrar - - super.init() - - registrar.register(FlutterWebViewFactory(plugin: self) as FlutterPlatformViewFactory, withId: FlutterWebViewFactory.VIEW_TYPE_ID) - - platformUtil = PlatformUtil(plugin: self) - inAppBrowserManager = InAppBrowserManager(plugin: self) - headlessInAppWebViewManager = HeadlessInAppWebViewManager(plugin: self) - chromeSafariBrowserManager = ChromeSafariBrowserManager(plugin: self) - inAppWebViewManager = InAppWebViewManager(plugin: self) - credentialDatabase = CredentialDatabase(plugin: self) - if #available(iOS 11.0, *) { - myCookieManager = MyCookieManager(plugin: self) - } - if #available(iOS 9.0, *) { - myWebStorageManager = MyWebStorageManager(plugin: self) - } - webAuthenticationSessionManager = WebAuthenticationSessionManager(plugin: self) - printJobManager = PrintJobManager(plugin: self) - if #available(iOS 17.0, *) { - proxyManager = ProxyManager(plugin: self) - } - } - - public static func register(with registrar: FlutterPluginRegistrar) { - let _ = InAppWebViewFlutterPlugin(with: registrar) - } - - public func detachFromEngine(for registrar: FlutterPluginRegistrar) { - platformUtil?.dispose() - platformUtil = nil - inAppBrowserManager?.dispose() - inAppBrowserManager = nil - headlessInAppWebViewManager?.dispose() - headlessInAppWebViewManager = nil - chromeSafariBrowserManager?.dispose() - chromeSafariBrowserManager = nil - inAppWebViewManager?.dispose() - inAppWebViewManager = nil - credentialDatabase?.dispose() - credentialDatabase = nil - if #available(iOS 11.0, *) { - (myCookieManager as? MyCookieManager)?.dispose() - myCookieManager = nil - } - if #available(iOS 9.0, *) { - (myWebStorageManager as? MyWebStorageManager)?.dispose() - myWebStorageManager = nil - } - webAuthenticationSessionManager?.dispose() - webAuthenticationSessionManager = nil - printJobManager?.dispose() - printJobManager = nil - if #available(iOS 17.0, *) { - (proxyManager as? ProxyManager)?.dispose() - proxyManager = nil - } - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/LeakAvoider.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/LeakAvoider.swift deleted file mode 100755 index edad1f2650..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/LeakAvoider.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// LeakAvoider.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 15/12/2019. -// - -import Foundation -import Flutter - -public class LeakAvoider: NSObject { - weak var delegate : FlutterMethodCallDelegate? - - init(delegate: FlutterMethodCallDelegate) { - super.init() - self.delegate = delegate - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - self.delegate?.handle(call, result: result) - } - - deinit { - debugPrint("LeakAvoider - dealloc") - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/MyCookieManager.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/MyCookieManager.swift deleted file mode 100755 index 6309bab2e3..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/MyCookieManager.swift +++ /dev/null @@ -1,300 +0,0 @@ -// -// MyCookieManager.swift -// flutter_inappwebview -// -// Created by Lorenzo on 26/10/18. -// - -import Foundation -import WebKit -import Flutter - -@available(iOS 11.0, *) -public class MyCookieManager: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_cookiemanager" - static let httpCookieStore = WKWebsiteDataStore.default().httpCookieStore - - private var plugin: InAppWebViewFlutterPlugin? - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: MyCookieManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger())) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - switch call.method { - case "setCookie": - let url = arguments!["url"] as! String - let name = arguments!["name"] as! String - let value = arguments!["value"] as! String - let path = arguments!["path"] as! String - - var expiresDate: Int64? - if let expiresDateString = arguments!["expiresDate"] as? String { - expiresDate = Int64(expiresDateString) - } - - let maxAge = arguments!["maxAge"] as? Int64 - let isSecure = arguments!["isSecure"] as? Bool - let isHttpOnly = arguments!["isHttpOnly"] as? Bool - let sameSite = arguments!["sameSite"] as? String - let domain = arguments!["domain"] as? String - - MyCookieManager.setCookie(url: url, - name: name, - value: value, - path: path, - domain: domain, - expiresDate: expiresDate, - maxAge: maxAge, - isSecure: isSecure, - isHttpOnly: isHttpOnly, - sameSite: sameSite, - result: result) - break - case "getCookies": - let url = arguments!["url"] as! String - MyCookieManager.getCookies(url: url, result: result) - break - case "getAllCookies": - MyCookieManager.getAllCookies(result: result) - break - case "deleteCookie": - let url = arguments!["url"] as! String - let name = arguments!["name"] as! String - let path = arguments!["path"] as! String - let domain = arguments!["domain"] as? String - MyCookieManager.deleteCookie(url: url, name: name, path: path, domain: domain, result: result) - break - case "deleteCookies": - let url = arguments!["url"] as! String - let path = arguments!["path"] as! String - let domain = arguments!["domain"] as? String - MyCookieManager.deleteCookies(url: url, path: path, domain: domain, result: result) - break - case "deleteAllCookies": - MyCookieManager.deleteAllCookies(result: result) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public static func setCookie(url: String, - name: String, - value: String, - path: String, - domain: String?, - expiresDate: Int64?, - maxAge: Int64?, - isSecure: Bool?, - isHttpOnly: Bool?, - sameSite: String?, - result: @escaping FlutterResult) { - var properties: [HTTPCookiePropertyKey: Any] = [:] - properties[.originURL] = url - properties[.name] = name - properties[.value] = value - properties[.path] = path - - if domain != nil { - properties[.domain] = domain - } - - if expiresDate != nil { - // convert from milliseconds - properties[.expires] = Date(timeIntervalSince1970: TimeInterval(Double(expiresDate!)/1000)) - } - if maxAge != nil { - properties[.maximumAge] = String(maxAge!) - } - if isSecure != nil && isSecure! { - properties[.secure] = "TRUE" - } - if isHttpOnly != nil && isHttpOnly! { - properties[.init("HttpOnly")] = "YES" - } - if sameSite != nil { - if #available(iOS 13.0, *) { - var sameSiteValue = HTTPCookieStringPolicy(rawValue: "None") - switch sameSite { - case "Lax": - sameSiteValue = HTTPCookieStringPolicy.sameSiteLax - case "Strict": - sameSiteValue = HTTPCookieStringPolicy.sameSiteStrict - default: - break - } - properties[.sameSitePolicy] = sameSiteValue - } else { - properties[.init("SameSite")] = sameSite - } - } - - - if let cookie = HTTPCookie(properties: properties) { - MyCookieManager.httpCookieStore.setCookie(cookie, completionHandler: {() in - result(true) - }) - } else { - result(false) - } - } - - public static func getCookies(url: String, result: @escaping FlutterResult) { - var cookieList: [[String: Any?]] = [] - - if let urlHost = URL(string: url)?.host { - MyCookieManager.httpCookieStore.getAllCookies { (cookies) in - for cookie in cookies { - if urlHost.hasSuffix(cookie.domain) || ".\(urlHost)".hasSuffix(cookie.domain) { - var sameSite: String? = nil - if #available(iOS 13.0, *) { - if let sameSiteValue = cookie.sameSitePolicy?.rawValue { - sameSite = sameSiteValue.prefix(1).capitalized + sameSiteValue.dropFirst() - } - } - - var expiresDateTimestamp: Int64 = -1 - if let expiresDate = cookie.expiresDate?.timeIntervalSince1970 { - // convert to milliseconds - expiresDateTimestamp = Int64(expiresDate * 1000) - } - - cookieList.append([ - "name": cookie.name, - "value": cookie.value, - "expiresDate": expiresDateTimestamp != -1 ? expiresDateTimestamp : nil, - "isSessionOnly": cookie.isSessionOnly, - "domain": cookie.domain, - "sameSite": sameSite, - "isSecure": cookie.isSecure, - "isHttpOnly": cookie.isHTTPOnly, - "path": cookie.path, - ]) - } - } - result(cookieList) - } - return - } else { - print("Cannot get WebView cookies. No HOST found for URL: \(url)") - } - - result(cookieList) - } - - public static func getAllCookies(result: @escaping FlutterResult) { - var cookieList: [[String: Any?]] = [] - - MyCookieManager.httpCookieStore.getAllCookies { (cookies) in - for cookie in cookies { - var sameSite: String? = nil - if #available(iOS 13.0, *) { - if let sameSiteValue = cookie.sameSitePolicy?.rawValue { - sameSite = sameSiteValue.prefix(1).capitalized + sameSiteValue.dropFirst() - } - } - - var expiresDateTimestamp: Int64 = -1 - if let expiresDate = cookie.expiresDate?.timeIntervalSince1970 { - // convert to milliseconds - expiresDateTimestamp = Int64(expiresDate * 1000) - } - - cookieList.append([ - "name": cookie.name, - "value": cookie.value, - "expiresDate": expiresDateTimestamp != -1 ? expiresDateTimestamp : nil, - "isSessionOnly": cookie.isSessionOnly, - "domain": cookie.domain, - "sameSite": sameSite, - "isSecure": cookie.isSecure, - "isHttpOnly": cookie.isHTTPOnly, - "path": cookie.path, - ]) - } - result(cookieList) - } - } - - public static func deleteCookie(url: String, name: String, path: String, domain: String?, result: @escaping FlutterResult) { - var domain = domain - MyCookieManager.httpCookieStore.getAllCookies { (cookies) in - for cookie in cookies { - var originURL = url - if cookie.properties![.originURL] is String { - originURL = cookie.properties![.originURL] as! String - } - else if cookie.properties![.originURL] is URL { - originURL = (cookie.properties![.originURL] as! URL).absoluteString - } - if domain == nil, let domainUrl = URL(string: originURL) { - if #available(iOS 16.0, *) { - domain = domainUrl.host() - } else { - domain = domainUrl.host - } - } - if let domain = domain, cookie.domain == domain, cookie.name == name, cookie.path == path { - MyCookieManager.httpCookieStore.delete(cookie, completionHandler: { - result(true) - }) - return - } - } - result(false) - } - } - - public static func deleteCookies(url: String, path: String, domain: String?, result: @escaping FlutterResult) { - var domain = domain - let dispatchGroup = DispatchGroup() - MyCookieManager.httpCookieStore.getAllCookies { (cookies) in - for cookie in cookies { - var originURL = url - if cookie.properties![.originURL] is String { - originURL = cookie.properties![.originURL] as! String - } - else if cookie.properties![.originURL] is URL { - originURL = (cookie.properties![.originURL] as! URL).absoluteString - } - if domain == nil, let domainUrl = URL(string: originURL) { - if #available(iOS 16.0, *) { - domain = domainUrl.host() - } else { - domain = domainUrl.host - } - } - if let domain = domain, cookie.domain == domain, cookie.path == path { - dispatchGroup.enter() - MyCookieManager.httpCookieStore.delete(cookie) { - dispatchGroup.leave() - } - } - } - dispatchGroup.notify(queue: .main) { - result(true) - } - } - } - - public static func deleteAllCookies(result: @escaping FlutterResult) { - let websiteDataTypes = NSSet(array: [WKWebsiteDataTypeCookies]) - let date = NSDate(timeIntervalSince1970: 0) - WKWebsiteDataStore.default().removeData(ofTypes: websiteDataTypes as! Set, modifiedSince: date as Date, completionHandler:{ - result(true) - }) - } - - public override func dispose() { - super.dispose() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/MyWebStorageManager.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/MyWebStorageManager.swift deleted file mode 100755 index 51a376b97a..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/MyWebStorageManager.swift +++ /dev/null @@ -1,97 +0,0 @@ -// -// MyWebStorageManager.swift -// connectivity -// -// Created by Lorenzo Pichilli on 16/12/2019. -// - -import Foundation -import WebKit -import Flutter - -@available(iOS 9.0, *) -public class MyWebStorageManager: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webstoragemanager" - static let websiteDataStore = WKWebsiteDataStore.default() - - private var plugin: InAppWebViewFlutterPlugin? - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: MyWebStorageManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger())) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - switch call.method { - case "fetchDataRecords": - let dataTypes = Set(arguments!["dataTypes"] as! [String]) - MyWebStorageManager.fetchDataRecords(dataTypes: dataTypes, result: result) - break - case "removeDataFor": - let dataTypes = Set(arguments!["dataTypes"] as! [String]) - let recordList = arguments!["recordList"] as! [[String: Any?]] - MyWebStorageManager.removeDataFor(dataTypes: dataTypes, recordList: recordList, result: result) - break - case "removeDataModifiedSince": - let dataTypes = Set(arguments!["dataTypes"] as! [String]) - let timestamp = arguments!["timestamp"] as! Int64 - MyWebStorageManager.removeDataModifiedSince(dataTypes: dataTypes, timestamp: timestamp, result: result) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public static func fetchDataRecords(dataTypes: Set, result: @escaping FlutterResult) { - var recordList: [[String: Any?]] = [] - - MyWebStorageManager.websiteDataStore.fetchDataRecords(ofTypes: dataTypes) { (data) in - for record in data { - recordList.append([ - "displayName": record.displayName, - "dataTypes": record.dataTypes.map({ (dataType) -> String in - return dataType - }) - ]) - } - result(recordList) - } - } - - public static func removeDataFor(dataTypes: Set, recordList: [[String: Any?]], result: @escaping FlutterResult) { - var records: [WKWebsiteDataRecord] = [] - - MyWebStorageManager.websiteDataStore.fetchDataRecords(ofTypes: dataTypes) { (data) in - for record in data { - for r in recordList { - let displayName = r["displayName"] as! String - if (record.displayName == displayName) { - records.append(record) - break - } - } - } - MyWebStorageManager.websiteDataStore.removeData(ofTypes: dataTypes, for: records) { - result(true) - } - } - } - - public static func removeDataModifiedSince(dataTypes: Set, timestamp: Int64, result: @escaping FlutterResult) { - let date = NSDate(timeIntervalSince1970: TimeInterval(timestamp)) - MyWebStorageManager.websiteDataStore.removeData(ofTypes: dataTypes, modifiedSince: date as Date) { - result(true) - } - } - - public override func dispose() { - super.dispose() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PlatformUtil.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PlatformUtil.swift deleted file mode 100644 index 0d73cd231a..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PlatformUtil.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// PlatformUtil.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 01/03/21. -// - -import Foundation -import UIKit -import Flutter - -public class PlatformUtil: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_platformutil" - var plugin: InAppWebViewFlutterPlugin? - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: PlatformUtil.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger())) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "getSystemVersion": - let device = UIDevice.current - result(device.systemVersion) - break - case "formatDate": - let date = arguments!["date"] as! Int64 - let format = arguments!["format"] as! String - let locale = PlatformUtil.getLocaleFromString(locale: arguments!["locale"] as? String) - let timezone = TimeZone.init(abbreviation: arguments!["timezone"] as? String ?? "UTC")! - result(PlatformUtil.formatDate(date: date, format: format, locale: locale, timezone: timezone)) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - static public func getLocaleFromString(locale: String?) -> Locale { - guard let locale = locale else { - return Locale.init(identifier: "en_US") - } - return Locale.init(identifier: locale) - } - - static public func getDateFromMilliseconds(date: Int64) -> Date { - return Date(timeIntervalSince1970: TimeInterval(Double(date)/1000)) - } - - static public func formatDate(date: Int64, format: String, locale: Locale, timezone: TimeZone) -> String { - let formatter = DateFormatter() - formatter.locale = locale - formatter.dateFormat = format - formatter.timeZone = timezone - return formatter.string(from: PlatformUtil.getDateFromMilliseconds(date: date)) - } - - public override func dispose() { - super.dispose() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/CallAsyncJavaScriptBelowIOS14WrapperJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/CallAsyncJavaScriptBelowIOS14WrapperJS.swift deleted file mode 100644 index f1f83db006..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/CallAsyncJavaScriptBelowIOS14WrapperJS.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// CallAsyncJavaScriptBelowIOS14WrapperJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class CallAsyncJavaScriptBelowIOS14WrapperJS { - - public static func CALL_ASYNC_JAVASCRIPT_BELOW_IOS_14_WRAPPER_JS() -> String { - return """ - (function(obj) { - (async function(\(PluginScriptsUtil.VAR_FUNCTION_ARGUMENT_NAMES) { - \(PluginScriptsUtil.VAR_FUNCTION_BODY) - })(\(PluginScriptsUtil.VAR_FUNCTION_ARGUMENT_VALUES)).then(function(value) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onCallAsyncJavaScriptResultBelowIOS14Received', { - 'value': value, - 'error': null, - 'resultUuid': '\(PluginScriptsUtil.VAR_RESULT_UUID)' - }); - }).catch(function(error) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onCallAsyncJavaScriptResultBelowIOS14Received', { - 'value': null, - 'error': error + '', - 'resultUuid': '\(PluginScriptsUtil.VAR_RESULT_UUID)' - }); - }); - return null; - })(\(PluginScriptsUtil.VAR_FUNCTION_ARGUMENTS_OBJ)); - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/ConsoleLogJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/ConsoleLogJS.swift deleted file mode 100644 index 5636ea62c8..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/ConsoleLogJS.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// ConsoleLogJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class ConsoleLogJS { - - public static let CONSOLE_LOG_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_CONSOLE_LOG_JS_PLUGIN_SCRIPT" - - // This plugin is only for main frame. - // Using it also on non-main frames could cause issues - // such as https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738 - public static func CONSOLE_LOG_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: CONSOLE_LOG_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: CONSOLE_LOG_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: true, - messageHandlerNames: []) - } - - // the message needs to be concatenated with '' in order to have the same behavior like on Android - public static func CONSOLE_LOG_JS_SOURCE() -> String { - return """ - (function(console) { - - function _callHandler(logLevel, args) { - var message = ''; - for (var i in args) { - try { - message += message === '' ? args[i] : ' ' + args[i]; - } catch(_) {} - } - try { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onConsoleMessage', {'level': logLevel, 'message': message}) - } catch(_) {} - } - - var oldLogs = { - 'consoleLog': console.log, - 'consoleDebug': console.debug, - 'consoleError': console.error, - 'consoleInfo': console.info, - 'consoleWarn': console.warn - }; - - for (var k in oldLogs) { - (function(oldLog) { - var logLevel = oldLog.replace('console', '').toLowerCase(); - console[logLevel] = function() { - oldLogs[oldLog].apply(null, arguments); - _callHandler(logLevel, arguments); - } - })(k); - } - })(window.console); - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/EnableViewportScaleJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/EnableViewportScaleJS.swift deleted file mode 100644 index efa07583a4..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/EnableViewportScaleJS.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// EnableViewportScaleJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class EnableViewportScaleJS { - - public static let ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT" - - // This plugin is only for main frame - public static func ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: ENABLE_VIEWPORT_SCALE_JS_SOURCE, - injectionTime: .atDocumentEnd, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static let ENABLE_VIEWPORT_SCALE_JS_SOURCE = """ - (function() { - var meta = document.createElement('meta'); - meta.setAttribute('name', 'viewport'); - meta.setAttribute('content', 'width=device-width'); - document.getElementsByTagName('head')[0].appendChild(meta); - })() - """ - - public static func NOT_ENABLE_VIEWPORT_SCALE_JS_SOURCE() -> String { - return """ - (function() { - var meta = document.createElement('meta'); - meta.setAttribute('name', 'viewport'); - meta.setAttribute('content', window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._originalViewPortMetaTagContent); - document.getElementsByTagName('head')[0].appendChild(meta); - })() - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/FindElementsAtPointJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/FindElementsAtPointJS.swift deleted file mode 100644 index 26220f8a59..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/FindElementsAtPointJS.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// FindElementsAtPointJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class FindElementsAtPointJS { - public static let FIND_ELEMENTS_AT_POINT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_FIND_ELEMENTS_AT_POINT_JS_PLUGIN_SCRIPT" - - // This plugin is only for main frame - public static func FIND_ELEMENTS_AT_POINT_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: FIND_ELEMENTS_AT_POINT_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: FIND_ELEMENTS_AT_POINT_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - /** - https://developer.android.com/reference/android/webkit/WebView.HitTestResult - */ - public static func FIND_ELEMENTS_AT_POINT_JS_SOURCE() -> String { - return """ - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findElementsAtPoint = function(x, y) { - var hitTestResultType = { - UNKNOWN_TYPE: 0, - PHONE_TYPE: 2, - GEO_TYPE: 3, - EMAIL_TYPE: 4, - IMAGE_TYPE: 5, - SRC_ANCHOR_TYPE: 7, - SRC_IMAGE_ANCHOR_TYPE: 8, - EDIT_TEXT_TYPE: 9 - }; - var element = document.elementFromPoint(x, y); - var data = { - type: 0, - extra: null - }; - while (element) { - if (element.tagName === 'IMG' && element.src) { - if (element.parentNode && element.parentNode.tagName === 'A' && element.parentNode.href) { - data.type = hitTestResultType.SRC_IMAGE_ANCHOR_TYPE; - } else { - data.type = hitTestResultType.IMAGE_TYPE; - } - data.extra = element.src; - break; - } else if (element.tagName === 'A' && element.href) { - if (element.href.indexOf('mailto:') === 0) { - data.type = hitTestResultType.EMAIL_TYPE; - data.extra = element.href.replace('mailto:', ''); - } else if (element.href.indexOf('tel:') === 0) { - data.type = hitTestResultType.PHONE_TYPE; - data.extra = element.href.replace('tel:', ''); - } else if (element.href.indexOf('geo:') === 0) { - data.type = hitTestResultType.GEO_TYPE; - data.extra = element.href.replace('geo:', ''); - } else { - data.type = hitTestResultType.SRC_ANCHOR_TYPE; - data.extra = element.href; - } - break; - } else if ( - (element.tagName === 'INPUT' && ['text', 'email', 'password', 'number', 'search', 'tel', 'url'].indexOf(element.type) >= 0) || - element.tagName === 'TEXTAREA') { - data.type = hitTestResultType.EDIT_TEXT_TYPE - } - element = element.parentNode; - } - return data; - } - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/FindTextHighlightJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/FindTextHighlightJS.swift deleted file mode 100644 index 5006f04b76..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/FindTextHighlightJS.swift +++ /dev/null @@ -1,186 +0,0 @@ -// -// FindTextHighlightJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class FindTextHighlightJS { - public static let FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT" - public static func FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._searchResultCount" - } - public static func FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._currentHighlight" - } - public static func FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._isDoneCounting" - } - - // This plugin is only for main frame - public static func FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: FIND_TEXT_HIGHLIGHT_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static func FIND_TEXT_HIGHLIGHT_JS_SOURCE() -> String { - return """ - \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()) = 0; - \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE()) = 0; - \(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE()) = false; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findAllAsyncForElement = function(element, keyword) { - if (element) { - if (element.nodeType == 3) { - // Text node - - var elementTmp = element; - while (true) { - var value = elementTmp.nodeValue; // Search for keyword in text node - var idx = value.toLowerCase().indexOf(keyword); - - if (idx < 0) break; - - var span = document.createElement("span"); - var text = document.createTextNode(value.substr(idx, keyword.length)); - span.appendChild(text); - - span.setAttribute( - "id", - "\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())_SEARCH_WORD_" + \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()) - ); - span.setAttribute("class", "\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())_Highlight"); - var backgroundColor = \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()) == 0 ? "#FF9732" : "#FFFF00"; - span.setAttribute("style", "color: #000 !important; background: " + backgroundColor + " !important; padding: 0px !important; margin: 0px !important; border: 0px !important;"); - - text = document.createTextNode(value.substr(idx + keyword.length)); - element.deleteData(idx, value.length - idx); - - var next = element.nextSibling; - element.parentNode.insertBefore(span, next); - element.parentNode.insertBefore(text, next); - element = text; - - \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE())++; - elementTmp = document.createTextNode( - value.substr(idx + keyword.length) - ); - - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onFindResultReceived', { - 'findResult': { - 'activeMatchOrdinal': \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE()), - 'numberOfMatches': \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()), - 'isDoneCounting': \(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE()) - } - }); - } - } else if (element.nodeType == 1) { - // Element node - if ( - element.style.display != "none" && - element.nodeName.toLowerCase() != "select" - ) { - for (var i = element.childNodes.length - 1; i >= 0; i--) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findAllAsyncForElement( - element.childNodes[element.childNodes.length - 1 - i], - keyword - ); - } - } - } - } - } - - // the main entry point to start the search - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findAllAsync = function(keyword) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._clearMatches(); - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findAllAsyncForElement(document.body, keyword.toLowerCase()); - \(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE()) = true; - - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onFindResultReceived', { - 'findResult': { - 'activeMatchOrdinal': \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE()), - 'numberOfMatches': \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()), - 'isDoneCounting': \(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE()) - } - }); - } - - // helper function, recursively removes the highlights in elements and their children - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._clearMatchesForElement = function(element) { - if (element) { - if (element.nodeType == 1) { - if (element.getAttribute("class") == "\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())_Highlight") { - var text = element.removeChild(element.firstChild); - element.parentNode.insertBefore(text, element); - element.parentNode.removeChild(element); - return true; - } else { - var normalize = false; - for (var i = element.childNodes.length - 1; i >= 0; i--) { - if (window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._clearMatchesForElement(element.childNodes[i])) { - normalize = true; - } - } - if (normalize) { - element.normalize(); - } - } - } - } - return false; - } - - // the main entry point to remove the highlights - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._clearMatches = function() { - \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()) = 0; - \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE()) = 0; - \(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE()) = false; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._clearMatchesForElement(document.body); - } - - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findNext = function(forward) { - if (\(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()) <= 0) return; - - var idx = \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE()) + (forward ? +1 : -1); - idx = - idx < 0 - ? \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()) - 1 - : idx >= \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()) - ? 0 - : idx; - \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE()) = idx; - - var scrollTo = document.getElementById("\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())_SEARCH_WORD_" + idx); - if (scrollTo) { - var highlights = document.getElementsByClassName("\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())_Highlight"); - for (var i = 0; i < highlights.length; i++) { - var span = highlights[i]; - span.style.backgroundColor = "#FFFF00"; - } - scrollTo.style.backgroundColor = "#FF9732"; - - scrollTo.scrollIntoView({ - behavior: "auto", - block: "center" - }); - - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onFindResultReceived', { - 'findResult': { - 'activeMatchOrdinal': \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE()), - 'numberOfMatches': \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()), - 'isDoneCounting': \(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE()) - } - }); - } - } - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/InterceptAjaxRequestJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/InterceptAjaxRequestJS.swift deleted file mode 100644 index e8ca40c76d..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/InterceptAjaxRequestJS.swift +++ /dev/null @@ -1,294 +0,0 @@ -// -// InterceptAjaxRequestsJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class InterceptAjaxRequestJS { - - public static let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT" - - public static func FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._useShouldInterceptAjaxRequest" - } - - public static func FLAG_VARIABLE_FOR_ON_AJAX_READY_STATE_CHANGE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._useOnAjaxReadyStateChange" - } - - public static func FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._useOnAjaxProgress" - } - - public static func FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._interceptOnlyAsyncAjaxRequests" - } - - public static func INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?, forMainFrameOnly: Bool, initialUseOnAjaxReadyStateChange: Bool = false, initialUseOnAjaxProgress: Bool = false) -> PluginScript { - return PluginScript( - groupName: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: INTERCEPT_AJAX_REQUEST_JS_SOURCE(initialUseOnAjaxReadyStateChange: initialUseOnAjaxReadyStateChange, initialUseOnAjaxProgress: initialUseOnAjaxProgress), - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: true, - messageHandlerNames: []) - } - - public static func createInterceptOnlyAsyncAjaxRequestsPluginScript(onlyAsync: Bool, allowedOriginRules: [String]?, forMainFrameOnly: Bool) -> PluginScript { - return PluginScript(groupName: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: "\(FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE()) = \(onlyAsync);", - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: true, - messageHandlerNames: [] - ); - } - - public static func INTERCEPT_AJAX_REQUEST_JS_SOURCE(initialUseOnAjaxReadyStateChange: Bool, initialUseOnAjaxProgress: Bool) -> String { - return """ - \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) = true; - \(FLAG_VARIABLE_FOR_ON_AJAX_READY_STATE_CHANGE()) = \(initialUseOnAjaxReadyStateChange); - \(FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS()) = \(initialUseOnAjaxProgress); - (function(ajax) { - var send = ajax.prototype.send; - var open = ajax.prototype.open; - var setRequestHeader = ajax.prototype.setRequestHeader; - ajax.prototype._flutter_inappwebview_url = null; - ajax.prototype._flutter_inappwebview_method = null; - ajax.prototype._flutter_inappwebview_isAsync = null; - ajax.prototype._flutter_inappwebview_user = null; - ajax.prototype._flutter_inappwebview_password = null; - ajax.prototype._flutter_inappwebview_password = null; - ajax.prototype._flutter_inappwebview_already_onreadystatechange_wrapped = false; - ajax.prototype._flutter_inappwebview_request_headers = {}; - function convertRequestResponse(request, callback) { - if (request.response != null && request.responseType != null) { - switch (request.responseType) { - case 'arraybuffer': - callback(new Uint8Array(request.response)); - return; - case 'blob': - const reader = new FileReader(); - reader.addEventListener('loadend', function() { - callback(new Uint8Array(reader.result)); - }); - reader.readAsArrayBuffer(blob); - return; - case 'document': - callback(request.response.documentElement.outerHTML); - return; - case 'json': - callback(request.response); - return; - }; - } - callback(null); - }; - ajax.prototype.open = function(method, url, isAsync, user, password) { - isAsync = (isAsync != null) ? isAsync : true; - this._flutter_inappwebview_url = url; - this._flutter_inappwebview_method = method; - this._flutter_inappwebview_isAsync = isAsync; - this._flutter_inappwebview_user = user; - this._flutter_inappwebview_password = password; - this._flutter_inappwebview_request_headers = {}; - open.call(this, method, url, isAsync, user, password); - }; - ajax.prototype.setRequestHeader = function(header, value) { - this._flutter_inappwebview_request_headers[header] = value; - setRequestHeader.call(this, header, value); - }; - function handleEvent(e) { - if (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) === false || \(FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS()) == null || \(FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS()) === false) { - return; - } - var self = this; - if (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) == null || \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) == true) { - var headers = this.getAllResponseHeaders(); - var responseHeaders = {}; - if (headers != null) { - var arr = headers.trim().split(/[\\r\\n]+/); - arr.forEach(function (line) { - var parts = line.split(': '); - var header = parts.shift(); - var value = parts.join(': '); - responseHeaders[header] = value; - }); - } - convertRequestResponse(this, function(response) { - var ajaxRequest = { - method: self._flutter_inappwebview_method, - url: self._flutter_inappwebview_url, - isAsync: self._flutter_inappwebview_isAsync, - user: self._flutter_inappwebview_user, - password: self._flutter_inappwebview_password, - withCredentials: self.withCredentials, - headers: self._flutter_inappwebview_request_headers, - readyState: self.readyState, - status: self.status, - responseURL: self.responseURL, - responseType: self.responseType, - response: response, - responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null, - responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null, - statusText: self.statusText, - responseHeaders, responseHeaders, - event: { - type: e.type, - loaded: e.loaded, - lengthComputable: e.lengthComputable, - total: e.total - } - }; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onAjaxProgress', ajaxRequest).then(function(result) { - if (result != null) { - switch (result) { - case 0: - self.abort(); - return; - }; - } - }); - }); - } - }; - ajax.prototype.send = function(data) { - var self = this; - var canBeIntercepted = self._flutter_inappwebview_isAsync || \(FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE()) === false; - if (canBeIntercepted && (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) == null || \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) == true)) { - if (\(FLAG_VARIABLE_FOR_ON_AJAX_READY_STATE_CHANGE()) === true && !this._flutter_inappwebview_already_onreadystatechange_wrapped) { - this._flutter_inappwebview_already_onreadystatechange_wrapped = true; - var realOnreadystatechange = this.onreadystatechange; - this.onreadystatechange = function() { - if (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) == null || \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) == true) { - var headers = this.getAllResponseHeaders(); - var responseHeaders = {}; - if (headers != null) { - var arr = headers.trim().split(/[\\r\\n]+/); - arr.forEach(function (line) { - var parts = line.split(': '); - var header = parts.shift(); - var value = parts.join(': '); - responseHeaders[header] = value; - }); - } - convertRequestResponse(this, function(response) { - var ajaxRequest = { - method: self._flutter_inappwebview_method, - url: self._flutter_inappwebview_url, - isAsync: self._flutter_inappwebview_isAsync, - user: self._flutter_inappwebview_user, - password: self._flutter_inappwebview_password, - withCredentials: self.withCredentials, - headers: self._flutter_inappwebview_request_headers, - readyState: self.readyState, - status: self.status, - responseURL: self.responseURL, - responseType: self.responseType, - response: response, - responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null, - responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null, - statusText: self.statusText, - responseHeaders: responseHeaders - }; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onAjaxReadyStateChange', ajaxRequest).then(function(result) { - if (result != null) { - switch (result) { - case 0: - self.abort(); - return; - }; - } - if (realOnreadystatechange != null) { - realOnreadystatechange(); - } - }); - }); - } else if (realOnreadystatechange != null) { - realOnreadystatechange(); - } - }; - } - this.addEventListener('loadstart', handleEvent); - this.addEventListener('load', handleEvent); - this.addEventListener('loadend', handleEvent); - this.addEventListener('progress', handleEvent); - this.addEventListener('error', handleEvent); - this.addEventListener('abort', handleEvent); - this.addEventListener('timeout', handleEvent); - \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).convertBodyRequest(data).then(function(data) { - var ajaxRequest = { - data: data, - method: self._flutter_inappwebview_method, - url: self._flutter_inappwebview_url, - isAsync: self._flutter_inappwebview_isAsync, - user: self._flutter_inappwebview_user, - password: self._flutter_inappwebview_password, - withCredentials: self.withCredentials, - headers: self._flutter_inappwebview_request_headers, - responseType: self.responseType - }; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('shouldInterceptAjaxRequest', ajaxRequest).then(function(result) { - if (result != null) { - switch (result) { - case 0: - self.abort(); - return; - }; - if (result.data != null && !\(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).isString(result.data) && result.data.length > 0) { - var bodyString = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).arrayBufferToString(result.data); - if (\(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).isBodyFormData(bodyString)) { - var formDataContentType = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).getFormDataContentType(bodyString); - if (result.headers != null) { - result.headers['Content-Type'] = result.headers['Content-Type'] == null ? formDataContentType : result.headers['Content-Type']; - } else { - result.headers = { 'Content-Type': formDataContentType }; - } - } - } - if (\(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).isString(result.data) || result.data == null) { - data = result.data; - } else if (result.data.length > 0) { - data = new Uint8Array(result.data); - } - self.withCredentials = result.withCredentials; - if (result.responseType != null && self._flutter_inappwebview_isAsync) { - self.responseType = result.responseType; - }; - if (result.headers != null) { - for (var header in result.headers) { - var value = result.headers[header]; - var flutter_inappwebview_value = self._flutter_inappwebview_request_headers[header]; - if (flutter_inappwebview_value == null) { - self._flutter_inappwebview_request_headers[header] = value; - } else { - self._flutter_inappwebview_request_headers[header] += ', ' + value; - } - setRequestHeader.call(self, header, value); - }; - } - if ((self._flutter_inappwebview_method != result.method && result.method != null) || - (self._flutter_inappwebview_url != result.url && result.url != null) || - (self._flutter_inappwebview_isAsync != result.isAsync && result.isAsync != null) || - (self._flutter_inappwebview_user != result.user && result.user != null) || - (self._flutter_inappwebview_password != result.password && result.password != null)) { - self.abort(); - self.open(result.method, result.url, result.isAsync, result.user, result.password); - } - } - send.call(self, data); - }); - }); - } else { - send.call(this, data); - } - }; - })(window.XMLHttpRequest); - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/InterceptFetchRequestJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/InterceptFetchRequestJS.swift deleted file mode 100644 index 953fa3aa8f..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/InterceptFetchRequestJS.swift +++ /dev/null @@ -1,163 +0,0 @@ -// -// InterceptFetchRequestsJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class InterceptFetchRequestJS { - - public static let INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT" - public static func FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._useShouldInterceptFetchRequest" - } - - public static func INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?, forMainFrameOnly: Bool) -> PluginScript { - return PluginScript( - groupName: INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: INTERCEPT_FETCH_REQUEST_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: true, - messageHandlerNames: []) - } - - public static func INTERCEPT_FETCH_REQUEST_JS_SOURCE() -> String { - return """ - \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE()) = true; - (function(fetch) { - if (fetch == null) { - return; - } - window.fetch = async function(resource, init) { - if (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE()) == null || \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE()) == true) { - var fetchRequest = { - url: null, - method: null, - headers: null, - body: null, - mode: null, - credentials: null, - cache: null, - redirect: null, - referrer: null, - referrerPolicy: null, - integrity: null, - keepalive: null - }; - if (resource instanceof Request) { - fetchRequest.url = resource.url; - fetchRequest.method = resource.method; - fetchRequest.headers = resource.headers; - fetchRequest.body = resource.body; - fetchRequest.mode = resource.mode; - fetchRequest.credentials = resource.credentials; - fetchRequest.cache = resource.cache; - fetchRequest.redirect = resource.redirect; - fetchRequest.referrer = resource.referrer; - fetchRequest.referrerPolicy = resource.referrerPolicy; - fetchRequest.integrity = resource.integrity; - fetchRequest.keepalive = resource.keepalive; - } else { - fetchRequest.url = resource != null ? resource.toString() : null; - if (init != null) { - fetchRequest.method = init.method; - fetchRequest.headers = init.headers; - fetchRequest.body = init.body; - fetchRequest.mode = init.mode; - fetchRequest.credentials = init.credentials; - fetchRequest.cache = init.cache; - fetchRequest.redirect = init.redirect; - fetchRequest.referrer = init.referrer; - fetchRequest.referrerPolicy = init.referrerPolicy; - fetchRequest.integrity = init.integrity; - fetchRequest.keepalive = init.keepalive; - } - } - if (fetchRequest.headers instanceof Headers) { - fetchRequest.headers = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).convertHeadersToJson(fetchRequest.headers); - } - fetchRequest.credentials = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).convertCredentialsToJson(fetchRequest.credentials); - return \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).convertBodyRequest(fetchRequest.body).then(function(body) { - fetchRequest.body = body; - return window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('shouldInterceptFetchRequest', fetchRequest).then(function(result) { - if (result != null) { - switch (result.action) { - case 0: - var controller = new AbortController(); - if (init != null) { - init.signal = controller.signal; - } else { - init = { - signal: controller.signal - }; - } - controller.abort(); - break; - } - if (result.body != null && !\(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).isString(result.body) && result.body.length > 0) { - var bodyString = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).arrayBufferToString(result.body); - if (\(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).isBodyFormData(bodyString)) { - var formDataContentType = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).getFormDataContentType(bodyString); - if (result.headers != null) { - result.headers['Content-Type'] = result.headers['Content-Type'] == null ? formDataContentType : result.headers['Content-Type']; - } else { - result.headers = { 'Content-Type': formDataContentType }; - } - } - } - resource = result.url; - if (init == null) { - init = {}; - } - if (result.method != null && result.method.length > 0) { - init.method = result.method; - } - if (result.headers != null && Object.keys(result.headers).length > 0) { - init.headers = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).convertJsonToHeaders(result.headers); - } - if (\(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).isString(result.body) || result.body == null) { - init.body = result.body; - } else if (result.body.length > 0) { - init.body = new Uint8Array(result.body); - } - if (result.mode != null && result.mode.length > 0) { - init.mode = result.mode; - } - if (result.credentials != null) { - init.credentials = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).convertJsonToCredential(result.credentials); - } - if (result.cache != null && result.cache.length > 0) { - init.cache = result.cache; - } - if (result.redirect != null && result.redirect.length > 0) { - init.redirect = result.redirect; - } - if (result.referrer != null && result.referrer.length > 0) { - init.referrer = result.referrer; - } - if (result.referrerPolicy != null && result.referrerPolicy.length > 0) { - init.referrerPolicy = result.referrerPolicy; - } - if (result.integrity != null && result.integrity.length > 0) { - init.integrity = result.integrity; - } - if (result.keepalive != null) { - init.keepalive = result.keepalive; - } - return fetch(resource, init); - } - return fetch(resource, init); - }); - }); - } else { - return fetch(resource, init); - } - }; - })(window.fetch); - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/JavaScriptBridgeJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/JavaScriptBridgeJS.swift deleted file mode 100644 index 0e42a37342..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/JavaScriptBridgeJS.swift +++ /dev/null @@ -1,293 +0,0 @@ -// -// javaScriptBridgeJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class JavaScriptBridgeJS { - private static var _JAVASCRIPT_BRIDGE_NAME = "flutter_inappwebview" - public static func set_JAVASCRIPT_BRIDGE_NAME(bridgeName: String) { - _JAVASCRIPT_BRIDGE_NAME = bridgeName - } - public static func get_JAVASCRIPT_BRIDGE_NAME() -> String { - return _JAVASCRIPT_BRIDGE_NAME - } - - public static let JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT" - - public static let VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET = "$IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_BRIDGE_SECRET" - - public static func JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT(expectedBridgeSecret: String, allowedOriginRules: [String]?, forMainFrameOnly: Bool) -> PluginScript { - let source = JAVASCRIPT_BRIDGE_JS_SOURCE().replacingOccurrences(of: VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET, with: expectedBridgeSecret) - return PluginScript( - groupName: JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: source, - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: true, - messageHandlerNames: ["callHandler"]) - } - - public static func JAVASCRIPT_BRIDGE_JS_SOURCE() -> String { - return """ - window.\(get_JAVASCRIPT_BRIDGE_NAME()) = {}; - \(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME()) = {}; - (function(window) { - var bridgeSecret = '\(VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET)'; - var _JSON_stringify; - var _Array_slice; - var _setTimeout; - var _Promise; - var _UserMessageHandler; - var _postMessage; - try { - _JSON_stringify = window.JSON.stringify; - _Array_slice = window.Array.prototype.slice; - _Array_slice.call = window.Function.prototype.call; - _setTimeout = window.setTimeout; - _Promise = window.Promise; - _UserMessageHandler = window.webkit.messageHandlers['callHandler']; - _postMessage = _UserMessageHandler.postMessage; - _postMessage.call = window.Function.prototype.call; - } catch (_) { return; } - window.\(get_JAVASCRIPT_BRIDGE_NAME()).callHandler = function() { - var _windowId = \(WindowIdJS.WINDOW_ID_VARIABLE_JS_SOURCE()); - var _callHandlerID = _setTimeout(function(){}); - _postMessage.call(_UserMessageHandler, { - 'handlerName': arguments[0], - '_callHandlerID': _callHandlerID, - '_bridgeSecret': bridgeSecret, - 'args': _JSON_stringify(_Array_slice.call(arguments, 1)), - '_windowId': _windowId - }); - return new _Promise(function(resolve, reject) { - try { - (window.top === window ? window : window.top).\(get_JAVASCRIPT_BRIDGE_NAME())[_callHandlerID] = {resolve: resolve, reject: reject}; - } catch (e) { - resolve(); - } - }); - }; - })(window); - \(WebMessageListenerJS.WEB_MESSAGE_LISTENER_JS_SOURCE()) - \(UTIL_JS_SOURCE()) - """ - } - - public static let PLATFORM_READY_JS_SOURCE = "window.dispatchEvent(new Event('flutterInAppWebViewPlatformReady'));"; - - public static func JAVASCRIPT_UTIL_VAR_NAME() -> String { - return "window.\(get_JAVASCRIPT_BRIDGE_NAME())._Util" - } - - /* - https://github.com/github/fetch/blob/master/fetch.js - */ - public static func UTIL_JS_SOURCE() -> String { - return """ - \(JAVASCRIPT_UTIL_VAR_NAME()) = { - support: { - searchParams: 'URLSearchParams' in window, - iterable: 'Symbol' in window && 'iterator' in Symbol, - blob: - 'FileReader' in window && - 'Blob' in window && - (function() { - try { - new Blob(); - return true; - } catch (e) { - return false; - } - })(), - formData: 'FormData' in window, - arrayBuffer: 'ArrayBuffer' in window - }, - isDataView: function(obj) { - return obj && DataView.prototype.isPrototypeOf(obj); - }, - fileReaderReady: function(reader) { - return new Promise(function(resolve, reject) { - reader.onload = function() { - resolve(reader.result); - }; - reader.onerror = function() { - reject(reader.error); - }; - }); - }, - readBlobAsArrayBuffer: function(blob) { - var reader = new FileReader(); - var promise = \(JAVASCRIPT_UTIL_VAR_NAME()).fileReaderReady(reader); - reader.readAsArrayBuffer(blob); - return promise; - }, - convertBodyToArrayBuffer: function(body) { - var viewClasses = [ - '[object Int8Array]', - '[object Uint8Array]', - '[object Uint8ClampedArray]', - '[object Int16Array]', - '[object Uint16Array]', - '[object Int32Array]', - '[object Uint32Array]', - '[object Float32Array]', - '[object Float64Array]' - ]; - var isArrayBufferView = null; - if (\(JAVASCRIPT_UTIL_VAR_NAME()).support.arrayBuffer) { - isArrayBufferView = - ArrayBuffer.isView || - function(obj) { - return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1; - }; - } - - var bodyUsed = false; - - this._bodyInit = body; - if (!body) { - this._bodyText = ''; - } else if (typeof body === 'string') { - this._bodyText = body; - } else if (\(JAVASCRIPT_UTIL_VAR_NAME()).support.blob && Blob.prototype.isPrototypeOf(body)) { - this._bodyBlob = body; - } else if (\(JAVASCRIPT_UTIL_VAR_NAME()).support.formData && FormData.prototype.isPrototypeOf(body)) { - this._bodyFormData = body; - } else if (\(JAVASCRIPT_UTIL_VAR_NAME()).support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { - this._bodyText = body.toString(); - } else if (\(JAVASCRIPT_UTIL_VAR_NAME()).support.arrayBuffer && \(JAVASCRIPT_UTIL_VAR_NAME()).support.blob && \(JAVASCRIPT_UTIL_VAR_NAME()).isDataView(body)) { - this._bodyArrayBuffer = bufferClone(body.buffer); - this._bodyInit = new Blob([this._bodyArrayBuffer]); - } else if (\(JAVASCRIPT_UTIL_VAR_NAME()).support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) { - this._bodyArrayBuffer = bufferClone(body); - } else { - this._bodyText = body = Object.prototype.toString.call(body); - } - - this.blob = function () { - if (bodyUsed) { - return Promise.reject(new TypeError('Already read')); - } - bodyUsed = true; - if (this._bodyBlob) { - return Promise.resolve(this._bodyBlob); - } else if (this._bodyArrayBuffer) { - return Promise.resolve(new Blob([this._bodyArrayBuffer])); - } else if (this._bodyFormData) { - throw new Error('could not read FormData body as blob'); - } else { - return Promise.resolve(new Blob([this._bodyText])); - } - }; - - if (this._bodyArrayBuffer) { - if (bodyUsed) { - return Promise.reject(new TypeError('Already read')); - } - bodyUsed = true; - if (ArrayBuffer.isView(this._bodyArrayBuffer)) { - return Promise.resolve( - this._bodyArrayBuffer.buffer.slice( - this._bodyArrayBuffer.byteOffset, - this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength - ) - ); - } else { - return Promise.resolve(this._bodyArrayBuffer); - } - } - return this.blob().then(\(JAVASCRIPT_UTIL_VAR_NAME()).readBlobAsArrayBuffer); - }, - isString: function(variable) { - return typeof variable === 'string' || variable instanceof String; - }, - convertBodyRequest: function(body) { - if (body == null) { - return new Promise((resolve, reject) => resolve(null)); - } - if (\(JAVASCRIPT_UTIL_VAR_NAME()).isString(body) || (\(JAVASCRIPT_UTIL_VAR_NAME()).support.searchParams && body instanceof URLSearchParams)) { - return new Promise((resolve, reject) => resolve(body.toString())); - } - if (window.Response != null) { - return new Response(body).arrayBuffer().then(function(arrayBuffer) { - return Array.from(new Uint8Array(arrayBuffer)); - }); - } - return \(JAVASCRIPT_UTIL_VAR_NAME()).convertBodyToArrayBuffer(body).then(function(arrayBuffer) { - return Array.from(new Uint8Array(arrayBuffer)); - }); - }, - arrayBufferToString: function(arrayBuffer) { - var uint8Array = new Uint8Array(arrayBuffer); - return uint8Array.reduce(function(acc, i) { return acc += String.fromCharCode.apply(null, [i]); }, ''); - }, - isBodyFormData: function(bodyString) { - return bodyString.indexOf('------WebKitFormBoundary') >= 0; - }, - getFormDataContentType: function(bodyString) { - var boundary = bodyString.substr(2, 40); - return 'multipart/form-data; boundary=' + boundary; - }, - convertHeadersToJson: function(headers) { - var headersObj = {}; - for (var header of headers.keys()) { - var value = headers.get(header); - headersObj[header] = value; - } - return headersObj; - }, - convertJsonToHeaders: function(headersJson) { - return new Headers(headersJson); - }, - convertCredentialsToJson: function(credentials) { - var credentialsObj = {}; - if (window.FederatedCredential != null && credentials instanceof FederatedCredential) { - credentialsObj.type = credentials.type; - credentialsObj.id = credentials.id; - credentialsObj.name = credentials.name; - credentialsObj.protocol = credentials.protocol; - credentialsObj.provider = credentials.provider; - credentialsObj.iconURL = credentials.iconURL; - } else if (window.PasswordCredential != null && credentials instanceof PasswordCredential) { - credentialsObj.type = credentials.type; - credentialsObj.id = credentials.id; - credentialsObj.name = credentials.name; - credentialsObj.password = credentials.password; - credentialsObj.iconURL = credentials.iconURL; - } else { - credentialsObj.type = 'default'; - credentialsObj.value = credentials; - } - return credentialsObj; - }, - convertJsonToCredential: function(credentialsJson) { - var credentials; - if (window.FederatedCredential != null && credentialsJson.type === 'federated') { - credentials = new FederatedCredential({ - id: credentialsJson.id, - name: credentialsJson.name, - protocol: credentialsJson.protocol, - provider: credentialsJson.provider, - iconURL: credentialsJson.iconURL - }); - } else if (window.PasswordCredential != null && credentialsJson.type === 'password') { - credentials = new PasswordCredential({ - id: credentialsJson.id, - name: credentialsJson.name, - password: credentialsJson.password, - iconURL: credentialsJson.iconURL - }); - } else { - credentials = credentialsJson.value == null ? undefined : credentialsJson.value; - } - return credentials; - } - }; - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/LastTouchedAnchorOrImageJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/LastTouchedAnchorOrImageJS.swift deleted file mode 100644 index 9cdcdd5a5d..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/LastTouchedAnchorOrImageJS.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// LastTouchedAnchorOrImageJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class LastTouchedAnchorOrImageJS { - - public static let LAST_TOUCHED_ANCHOR_OR_IMAGE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_LAST_TOUCHED_ANCHOR_OR_IMAGE_JS_PLUGIN_SCRIPT" - - // This plugin is only for main frame - public static func LAST_TOUCHED_ANCHOR_OR_IMAGE_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: LAST_TOUCHED_ANCHOR_OR_IMAGE_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: LAST_TOUCHED_ANCHOR_OR_IMAGE_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static func LAST_TOUCHED_ANCHOR_OR_IMAGE_JS_SOURCE() -> String { - return """ - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._lastAnchorOrImageTouched = null; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._lastImageTouched = null; - (function() { - document.addEventListener('touchstart', function(event) { - var target = event.target; - while (target) { - if (target.tagName === 'IMG') { - var img = target; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._lastImageTouched = { - url: img.src - }; - var parent = img.parentNode; - while (parent) { - if (parent.tagName === 'A') { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._lastAnchorOrImageTouched = { - title: parent.textContent, - url: parent.href, - src: img.src - }; - break; - } - parent = parent.parentNode; - } - return; - } else if (target.tagName === 'A') { - var link = target; - var images = link.getElementsByTagName('img'); - var img = (images.length > 0) ? images[0] : null; - var imgSrc = (img != null) ? img.src : null; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._lastImageTouched = (img != null) ? {url: imgSrc} : window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._lastImageTouched; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._lastAnchorOrImageTouched = { - title: link.textContent, - url: link.href, - src: imgSrc - }; - return; - } - target = target.parentNode; - } - }); - })(); - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/OnLoadResourceJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/OnLoadResourceJS.swift deleted file mode 100644 index 18a5e496b4..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/OnLoadResourceJS.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// resourceObserverJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class OnLoadResourceJS { - - public static let ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT" - - public static func FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._useOnLoadResource" - } - - public static func ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?, forMainFrameOnly: Bool) -> PluginScript { - return PluginScript( - groupName: ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: ON_LOAD_RESOURCE_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static func ON_LOAD_RESOURCE_JS_SOURCE() -> String { - return """ - \(FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE()) = true; - (function() { - var observer = new PerformanceObserver(function(list) { - list.getEntries().forEach(function(entry) { - if (\(FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE()) == null || \(FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE()) == true) { - var resource = { - "url": entry.name, - "initiatorType": entry.initiatorType, - "startTime": entry.startTime, - "duration": entry.duration - }; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler("onLoadResource", resource); - } - }); - }); - observer.observe({entryTypes: ['resource']}); - })(); - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/OnWindowBlurEventJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/OnWindowBlurEventJS.swift deleted file mode 100644 index d9221d10e4..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/OnWindowBlurEventJS.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// OnWindowBlurEventJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class OnWindowBlurEventJS { - - public static let ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT" - - // This plugin is only for main frame - public static func ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: ON_WINDOW_BLUR_EVENT_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static func ON_WINDOW_BLUR_EVENT_JS_SOURCE() -> String { - return """ - (function(){ - window.addEventListener('blur', function(e) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onWindowBlur'); - }); - })(); - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/OnWindowFocusEventJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/OnWindowFocusEventJS.swift deleted file mode 100644 index b08bb08895..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/OnWindowFocusEventJS.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// OnWindowFocusEventJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class OnWindowFocusEventJS { - - public static let ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT" - - // This plugin is only for main frame - public static func ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: ON_WINDOW_FOCUS_EVENT_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static func ON_WINDOW_FOCUS_EVENT_JS_SOURCE() -> String { - return """ - (function(){ - window.addEventListener('focus', function(e) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onWindowFocus'); - }); - })(); - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/OriginalViewPortMetaTagContentJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/OriginalViewPortMetaTagContentJS.swift deleted file mode 100644 index d84c14ee34..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/OriginalViewPortMetaTagContentJS.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// OriginalViewPortMetaTagContentJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class OriginalViewPortMetaTagContentJS { - - public static let ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_PLUGIN_SCRIPT" - - // This plugin is only for main frame - public static func ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_SOURCE(), - injectionTime: .atDocumentEnd, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static func ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_SOURCE() -> String { - return """ - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._originalViewPortMetaTagContent = ""; - (function() { - var metaTagNodes = document.head.getElementsByTagName('meta'); - for (var i = 0; i < metaTagNodes.length; i++) { - var metaTagNode = metaTagNodes[i]; - if (metaTagNode.name === "viewport") { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._originalViewPortMetaTagContent = metaTagNode.content; - } - } - })(); - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/PluginScriptsUtil.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/PluginScriptsUtil.swift deleted file mode 100644 index 51f9c86714..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/PluginScriptsUtil.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// PluginScripts.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class PluginScriptsUtil { - public static let VAR_PLACEHOLDER_VALUE = "$IN_APP_WEBVIEW_PLACEHOLDER_VALUE" - public static let VAR_FUNCTION_ARGUMENT_NAMES = "$IN_APP_WEBVIEW_FUNCTION_ARGUMENT_NAMES" - public static let VAR_FUNCTION_ARGUMENT_VALUES = "$IN_APP_WEBVIEW_FUNCTION_ARGUMENT_VALUES" - public static let VAR_FUNCTION_ARGUMENTS_OBJ = "$IN_APP_WEBVIEW_FUNCTION_ARGUMENTS_OBJ" - public static let VAR_FUNCTION_BODY = "$IN_APP_WEBVIEW_FUNCTION_BODY" - public static let VAR_RESULT_UUID = "$IN_APP_WEBVIEW_RESULT_UUID" - - public static let GET_SELECTED_TEXT_JS_SOURCE = """ -(function(){ - var txt; - if (window.getSelection) { - txt = window.getSelection().toString(); - } else if (window.document.getSelection) { - txt = window.document.getSelection().toString(); - } else if (window.document.selection) { - txt = window.document.selection.createRange().text; - } - return txt; -})(); -""" -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/PrintJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/PrintJS.swift deleted file mode 100644 index fbf29f50f3..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/PrintJS.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// PrintJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class PrintJS { - - public static let PRINT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_PRINT_JS_PLUGIN_SCRIPT" - - public static func PRINT_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?, forMainFrameOnly: Bool) -> PluginScript { - return PluginScript( - groupName: PRINT_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: PRINT_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: true, - messageHandlerNames: []) - } - - public static func PRINT_JS_SOURCE() -> String { - return """ - window.print = function() { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler("onPrintRequest", window.location.href); - } - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/PromisePolyfillJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/PromisePolyfillJS.swift deleted file mode 100644 index 27c076be23..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/PromisePolyfillJS.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// PromisePolyfillJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation -import WebKit - -public class PromisePolyfillJS { - public static let PROMISE_POLYFILL_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_PROMISE_POLYFILL_JS_PLUGIN_SCRIPT" - - public static func PROMISE_POLYFILL_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?, forMainFrameOnly: Bool) -> PluginScript { - return PluginScript( - groupName: PROMISE_POLYFILL_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: PROMISE_POLYFILL_JS_SOURCE, - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: true, - messageHandlerNames: []) - } - - // https://github.com/tildeio/rsvp.js - public static let PROMISE_POLYFILL_JS_SOURCE = """ - if (window.Promise == null) { - !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(t.RSVP={})}(this,function(t){"use strict";function e(t){var e=t._promiseCallbacks;return e||(e=t._promiseCallbacks={}),e}var r={mixin:function(t){return t.on=this.on,t.off=this.off,t.trigger=this.trigger,t._promiseCallbacks=void 0,t},on:function(t,r){if("function"!=typeof r)throw new TypeError("Callback must be a function");var n=e(this),o=n[t];o||(o=n[t]=[]),-1===o.indexOf(r)&&o.push(r)},off:function(t,r){var n=e(this);if(r){var o=n[t],i=o.indexOf(r);-1!==i&&o.splice(i,1)}else n[t]=[]},trigger:function(t,r,n){var o=e(this)[t];if(o)for(var i=0;i2&&void 0!==arguments[2])||arguments[2],o=arguments[3];return function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,t.call(this,e,r,n,o))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,t),e.prototype._init=function(t,e){this._result={},this._enumerate(e)},e.prototype._enumerate=function(t){var e=Object.keys(t),r=e.length,n=this.promise;this._remaining=r;for(var o=void 0,i=void 0,s=0;n._state===a&&s PluginScript { - return PluginScript( - groupName: NOT_SUPPORT_ZOOM_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: NOT_SUPPORT_ZOOM_JS_SOURCE, - injectionTime: .atDocumentEnd, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static let NOT_SUPPORT_ZOOM_JS_SOURCE = """ - (function() { - var meta = document.createElement('meta'); - meta.setAttribute('name', 'viewport'); - meta.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'); - document.getElementsByTagName('head')[0].appendChild(meta); - })() - """ - - public static func SUPPORT_ZOOM_JS_SOURCE() -> String { - return """ - (function() { - var meta = document.createElement('meta'); - meta.setAttribute('name', 'viewport'); - meta.setAttribute('content', window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._originalViewPortMetaTagContent); - document.getElementsByTagName('head')[0].appendChild(meta); - })() - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/WebMessageChannelJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/WebMessageChannelJS.swift deleted file mode 100644 index e41494d88e..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/WebMessageChannelJS.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// WebMessageChannelJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/03/21. -// - -import Foundation - -public class WebMessageChannelJS { - - public static func WEB_MESSAGE_CHANNELS_VARIABLE_NAME() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._webMessageChannels" - } - -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/WebMessageListenerJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/WebMessageListenerJS.swift deleted file mode 100644 index 6740765ac5..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/WebMessageListenerJS.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// WebMessageListenerJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/03/21. -// - -import Foundation - -public class WebMessageListenerJS { - - public static func WEB_MESSAGE_LISTENER_JS_SOURCE() -> String { - return """ - function FlutterInAppWebViewWebMessageListener(jsObjectName) { - this.jsObjectName = jsObjectName; - this.listeners = []; - this.onmessage = null; - } - FlutterInAppWebViewWebMessageListener.prototype.postMessage = function(data) { - var message = { - "data": window.ArrayBuffer != null && data instanceof ArrayBuffer ? Array.from(new Uint8Array(data)) : (data != null ? data.toString() : null), - "type": window.ArrayBuffer != null && data instanceof ArrayBuffer ? 1 : 0 - }; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onWebMessageListenerPostMessageReceived', {jsObjectName: this.jsObjectName, message: message}); - }; - FlutterInAppWebViewWebMessageListener.prototype.addEventListener = function(type, listener) { - if (listener == null) { - return; - } - this.listeners.push(listener); - }; - FlutterInAppWebViewWebMessageListener.prototype.removeEventListener = function(type, listener) { - if (listener == null) { - return; - } - var index = this.listeners.indexOf(listener); - if (index >= 0) { - this.listeners.splice(index, 1); - } - }; - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/WindowIdJS.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/WindowIdJS.swift deleted file mode 100644 index 173167416d..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PluginScriptsJS/WindowIdJS.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// WindowIdJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class WindowIdJS { - - public static let WINDOW_ID_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_WINDOW_ID_JS_PLUGIN_SCRIPT" - - public static func WINDOW_ID_VARIABLE_JS_SOURCE() -> String { - return "window._\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())_windowId" - } - - public static func WINDOW_ID_INITIALIZE_JS_SOURCE() -> String { - return """ - (function() { - \(WINDOW_ID_VARIABLE_JS_SOURCE()) = \(PluginScriptsUtil.VAR_PLACEHOLDER_VALUE); - return \(WINDOW_ID_VARIABLE_JS_SOURCE()); - })() - """ - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/CustomUIPrintPageRenderer.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/CustomUIPrintPageRenderer.swift deleted file mode 100644 index 1fb06f0e49..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/CustomUIPrintPageRenderer.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// CustomUIPrintPageRenderer.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/05/22. -// - -import Foundation -import UIKit - -public class CustomUIPrintPageRenderer: UIPrintPageRenderer { - private var _numberOfPages: Int? - private var forceRenderingQuality: Int? - - public init(numberOfPage: Int? = nil, forceRenderingQuality: Int? = nil) { - super.init() - self._numberOfPages = numberOfPage - self.forceRenderingQuality = forceRenderingQuality - } - - open override var numberOfPages: Int { - get { - return _numberOfPages ?? super.numberOfPages - } - } - - @available(iOS 14.5, *) - open override func currentRenderingQuality(forRequested requestedRenderingQuality: UIPrintRenderingQuality) -> UIPrintRenderingQuality { - if let forceRenderingQuality = forceRenderingQuality, - let quality = UIPrintRenderingQuality.init(rawValue: forceRenderingQuality) { - return quality - } - return super.currentRenderingQuality(forRequested: requestedRenderingQuality) - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintAttributes.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintAttributes.swift deleted file mode 100644 index c290a279c1..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintAttributes.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// PrintAttributes.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/05/22. -// - -import Foundation -import UIKit - -public class PrintAttributes: NSObject { - var orientation: UIPrintInfo.Orientation? - var duplex: UIPrintInfo.Duplex? - var outputType: UIPrintInfo.OutputType? - var margins: UIEdgeInsets? - var footerHeight: Double? - var headerHeight: Double? - var paperRect: CGRect? - var printableRect: CGRect? - var maximumContentHeight: Double? - var maximumContentWidth: Double? - - public init(fromPrintJobController: PrintJobController) { - super.init() - if let printPageRenderer = fromPrintJobController.printPageRenderer { - footerHeight = printPageRenderer.footerHeight - headerHeight = printPageRenderer.headerHeight - paperRect = printPageRenderer.paperRect - printableRect = printPageRenderer.printableRect - } - if let printFormatter = fromPrintJobController.printFormatter { - maximumContentHeight = printFormatter.maximumContentHeight - maximumContentWidth = printFormatter.maximumContentWidth - margins = printFormatter.perPageContentInsets - } - if let job = fromPrintJobController.job, let printInfo = job.printInfo { - orientation = printInfo.orientation - duplex = printInfo.duplex - outputType = printInfo.outputType - } - } - - public func toMap () -> [String:Any?] { - return [ - "footerHeight": footerHeight, - "headerHeight": headerHeight, - "paperRect": paperRect?.toMap(), - "printableRect": printableRect?.toMap(), - "margins": margins?.toMap(), - "maximumContentHeight": maximumContentHeight, - "maximumContentWidth": maximumContentWidth, - "orientation": orientation?.rawValue, - "duplex": duplex?.rawValue, - "outputType": outputType?.rawValue - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintJobChannelDelegate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintJobChannelDelegate.swift deleted file mode 100644 index 5dfd7ec073..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintJobChannelDelegate.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// PrintJobChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 09/05/22. -// - -import Foundation -import Flutter - -public class PrintJobChannelDelegate: ChannelDelegate { - private weak var printJobController: PrintJobController? - - public init(printJobController: PrintJobController, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.printJobController = printJobController - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "dismiss": - if let job = printJobController?.job { - let animated = arguments!["animated"] as! Bool - job.dismiss(animated: animated) - result(true) - } else { - result(false) - } - break - case "getInfo": - if let printJobController = printJobController { - result(printJobController.getInfo()?.toMap()) - } else { - result(false) - } - break - case "dispose": - if let printJobController = printJobController { - printJobController.dispose() - result(true) - } else { - result(false) - } - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func onComplete(completed: Bool, error: Error?) { - let arguments: [String: Any?] = [ - "completed": completed, - "error": error?.localizedDescription - ] - channel?.invokeMethod("onComplete", arguments: arguments) - } - - public override func dispose() { - super.dispose() - printJobController = nil - } - - deinit { - debugPrint("PrintJobChannelDelegate - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintJobController.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintJobController.swift deleted file mode 100644 index f3056d9477..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintJobController.swift +++ /dev/null @@ -1,106 +0,0 @@ -// -// PrintJob.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 09/05/22. -// - -import Foundation -import UIKit -import Flutter - -public enum PrintJobState: Int { - case created = 1 - case started = 3 - case completed = 5 - case failed = 6 - case canceled = 7 -} - -public class PrintJobController: NSObject, Disposable, UIPrintInteractionControllerDelegate { - static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_printjobcontroller_" - var id: String - var plugin: InAppWebViewFlutterPlugin? - var job: UIPrintInteractionController? - var settings: PrintJobSettings? - var printFormatter: UIPrintFormatter? - var printPageRenderer: UIPrintPageRenderer? - var channelDelegate: PrintJobChannelDelegate? - var state = PrintJobState.created - var creationTime = Int64(Date().timeIntervalSince1970 * 1000) - - public init(plugin: InAppWebViewFlutterPlugin, id: String, job: UIPrintInteractionController? = nil, settings: PrintJobSettings? = nil) { - self.id = id - self.plugin = plugin - super.init() - self.job = job - self.settings = settings - self.printFormatter = job?.printFormatter - self.printPageRenderer = job?.printPageRenderer - self.job?.delegate = self - let channel = FlutterMethodChannel(name: PrintJobController.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: plugin.registrar.messenger()) - self.channelDelegate = PrintJobChannelDelegate(printJobController: self, channel: channel) - } - - public func printInteractionControllerWillStartJob(_ printInteractionController: UIPrintInteractionController) { - state = .started - } - - public func present(animated: Bool, completionHandler: UIPrintInteractionController.CompletionHandler? = nil) { - guard let job = job else { - return - } - - job.present(animated: animated, completionHandler: { [weak self] (printController, completed, error) in - if !completed { - if let _ = error { - self?.state = .failed - } else { - self?.state = .canceled - } - } else { - self?.state = .completed - } - self?.channelDelegate?.onComplete(completed: completed, error: error) - if let completionHandler = completionHandler { - completionHandler(printController, completed, error) - } - }) - } - - public func getInfo() -> PrintJobInfo? { - guard let _ = job else { - return nil - } - - return PrintJobInfo.init(fromPrintJobController: self) - } - - public func disposeNoDismiss() { - channelDelegate?.dispose() - channelDelegate = nil - printFormatter = nil - printPageRenderer = nil - job?.delegate = nil - job = nil - plugin?.printJobManager?.jobs[id] = nil - plugin = nil - } - - public func dispose() { - channelDelegate?.dispose() - channelDelegate = nil - printFormatter = nil - printPageRenderer = nil - job?.delegate = nil - job?.dismiss(animated: false) - job = nil - plugin?.printJobManager?.jobs[id] = nil - plugin = nil - } - - deinit { - debugPrint("PrintJobController - dealloc") - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintJobInfo.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintJobInfo.swift deleted file mode 100644 index b94c129376..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintJobInfo.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// PrintJobInfo.swift -// flutter_downloader -// -// Created by Lorenzo Pichilli on 10/05/22. -// - -import Foundation - -public class PrintJobInfo: NSObject { - var state: PrintJobState - var attributes: PrintAttributes - var creationTime: Int64 - var numberOfPages: Int? - var label: String? - var printerId: String? - - public init(fromPrintJobController: PrintJobController) { - state = fromPrintJobController.state - creationTime = fromPrintJobController.creationTime - attributes = PrintAttributes.init(fromPrintJobController: fromPrintJobController) - super.init() - if let printPageRenderer = fromPrintJobController.printPageRenderer { - numberOfPages = printPageRenderer.numberOfPages - } - if let job = fromPrintJobController.job, let printInfo = job.printInfo { - label = printInfo.jobName - printerId = printInfo.printerID - } - } - - public func toMap () -> [String:Any?] { - return [ - "state": state.rawValue, - "attributes": attributes.toMap(), - "copies": nil, - "numberOfPages": numberOfPages, - "creationTime": creationTime, - "label": label, - "printer": [ - "id": printerId - ] - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintJobManager.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintJobManager.swift deleted file mode 100644 index cf86b1e46a..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintJobManager.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// PrintJobManager.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 09/05/22. -// - -import Foundation - -public class PrintJobManager: NSObject, Disposable { - var plugin: InAppWebViewFlutterPlugin? - var jobs: [String: PrintJobController?] = [:] - - public init(plugin: InAppWebViewFlutterPlugin?) { - super.init() - self.plugin = plugin - } - - public func dispose() { - let jobValues = jobs.values - jobValues.forEach { (job: PrintJobController?) in - job?.dispose() - } - jobs.removeAll() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintJobSettings.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintJobSettings.swift deleted file mode 100644 index c576dc5ae7..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PrintJob/PrintJobSettings.swift +++ /dev/null @@ -1,155 +0,0 @@ -// -// PrintJobSettings.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 09/05/22. -// - -import Foundation -import UIKit - -@objcMembers -public class PrintJobSettings: ISettings { - - public var handledByClient = false - public var jobName: String? - public var animated = true - public var _orientation: NSNumber? - public var orientation: Int? { - get { - return _orientation?.intValue - } - set { - if let newValue = newValue { - _orientation = NSNumber.init(value: newValue) - } else { - _orientation = nil - } - } - } - public var _numberOfPages: NSNumber? - public var numberOfPages: Int? { - get { - return _numberOfPages?.intValue - } - set { - if let newValue = newValue { - _numberOfPages = NSNumber.init(value: newValue) - } else { - _numberOfPages = nil - } - } - } - public var _forceRenderingQuality: NSNumber? - public var forceRenderingQuality: Int? { - get { - return _forceRenderingQuality?.intValue - } - set { - if let newValue = newValue { - _forceRenderingQuality = NSNumber.init(value: newValue) - } else { - _forceRenderingQuality = nil - } - } - } - public var margins: UIEdgeInsets? - public var _duplexMode: NSNumber? - public var duplexMode: Int? { - get { - return _duplexMode?.intValue - } - set { - if let newValue = newValue { - _duplexMode = NSNumber.init(value: newValue) - } else { - _duplexMode = nil - } - } - } - public var _outputType: NSNumber? - public var outputType: Int? { - get { - return _outputType?.intValue - } - set { - if let newValue = newValue { - _outputType = NSNumber.init(value: newValue) - } else { - _outputType = nil - } - } - } - public var showsNumberOfCopies = true - public var showsPaperSelectionForLoadedPapers = false - public var showsPaperOrientation = true - public var _maximumContentHeight: NSNumber? - public var maximumContentHeight: Double? { - get { - return _maximumContentHeight?.doubleValue - } - set { - if let newValue = newValue { - _maximumContentHeight = NSNumber.init(value: newValue) - } else { - _maximumContentHeight = nil - } - } - } - public var _maximumContentWidth: NSNumber? - public var maximumContentWidth: Double? { - get { - return _maximumContentWidth?.doubleValue - } - set { - if let newValue = newValue { - _maximumContentWidth = NSNumber.init(value: newValue) - } else { - _maximumContentWidth = nil - } - } - } - public var _footerHeight: NSNumber? - public var footerHeight: Double? { - get { - return _footerHeight?.doubleValue - } - set { - if let newValue = newValue { - _footerHeight = NSNumber.init(value: newValue) - } else { - _footerHeight = nil - } - } - } - public var _headerHeight: NSNumber? - public var headerHeight: Double? { - get { - return _headerHeight?.doubleValue - } - set { - if let newValue = newValue { - _headerHeight = NSNumber.init(value: newValue) - } else { - _headerHeight = nil - } - } - } - - override init(){ - super.init() - } - - override func parse(settings: [String: Any?]) -> PrintJobSettings { - let _ = super.parse(settings: settings) - if let marginsMap = settings["margins"] as? [String : Double] { - margins = UIEdgeInsets.fromMap(map: marginsMap) - } - return self - } - - override func getRealSettings(obj: PrintJobController?) -> [String: Any?] { - let realOptions: [String: Any?] = toMap() - return realOptions - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/ProxyManager.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/ProxyManager.swift deleted file mode 100644 index 47b07d401c..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/ProxyManager.swift +++ /dev/null @@ -1,248 +0,0 @@ -// -// ProxyManager.swift -// flutter_inappwebview -// - -import Foundation -import WebKit -import Flutter - -@available(iOS 17.0, *) -public class ProxyManager: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_proxycontroller" - - private var plugin: InAppWebViewFlutterPlugin? - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: ProxyManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger())) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? [String: Any] - switch call.method { - case "setProxyOverride": - if let args = arguments?["settings"] as? [String:Any?], - let settings = ProxySettings.fromMap(map: args) { - setProxyOverride(settings) - result(true) - } else { - result(false) - } - break - case "clearProxyOverride": - clearProxyOverride() - result(true) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func setProxyOverride(_ settings: ProxySettings) { - let proxyConfigurations = settings.toProxyConfigurations() - WKWebsiteDataStore.default().proxyConfigurations = proxyConfigurations - WKWebsiteDataStore.nonPersistent().proxyConfigurations = proxyConfigurations - } - - public func clearProxyOverride() { - WKWebsiteDataStore.default().proxyConfigurations = [] - WKWebsiteDataStore.nonPersistent().proxyConfigurations = [] - } - - public override func dispose() { - super.dispose() - plugin = nil - } - - deinit { - debugPrint("ProxyManager - dealloc") - dispose() - } -} - -@available(iOS 17.0, *) -public class ProxySettings { - var proxyRules: [ProxyRule] - - init( - proxyRules: [ProxyRule] - ) { - self.proxyRules = proxyRules - } - - public static func fromMap(map: [String:Any?]?) -> ProxySettings? { - guard let map = map else { - return nil - } - return ProxySettings( - proxyRules: (map["proxyRules"] as! [[String:Any?]]).map { ProxyRule.fromMap(map: $0)! } - ) - } - - public func toProxyConfigurations() -> [ProxyConfiguration] { - var proxyConfigurations: [ProxyConfiguration] = [] - for rule in proxyRules { - if let proxyConfiguration = rule.toProxyConfiguration() { - proxyConfigurations.append(proxyConfiguration) - } - } - return proxyConfigurations - } -} - -@available(iOS 17.0, *) -public class ProxyRule { - var url: String - var allowFailover: Bool? - var excludedDomains: [String]? - var matchDomains: [String]? - var username: String? - var password: String? - var relayHop1: ProxyRelayHop? - var relayHop2: ProxyRelayHop? - - init( - url: String, - allowFailover: Bool?, - excludedDomains: [String]?, - matchDomains: [String]?, - username: String?, - password: String?, - relayHop1: ProxyRelayHop?, - relayHop2: ProxyRelayHop? - ) { - self.url = url - self.allowFailover = allowFailover - self.excludedDomains = excludedDomains - self.matchDomains = matchDomains - self.username = username - self.password = password - self.relayHop1 = relayHop1 - self.relayHop2 = relayHop2 - } - - public static func fromMap(map: [String:Any?]?) -> ProxyRule? { - guard let map = map else { - return nil - } - return ProxyRule( - url: map["url"] as! String, - allowFailover: map["allowFailover"] as? Bool, - excludedDomains: map["excludedDomains"] as? [String], - matchDomains: map["matchDomains"] as? [String], - username: map["username"] as? String, - password: map["password"] as? String, - relayHop1: ProxyRelayHop.fromMap(map: map["relayHop1"] as? [String:Any?]), - relayHop2: ProxyRelayHop.fromMap(map: map["relayHop2"] as? [String:Any?]) - ) - } - - public func toProxyConfiguration() -> ProxyConfiguration? { - guard let endpointUrl = URL(string: url.contains("://") ? url : "http://" + url), - let port: NWEndpoint.Port = .init(rawValue: UInt16(endpointUrl.port ?? 80)), - let host = endpointUrl.host else { - return nil - } - - var endpointHost = NWEndpoint.Host(host) - if let ipv4 = IPv4Address(host) { - endpointHost = .ipv4(ipv4) - } else if let ipv6 = IPv6Address(host) { - endpointHost = .ipv6(ipv6) - } - let endpoint = NWEndpoint.hostPort(host: endpointHost, port: port) - var proxyConfiguration: ProxyConfiguration - let proxyRelayHops: [ProxyRelayHop] = [relayHop1, relayHop2].filter({ $0 != nil }).map({ $0! }) - if !proxyRelayHops.isEmpty { - proxyConfiguration = ProxyConfiguration(relayHops: proxyRelayHops.compactMap({ $0.toRelayHop() })) - } else { - proxyConfiguration = endpointUrl.scheme?.lowercased() == "socks5" ? - ProxyConfiguration(socksv5Proxy: endpoint) : - ProxyConfiguration(httpCONNECTProxy: endpoint, tlsOptions: endpointUrl.scheme?.lowercased() == "https" ? .init() : nil) - } - - if let allowFailover = allowFailover { - proxyConfiguration.allowFailover = allowFailover - } - if let excludedDomains = excludedDomains { - proxyConfiguration.excludedDomains = excludedDomains - } - if let matchDomains = matchDomains { - proxyConfiguration.matchDomains = matchDomains - } - if let username = username, let password = password { - proxyConfiguration.applyCredential(username: username, password: password) - } - return proxyConfiguration - } -} - -@available(iOS 17.0, *) -public class ProxyRelayHop { - var http3RelayEndpoint: String? - var http2RelayEndpoint: String? - var additionalHTTPHeaders: [String:String]? - - init( - http3RelayEndpoint: String, - http2RelayEndpoint: String?, - additionalHTTPHeaders: [String:String]? - ) { - self.http3RelayEndpoint = http3RelayEndpoint - self.http2RelayEndpoint = http2RelayEndpoint - self.additionalHTTPHeaders = additionalHTTPHeaders - } - - init( - http2RelayEndpoint: String, - additionalHTTPHeaders: [String:String]? - ) { - self.http2RelayEndpoint = http2RelayEndpoint - self.additionalHTTPHeaders = additionalHTTPHeaders - } - - public static func fromMap(map: [String:Any?]?) -> ProxyRelayHop? { - guard let map = map else { - return nil - } - let http3RelayEndpoint = map["http3RelayEndpoint"] as? String - let http2RelayEndpoint = map["http2RelayEndpoint"] as? String - let additionalHTTPHeaders = map["additionalHTTPHeaders"] as? [String:String] - if http3RelayEndpoint == nil, http2RelayEndpoint == nil { - return nil - } - if http3RelayEndpoint != nil { - return ProxyRelayHop( - http3RelayEndpoint: http3RelayEndpoint!, - http2RelayEndpoint: http2RelayEndpoint, - additionalHTTPHeaders: additionalHTTPHeaders - ) - } - return ProxyRelayHop( - http2RelayEndpoint: http2RelayEndpoint!, - additionalHTTPHeaders: additionalHTTPHeaders - ) - } - - public func toRelayHop() -> ProxyConfiguration.RelayHop? { - if let http3RelayEndpoint = http3RelayEndpoint, - let url = URL(string: http3RelayEndpoint) { - var http2Endpoint: NWEndpoint? = nil - if let http2RelayEndpoint = http2RelayEndpoint, - let url2 = URL(string: http2RelayEndpoint) { - http2Endpoint = NWEndpoint.url(url2) - } - return ProxyConfiguration.RelayHop(http3RelayEndpoint: NWEndpoint.url(url), - http2RelayEndpoint: http2Endpoint, - additionalHTTPHeaderFields: additionalHTTPHeaders ?? [:]) - } - if let http2RelayEndpoint = http2RelayEndpoint, - let url = URL(string: http2RelayEndpoint) { - return ProxyConfiguration.RelayHop(http2RelayEndpoint: NWEndpoint.url(url), - additionalHTTPHeaderFields: additionalHTTPHeaders ?? [:]) - } - return nil - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PullToRefresh/PullToRefreshChannelDelegate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PullToRefresh/PullToRefreshChannelDelegate.swift deleted file mode 100644 index 250c831f18..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PullToRefresh/PullToRefreshChannelDelegate.swift +++ /dev/null @@ -1,110 +0,0 @@ -// -// PullToRefreshChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 05/05/22. -// - -import Foundation -import UIKit -import Flutter - -public class PullToRefreshChannelDelegate: ChannelDelegate { - private weak var pullToRefreshControl: PullToRefreshControl? - - public init(pullToRefreshControl: PullToRefreshControl, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.pullToRefreshControl = pullToRefreshControl - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "setEnabled": - if let pullToRefreshView = pullToRefreshControl { - let enabled = arguments!["enabled"] as! Bool - if enabled { - pullToRefreshView.delegate?.enablePullToRefresh() - } else { - pullToRefreshView.delegate?.disablePullToRefresh() - } - result(true) - } else { - result(false) - } - break - case "isEnabled": - if let pullToRefreshView = pullToRefreshControl { - result(pullToRefreshView.delegate?.isPullToRefreshEnabled()) - } else { - result(false) - } - break - case "setRefreshing": - if let pullToRefreshView = pullToRefreshControl { - let refreshing = arguments!["refreshing"] as! Bool - if refreshing { - pullToRefreshView.beginRefreshing() - } else { - pullToRefreshView.endRefreshing() - } - result(true) - } else { - result(false) - } - break - case "isRefreshing": - if let pullToRefreshView = pullToRefreshControl { - result(pullToRefreshView.isRefreshing) - } else { - result(false) - } - break - case "setColor": - if let pullToRefreshView = pullToRefreshControl { - let color = arguments!["color"] as! String - pullToRefreshView.tintColor = UIColor(hexString: color) - result(true) - } else { - result(false) - } - break - case "setBackgroundColor": - if let pullToRefreshView = pullToRefreshControl { - let color = arguments!["color"] as! String - pullToRefreshView.backgroundColor = UIColor(hexString: color) - result(true) - } else { - result(false) - } - break - case "setStyledTitle": - if let pullToRefreshView = pullToRefreshControl { - let attributedTitleMap = arguments!["attributedTitle"] as! [String: Any?] - pullToRefreshView.attributedTitle = NSAttributedString.fromMap(map: attributedTitleMap) - result(true) - } else { - result(false) - } - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func onRefresh() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onRefresh", arguments: arguments) - } - - public override func dispose() { - super.dispose() - pullToRefreshControl = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PullToRefresh/PullToRefreshControl.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PullToRefresh/PullToRefreshControl.swift deleted file mode 100644 index 4124c3582a..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PullToRefresh/PullToRefreshControl.swift +++ /dev/null @@ -1,72 +0,0 @@ -// -// File.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 03/03/21. -// - -import Foundation -import Flutter - -public class PullToRefreshControl: UIRefreshControl, Disposable { - static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_" - - var plugin: InAppWebViewFlutterPlugin? - var channelDelegate: PullToRefreshChannelDelegate? - var settings: PullToRefreshSettings? - var shouldCallOnRefresh = false - var delegate: PullToRefreshDelegate? - - public init(plugin: InAppWebViewFlutterPlugin, id: Any, settings: PullToRefreshSettings?) { - super.init() - self.plugin = plugin - self.settings = settings - let channel = FlutterMethodChannel(name: PullToRefreshControl.METHOD_CHANNEL_NAME_PREFIX + String(describing: id), - binaryMessenger: plugin.registrar.messenger()) - self.channelDelegate = PullToRefreshChannelDelegate(pullToRefreshControl: self, channel: channel) - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - public func prepare() { - if let settings = settings { - if settings.enabled { - delegate?.enablePullToRefresh() - } - if let color = settings.color, !color.isEmpty { - tintColor = UIColor(hexString: color) - } - if let backgroundTintColor = settings.backgroundColor, !backgroundTintColor.isEmpty { - backgroundColor = UIColor(hexString: backgroundTintColor) - } - if let attributedTitleMap = settings.attributedTitle { - attributedTitle = NSAttributedString.fromMap(map: attributedTitleMap) - } - } - addTarget(self, action: #selector(updateShouldCallOnRefresh), for: .valueChanged) - } - - public func onRefresh() { - shouldCallOnRefresh = false - channelDelegate?.onRefresh() - } - - @objc public func updateShouldCallOnRefresh() { - shouldCallOnRefresh = true - } - - public func dispose() { - channelDelegate?.dispose() - channelDelegate = nil - removeTarget(self, action: #selector(updateShouldCallOnRefresh), for: .valueChanged) - delegate = nil - plugin = nil - } - - deinit { - debugPrint("PullToRefreshControl - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PullToRefresh/PullToRefreshDelegate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PullToRefresh/PullToRefreshDelegate.swift deleted file mode 100644 index 81d97a54e7..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PullToRefresh/PullToRefreshDelegate.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// PullToRefreshDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 04/03/21. -// - -import Foundation - -public protocol PullToRefreshDelegate { - func enablePullToRefresh() - func disablePullToRefresh() - func isPullToRefreshEnabled() -> Bool -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PullToRefresh/PullToRefreshSettings.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PullToRefresh/PullToRefreshSettings.swift deleted file mode 100644 index 2172bba1e3..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/PullToRefresh/PullToRefreshSettings.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// pullToRefreshSettings.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 03/03/21. -// - -import Foundation - -public class PullToRefreshSettings: ISettings { - - var enabled = true - var color: String? - var backgroundColor: String? - var attributedTitle: [String: Any?]? - - override init(){ - super.init() - } - - override func parse(settings: [String: Any?]) -> PullToRefreshSettings { - let _ = super.parse(settings: settings) - if let attributedTitle = settings["attributedTitle"] as? [String: Any?] { - self.attributedTitle = attributedTitle - } - return self - } - - override func getRealSettings(obj: PullToRefreshControl?) -> [String: Any?] { - let realSettings: [String: Any?] = toMap() - return realSettings - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Resources/PrivacyInfo.xcprivacy b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Resources/PrivacyInfo.xcprivacy deleted file mode 100644 index 0eca193ea7..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Resources/PrivacyInfo.xcprivacy +++ /dev/null @@ -1,14 +0,0 @@ - - - - - NSPrivacyTrackingDomains - - NSPrivacyAccessedAPITypes - - NSPrivacyCollectedDataTypes - - NSPrivacyTracking - - - \ No newline at end of file diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Resources/WebView.storyboard b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Resources/WebView.storyboard deleted file mode 100755 index 51a8d4f4c9..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Resources/WebView.storyboard +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/SafariViewController/ChromeSafariBrowserManager.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/SafariViewController/ChromeSafariBrowserManager.swift deleted file mode 100755 index 6bd29f6dcf..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/SafariViewController/ChromeSafariBrowserManager.swift +++ /dev/null @@ -1,148 +0,0 @@ -// -// ChromeSafariBrowserManager.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 18/12/2019. -// - -import Flutter -import UIKit -import WebKit -import Foundation -import AVFoundation -import SafariServices - -public class ChromeSafariBrowserManager: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_chromesafaribrowser" - var plugin: InAppWebViewFlutterPlugin? - var browsers: [String: SafariViewController?] = [:] - var prewarmingTokens: [String: Any?] = [:] - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: ChromeSafariBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger())) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "open": - let id = arguments!["id"] as! String - let url = arguments!["url"] as! String - let settings = arguments!["settings"] as! [String: Any?] - let menuItemList = arguments!["menuItemList"] as! [[String: Any]] - open(id: id, url: url, settings: settings, menuItemList: menuItemList, result: result) - break - case "isAvailable": - if #available(iOS 9.0, *) { - result(true) - } else { - result(false) - } - break - case "clearWebsiteData": - if #available(iOS 16.0, *) { - SFSafariViewController.DataStore.default.clearWebsiteData { - result(true) - } - } else { - result(false) - } - case "prewarmConnections": - if #available(iOS 15.0, *) { - let stringURLs = arguments!["URLs"] as! [String] - var URLs: [URL] = [] - for stringURL in stringURLs { - if let url = URL(string: stringURL) { - URLs.append(url) - } - } - let prewarmingToken = SFSafariViewController.prewarmConnections(to: URLs) - let prewarmingTokenId = NSUUID().uuidString - prewarmingTokens[prewarmingTokenId] = prewarmingToken - result([ - "id": prewarmingTokenId - ]) - } else { - result(nil) - } - case "invalidatePrewarmingToken": - if #available(iOS 15.0, *) { - let prewarmingToken = arguments!["prewarmingToken"] as! [String:Any?] - if let prewarmingTokenId = prewarmingToken["id"] as? String, - let prewarmingToken = prewarmingTokens[prewarmingTokenId] as? SFSafariViewController.PrewarmingToken? { - prewarmingToken?.invalidate() - prewarmingTokens[prewarmingTokenId] = nil - } - result(true) - } else { - result(false) - } - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func open(id: String, url: String, settings: [String: Any?], menuItemList: [[String: Any]], result: @escaping FlutterResult) { - let absoluteUrl = URL(string: url)!.absoluteURL - - if #available(iOS 9.0, *), let plugin = plugin { - - if let flutterViewController = UIApplication.shared.visibleViewController { - // flutterViewController could be casted to FlutterViewController if needed - - let safariSettings = SafariBrowserSettings() - let _ = safariSettings.parse(settings: settings) - - let safari: SafariViewController - - if #available(iOS 11.0, *) { - let config = SFSafariViewController.Configuration() - safari = SafariViewController(plugin: plugin, id: id, url: absoluteUrl, configuration: config, - menuItemList: menuItemList, safariSettings: safariSettings) - } else { - // Fallback on earlier versions - safari = SafariViewController(plugin: plugin, id: id, url: absoluteUrl, entersReaderIfAvailable: safariSettings.entersReaderIfAvailable, - menuItemList: menuItemList, safariSettings: safariSettings) - } - - safari.prepareSafariBrowser() - - flutterViewController.present(safari, animated: true) { - result(true) - } - - browsers[id] = safari - } - return - } - - result(FlutterError.init(code: "ChromeSafariBrowserManager", message: "SafariViewController is not available!", details: nil)) - } - - public override func dispose() { - super.dispose() - let browserValues = browsers.values - browserValues.forEach { (browser: SafariViewController?) in - browser?.close(result: nil) - browser?.dispose() - } - browsers.removeAll() - if #available(iOS 15.0, *) { - let prewarmingTokensValues = prewarmingTokens.values - prewarmingTokensValues.forEach { (prewarmingToken: Any?) in - if let prewarmingToken = prewarmingToken as? SFSafariViewController.PrewarmingToken? { - prewarmingToken?.invalidate() - } - } - prewarmingTokens.removeAll() - } - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/SafariViewController/CustomUIActivity.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/SafariViewController/CustomUIActivity.swift deleted file mode 100644 index 559c264c3b..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/SafariViewController/CustomUIActivity.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// CustomUIActivity.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 08/05/22. -// - -import Foundation -import UIKit - -class CustomUIActivity: UIActivity { - var plugin: InAppWebViewFlutterPlugin - var viewId: String - var id: Int64 - var url: URL - var title: String? - var type: UIActivity.ActivityType? - var label: String? - var image: UIImage? - - init(plugin: InAppWebViewFlutterPlugin, viewId: String, id: Int64, url: URL, title: String?, label: String?, type: UIActivity.ActivityType?, image: UIImage?) { - self.plugin = plugin - self.viewId = viewId - self.id = id - self.url = url - self.title = title - self.label = label - self.type = type - self.image = image - } - - override class var activityCategory: UIActivity.Category { - return .action - } - - override var activityType: UIActivity.ActivityType? { - return type - } - - override var activityTitle: String? { - return label - } - - override var activityImage: UIImage? { - return image - } - - override func canPerform(withActivityItems activityItems: [Any]) -> Bool { - return true - } - - override func perform() { - let browser = plugin.chromeSafariBrowserManager?.browsers[viewId] - browser??.channelDelegate?.onItemActionPerform(id: id, url: url, title: title) - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/SafariViewController/SafariBrowserSettings.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/SafariViewController/SafariBrowserSettings.swift deleted file mode 100755 index d7ec25ebc9..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/SafariViewController/SafariBrowserSettings.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// SafariBrowserOptions.swift -// flutter_inappwebview -// -// Created by Lorenzo on 26/09/18. -// - -import Foundation - -@available(iOS 9.0, *) -@objcMembers -public class SafariBrowserSettings: ISettings { - - var entersReaderIfAvailable = false - var barCollapsingEnabled = false - var dismissButtonStyle = 0 //done - var preferredBarTintColor: String? - var preferredControlTintColor: String? - var presentationStyle = 0 //fullscreen - var transitionStyle = 0 //coverVertical - var activityButton: [String:Any?]? - var eventAttribution: [String:Any?]? - - override init(){ - super.init() - } - - override func parse(settings: [String: Any?]) -> SafariBrowserSettings { - let _ = super.parse(settings: settings) - activityButton = settings["activityButton"] as? [String : Any?] - eventAttribution = settings["eventAttribution"] as? [String : Any?] - return self - } - - override func getRealSettings(obj: SafariViewController?) -> [String: Any?] { - var realOptions: [String: Any?] = toMap() - if let safariViewController = obj { - if #available(iOS 11.0, *) { - realOptions["entersReaderIfAvailable"] = safariViewController.configuration.entersReaderIfAvailable - realOptions["barCollapsingEnabled"] = safariViewController.configuration.barCollapsingEnabled - realOptions["dismissButtonStyle"] = safariViewController.dismissButtonStyle.rawValue - } - if #available(iOS 10.0, *) { - realOptions["preferredBarTintColor"] = safariViewController.preferredBarTintColor?.hexString - realOptions["preferredControlTintColor"] = safariViewController.preferredControlTintColor?.hexString - } - realOptions["presentationStyle"] = safariViewController.modalPresentationStyle.rawValue - realOptions["transitionStyle"] = safariViewController.modalTransitionStyle.rawValue - } - return realOptions - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/SafariViewController/SafariViewController.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/SafariViewController/SafariViewController.swift deleted file mode 100755 index 736c55834b..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/SafariViewController/SafariViewController.swift +++ /dev/null @@ -1,142 +0,0 @@ -// -// SafariViewController.swift -// flutter_inappwebview -// -// Created by Lorenzo on 25/09/18. -// - -import Foundation -import SafariServices -import Flutter - -@available(iOS 9.0, *) -public class SafariViewController: SFSafariViewController, SFSafariViewControllerDelegate, Disposable { - static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_chromesafaribrowser_" - var channelDelegate: SafariViewControllerChannelDelegate? - var safariSettings: SafariBrowserSettings - var id: String - var plugin: InAppWebViewFlutterPlugin? - var menuItemList: [[String: Any]] = [] - - @available(iOS 11.0, *) - public init(plugin: InAppWebViewFlutterPlugin, id: String, url: URL, configuration: SFSafariViewController.Configuration, menuItemList: [[String: Any]] = [], safariSettings: SafariBrowserSettings) { - self.id = id - self.plugin = plugin - self.menuItemList = menuItemList - self.safariSettings = safariSettings - SafariViewController.prepareConfig(configuration: configuration, safariSettings: safariSettings) - super.init(url: url, configuration: configuration) - let channel = FlutterMethodChannel(name: SafariViewController.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: plugin.registrar.messenger()) - self.channelDelegate = SafariViewControllerChannelDelegate(safariViewController: self, channel: channel) - self.delegate = self - } - - public init(plugin: InAppWebViewFlutterPlugin, id: String, url: URL, entersReaderIfAvailable: Bool, menuItemList: [[String: Any]] = [], safariSettings: SafariBrowserSettings) { - self.id = id - self.plugin = plugin - self.menuItemList = menuItemList - self.safariSettings = safariSettings - super.init(url: url, entersReaderIfAvailable: entersReaderIfAvailable) - let channel = FlutterMethodChannel(name: SafariViewController.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: plugin.registrar.messenger()) - self.channelDelegate = SafariViewControllerChannelDelegate(safariViewController: self, channel: channel) - self.delegate = self - } - - public static func prepareConfig(configuration: SFSafariViewController.Configuration, safariSettings: SafariBrowserSettings) { - configuration.entersReaderIfAvailable = safariSettings.entersReaderIfAvailable - configuration.barCollapsingEnabled = safariSettings.barCollapsingEnabled - if #available(iOS 15.0, *), let activityButtonMap = safariSettings.activityButton { - configuration.activityButton = .fromMap(map: activityButtonMap) - } - if #available(iOS 15.2, *), let eventAttributionMap = safariSettings.eventAttribution { - configuration.eventAttribution = .fromMap(map: eventAttributionMap) - } - } - - func prepareSafariBrowser() { - if #available(iOS 11.0, *) { - self.dismissButtonStyle = SFSafariViewController.DismissButtonStyle(rawValue: safariSettings.dismissButtonStyle)! - } - - if #available(iOS 10.0, *) { - if let preferredBarTintColor = safariSettings.preferredBarTintColor, !preferredBarTintColor.isEmpty { - self.preferredBarTintColor = UIColor(hexString: preferredBarTintColor) - } - if let preferredControlTintColor = safariSettings.preferredControlTintColor, !preferredControlTintColor.isEmpty { - self.preferredControlTintColor = UIColor(hexString: preferredControlTintColor) - } - } - - self.modalPresentationStyle = UIModalPresentationStyle(rawValue: safariSettings.presentationStyle)! - self.modalTransitionStyle = UIModalTransitionStyle(rawValue: safariSettings.transitionStyle)! - } - - public override func viewWillAppear(_ animated: Bool) { - // prepareSafariBrowser() - super.viewWillAppear(animated) - channelDelegate?.onOpened() - } - - public override func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - channelDelegate?.onClosed() - self.dispose() - } - - func close(result: FlutterResult?) { - dismiss(animated: true) - - // wait for the animation - DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(400), execute: {() -> Void in - if let result = result { - result(true) - } - }) - } - - public func safariViewControllerDidFinish(_ controller: SFSafariViewController) { - close(result: nil) - } - - public func safariViewController(_ controller: SFSafariViewController, - didCompleteInitialLoad didLoadSuccessfully: Bool) { - channelDelegate?.onCompletedInitialLoad(didLoadSuccessfully: didLoadSuccessfully) - } - - public func safariViewController(_ controller: SFSafariViewController, activityItemsFor URL: URL, title: String?) -> [UIActivity] { - guard let plugin = plugin else { - return [] - } - var uiActivities: [UIActivity] = [] - menuItemList.forEach { (menuItem) in - let activity = CustomUIActivity(plugin: plugin, viewId: id, id: menuItem["id"] as! Int64, url: URL, - title: title, label: menuItem["label"] as? String, type: nil, - image: .fromMap(map: menuItem["image"] as? [String:Any?])) - uiActivities.append(activity) - } - return uiActivities - } - - public func safariViewController(_ controller: SFSafariViewController, initialLoadDidRedirectTo url: URL) { - channelDelegate?.onInitialLoadDidRedirect(url: url) - } - - public func safariViewControllerWillOpenInBrowser(_ controller: SFSafariViewController) { - channelDelegate?.onWillOpenInBrowser() - } - - public func dispose() { - channelDelegate?.dispose() - channelDelegate = nil - delegate = nil - plugin?.chromeSafariBrowserManager?.browsers[id] = nil - plugin = nil - } - - deinit { - debugPrint("SafariViewController - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/SafariViewController/SafariViewControllerChannelDelegate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/SafariViewController/SafariViewControllerChannelDelegate.swift deleted file mode 100644 index e53d37fda9..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/SafariViewController/SafariViewControllerChannelDelegate.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// SafariViewControllerChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 05/05/22. -// - -import Foundation -import Flutter - -public class SafariViewControllerChannelDelegate: ChannelDelegate { - private weak var safariViewController: SafariViewController? - - public init(safariViewController: SafariViewController, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.safariViewController = safariViewController - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - // let arguments = call.arguments as? NSDictionary - switch call.method { - case "close": - if let safariViewController = safariViewController { - safariViewController.close(result: result) - } else { - result(false) - } - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func onOpened() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onOpened", arguments: arguments) - } - - public func onCompletedInitialLoad(didLoadSuccessfully: Bool) { - let arguments: [String: Any?] = [ - "didLoadSuccessfully": didLoadSuccessfully - ] - channel?.invokeMethod("onCompletedInitialLoad", arguments: arguments) - } - - public func onInitialLoadDidRedirect(url: URL) { - let arguments: [String: Any?] = [ - "url": url.absoluteString - ] - channel?.invokeMethod("onInitialLoadDidRedirect", arguments: arguments) - } - - public func onWillOpenInBrowser() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onWillOpenInBrowser", arguments: arguments) - } - - public func onClosed() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onClosed", arguments: arguments) - } - - public func onItemActionPerform(id: Int64, url: URL, title: String?) { - let arguments: [String: Any?] = [ - "id": id, - "url": url.absoluteString, - "title": title, - ] - channel?.invokeMethod("onItemActionPerform", arguments: arguments) - } - - public override func dispose() { - super.dispose() - safariViewController = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ActivityButton.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ActivityButton.swift deleted file mode 100644 index 85612318ba..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ActivityButton.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// ActivityButton.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 26/10/22. -// - -import Foundation -import SafariServices - -@available(iOS 15.0, *) -extension SFSafariViewController.ActivityButton { - public static func fromMap(map: [String:Any?]?) -> SFSafariViewController.ActivityButton? { - guard let map = map else { - return nil - } - if let templateImageMap = map["templateImage"] as? [String:Any?], - let templateImage = UIImage.fromMap(map: templateImageMap), - let extensionIdentifier = map["extensionIdentifier"] as? String { - return .init(templateImage: templateImage, extensionIdentifier: extensionIdentifier) - } - return nil - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/BaseCallbackResult.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/BaseCallbackResult.swift deleted file mode 100644 index aa79e499fd..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/BaseCallbackResult.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// BaseCallbackResult.swift -// shared-apple -// -// Created by Lorenzo Pichilli on 17/10/22. -// - -import Foundation - -public class BaseCallbackResult: CallbackResult { - - override init() { - super.init() - - self.success = { [weak self] (obj: Any?) in - let result: T? = self?.decodeResult(obj) - var shouldRunDefaultBehaviour = false - if let result = result { - shouldRunDefaultBehaviour = self?.nonNullSuccess(result) ?? shouldRunDefaultBehaviour - } else { - shouldRunDefaultBehaviour = self?.nullSuccess() ?? shouldRunDefaultBehaviour - } - if shouldRunDefaultBehaviour { - self?.defaultBehaviour(result) - } - } - - self.notImplemented = { [weak self] in - self?.defaultBehaviour(nil) - } - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/CGRect.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/CGRect.swift deleted file mode 100644 index 61cb7627f5..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/CGRect.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// CGRect.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/05/22. -// - -import Foundation - -extension CGRect { - public static func fromMap(map: [String: Double]) -> CGRect { - return CGRect(x: map["x"]!, y: map["y"]!, width: map["width"]!, height: map["height"]!) - } - - public func toMap () -> [String:Any?] { - return [ - "x": minX, - "y": minY, - "width": width, - "height": height - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/CGSize.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/CGSize.swift deleted file mode 100644 index 730861e798..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/CGSize.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// CGSize.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 28/10/22. -// - -import Foundation - -extension CGSize { - public static func fromMap(map: [String: Double]) -> CGSize { - return CGSize(width: map["width"]!, height: map["height"]!) - } - - public func toMap () -> [String:Any?] { - return [ - "width": width, - "height": height - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/CallbackResult.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/CallbackResult.swift deleted file mode 100644 index ea677c6b0c..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/CallbackResult.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// CallbackResult.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 06/05/22. -// - -import Foundation - -public class CallbackResult: MethodChannelResult { - public var notImplemented: () -> Void = {} - public var success: (Any?) -> Void = {_ in } - public var error: (String, String?, Any?) -> Void = {_,_,_ in } - public var nonNullSuccess: (T) -> Bool = {_ in true} - public var nullSuccess: () -> Bool = {true} - public var defaultBehaviour: (T?) -> Void = {_ in } - public var decodeResult: (Any?) -> T? = {_ in nil} -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ChannelDelegate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ChannelDelegate.swift deleted file mode 100644 index 90234abb27..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ChannelDelegate.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// ChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 04/05/22. -// - -import Foundation -import Flutter - -public class ChannelDelegate: FlutterMethodCallDelegate, Disposable { - var channel: FlutterMethodChannel? - - public init(channel: FlutterMethodChannel) { - super.init() - self.channel = channel - self.channel?.setMethodCallHandler(handle) - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - - } - - public func dispose() { - channel?.setMethodCallHandler(nil) - channel = nil - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ClientCertChallenge.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ClientCertChallenge.swift deleted file mode 100644 index f2381ee4a5..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ClientCertChallenge.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// ClientCertChallenge.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 15/02/21. -// - -import Foundation - -public class ClientCertChallenge: NSObject { - var protectionSpace: URLProtectionSpace! - - public init(fromChallenge: URLAuthenticationChallenge) { - protectionSpace = fromChallenge.protectionSpace - } - - public func toMap () -> [String:Any?] { - return [ - "protectionSpace": protectionSpace.toMap(), - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ClientCertResponse.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ClientCertResponse.swift deleted file mode 100644 index 6273db74ba..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ClientCertResponse.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// ClientCertResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation - -public class ClientCertResponse: NSObject { - var certificatePath: String - var certificatePassword: String? - var keyStoreType: String? - var action: Int? - - public init(certificatePath: String, certificatePassword: String? = nil, keyStoreType: String? = nil, action: Int? = nil) { - self.certificatePath = certificatePath - self.certificatePassword = certificatePassword - self.keyStoreType = keyStoreType - self.action = action - } - - public static func fromMap(map: [String:Any?]?) -> ClientCertResponse? { - guard let map = map else { - return nil - } - let certificatePath = map["certificatePath"] as! String - let certificatePassword = map["certificatePassword"] as? String - let keyStoreType = map["keyStoreType"] as? String - let action = map["action"] as? Int - return ClientCertResponse(certificatePath: certificatePath, certificatePassword: certificatePassword, keyStoreType: keyStoreType, action: action) - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/CreateWindowAction.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/CreateWindowAction.swift deleted file mode 100644 index f3b4681f6f..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/CreateWindowAction.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// CreateWindowAction.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation -import WebKit - -public class CreateWindowAction: NSObject { - var navigationAction: WKNavigationAction - var windowId: Int64 - var windowFeatures: WKWindowFeatures - var isDialog: Bool? - - public init(navigationAction: WKNavigationAction, windowId: Int64, windowFeatures: WKWindowFeatures, isDialog: Bool? = nil) { - self.navigationAction = navigationAction - self.windowId = windowId - self.windowFeatures = windowFeatures - self.isDialog = isDialog - } - - public func toMap () -> [String:Any?] { - var map = navigationAction.toMap() - map["windowId"] = windowId - map["windowFeatures"] = windowFeatures.toMap() - map["isDialog"] = isDialog - return map - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/CustomSchemeResponse.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/CustomSchemeResponse.swift deleted file mode 100644 index 50315520b0..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/CustomSchemeResponse.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// CustomSchemeResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation -import Flutter - -public class CustomSchemeResponse: NSObject { - var data: Data - var contentType: String - var contentEncoding: String - - public init(data: Data, contentType: String, contentEncoding: String) { - self.data = data - self.contentType = contentType - self.contentEncoding = contentEncoding - } - - public static func fromMap(map: [String:Any?]?) -> CustomSchemeResponse? { - guard let map = map else { - return nil - } - let data = map["data"] as! FlutterStandardTypedData - let contentType = map["contentType"] as! String - let contentEncoding = map["contentEncoding"] as! String - return CustomSchemeResponse(data: data.data, contentType: contentType, contentEncoding: contentEncoding) - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/Disposable.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/Disposable.swift deleted file mode 100644 index 0a34a94248..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/Disposable.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// Disposable.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 04/05/22. -// - -import Foundation - -public protocol Disposable { - func dispose() -> Void -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/DownloadStartRequest.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/DownloadStartRequest.swift deleted file mode 100644 index 808f9453ca..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/DownloadStartRequest.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// DownloadStartRequest.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 17/04/22. -// - -import Foundation - -public class DownloadStartRequest: NSObject { - var url: String - var userAgent: String? - var contentDisposition: String? - var mimeType: String? - var contentLength: Int64 - var suggestedFilename: String? - var textEncodingName: String? - - public init(url: String, userAgent: String?, contentDisposition: String?, - mimeType: String?, contentLength: Int64, - suggestedFilename: String?, textEncodingName: String?) { - self.url = url - self.userAgent = userAgent - self.contentDisposition = contentDisposition - self.mimeType = mimeType - self.contentLength = contentLength - self.suggestedFilename = suggestedFilename - self.textEncodingName = textEncodingName - } - - public func toMap () -> [String:Any?] { - return [ - "url": url, - "userAgent": userAgent, - "contentDisposition": contentDisposition, - "mimeType": mimeType, - "contentLength": contentLength, - "suggestedFilename": suggestedFilename, - "textEncodingName": textEncodingName - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/FlutterMethodCallDelegate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/FlutterMethodCallDelegate.swift deleted file mode 100755 index 244108c4c9..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/FlutterMethodCallDelegate.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// FlutterMethodCallDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 15/12/2019. -// - -import Foundation -import Flutter - -public class FlutterMethodCallDelegate: NSObject { - public override init() { - super.init() - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/FlutterMethodChannel.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/FlutterMethodChannel.swift deleted file mode 100644 index a7409d581e..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/FlutterMethodChannel.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// FlutterMethodChannel.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 06/05/22. -// - -import Foundation -import Flutter - -extension FlutterMethodChannel { - public func invokeMethod(_ method: String, arguments: Any, callback: MethodChannelResult) { - invokeMethod(method, arguments: arguments) {(result) -> Void in - if result is FlutterError { - let error = result as! FlutterError - callback.error(error.code, error.message, error.details) - } - else if (result as? NSObject) == FlutterMethodNotImplemented { - callback.notImplemented() - } - else { - callback.success(result) - } - } - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/HitTestResult.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/HitTestResult.swift deleted file mode 100644 index 53307789f0..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/HitTestResult.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// HitTestResult.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public enum HitTestResultType: Int { - case unknownType = 0 - case phoneType = 2 - case geoType = 3 - case emailType = 4 - case imageType = 5 - case srcAnchorType = 7 - case srcImageAnchorType = 8 - case editTextType = 9 -} - -public class HitTestResult: NSObject { - var type: HitTestResultType - var extra: String? - - public init(type: HitTestResultType, extra: String?) { - self.type = type - self.extra = extra - } - - public static func fromMap(map: [String:Any?]?) -> HitTestResult? { - guard let map = map else { - return nil - } - let type = HitTestResultType.init(rawValue: map["type"] as? Int ?? HitTestResultType.unknownType.rawValue) ?? HitTestResultType.unknownType - return HitTestResult(type: type, extra: map["extra"] as? String) - } - - public func toMap () -> [String:Any?] { - return [ - "type": type.rawValue, - "extra": extra, - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/HttpAuthResponse.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/HttpAuthResponse.swift deleted file mode 100644 index f77d3ab1c1..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/HttpAuthResponse.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// HttpAuthResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation - -public class HttpAuthResponse: NSObject { - var username: String - var password: String - var permanentPersistence: Bool - var action: Int? - - public init(username: String, password: String, permanentPersistence: Bool, action: Int? = nil) { - self.username = username - self.password = password - self.permanentPersistence = permanentPersistence - self.action = action - } - - public static func fromMap(map: [String:Any?]?) -> HttpAuthResponse? { - guard let map = map else { - return nil - } - let username = map["username"] as! String - let password = map["password"] as! String - let permanentPersistence = map["permanentPersistence"] as! Bool - let action = map["action"] as? Int - return HttpAuthResponse(username: username, password: password, permanentPersistence: permanentPersistence, action: action) - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/HttpAuthenticationChallenge.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/HttpAuthenticationChallenge.swift deleted file mode 100644 index b22a009234..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/HttpAuthenticationChallenge.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// HttpAuthenticationChallenge.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 15/02/21. -// - -import Foundation - -public class HttpAuthenticationChallenge: NSObject { - var protectionSpace: URLProtectionSpace! - var previousFailureCount: Int = 0 - var failureResponse: URLResponse? - var error: Error? - var proposedCredential: URLCredential? - - public init(fromChallenge: URLAuthenticationChallenge) { - protectionSpace = fromChallenge.protectionSpace - previousFailureCount = fromChallenge.previousFailureCount - failureResponse = fromChallenge.failureResponse - error = fromChallenge.error - proposedCredential = fromChallenge.proposedCredential - } - - public func toMap () -> [String:Any?] { - return [ - "protectionSpace": protectionSpace.toMap(), - "previousFailureCount": previousFailureCount, - "failureResponse": failureResponse?.toMap(), - "error": error?.localizedDescription, - "proposedCredential": proposedCredential?.toMap() - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/InAppBrowserMenuItem.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/InAppBrowserMenuItem.swift deleted file mode 100644 index c853c41098..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/InAppBrowserMenuItem.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// InAppBrowserMenuItem.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 21/05/23. -// - -import Foundation -import UIKit -import Flutter - -public class InAppBrowserMenuItem: NSObject { - var id: Int64 - var title: String - var order: Int64? - var icon: UIImage? - var iconColor: UIColor? - var showAsAction = false - - public init(id: Int64, title: String, order: Int64?, icon: UIImage?, iconColor: UIColor?, showAsAction: Bool) { - self.id = id - self.title = title - self.order = order - self.icon = icon - self.iconColor = iconColor - self.showAsAction = showAsAction - if #available(iOS 13.0, *), let icon = icon, let iconColor = iconColor { - icon.withTintColor(iconColor, renderingMode: .alwaysOriginal) - } - } - - public static func fromMap(map: [String:Any?]?) -> InAppBrowserMenuItem? { - guard let map = map else { - return nil - } - let id = map["id"] as! Int64 - let title = map["title"] as! String - let order = map["order"] as? Int64 - var icon = UIImage.fromMap(map: map["icon"] as? [String : Any?]) - if let data = map["icon"] as? FlutterStandardTypedData { - icon = UIImage(data: data.data) - } - var iconColor: UIColor? = nil - if let hexString = map["iconColor"] as? String { - iconColor = UIColor(hexString: hexString) - } - let showAsAction = map["showAsAction"] as! Bool - return InAppBrowserMenuItem(id: id, title: title, order: order, icon: icon, iconColor: iconColor, showAsAction: showAsAction) - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/JavaScriptHandlerFunctionData.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/JavaScriptHandlerFunctionData.swift deleted file mode 100644 index 5816ecffda..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/JavaScriptHandlerFunctionData.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// JavaScriptHandlerFunctionData.swift -// Pods -// -// Created by Lorenzo Pichilli on 27/10/24. -// - -import Foundation - -public class JavaScriptHandlerFunctionData: NSObject { - var args: String - var isMainFrame: Bool - var origin: String - var requestUrl: String - - public init(args: String, isMainFrame: Bool, origin: String, requestUrl: String) { - self.args = args - self.isMainFrame = isMainFrame - self.origin = origin - self.requestUrl = requestUrl - } - - public static func fromMap(map: [String:Any?]?) -> JavaScriptHandlerFunctionData? { - guard let map = map else { - return nil - } - - return JavaScriptHandlerFunctionData( - args: map["args"] as! String, - isMainFrame: map["isMainFrame"] as! Bool, - origin: map["origin"] as! String, - requestUrl: map["requestUrl"] as! String - ) - } - - public func toMap () -> [String:Any?] { - return [ - "args": args, - "isMainFrame": isMainFrame, - "origin": origin, - "requestUrl": requestUrl - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/JsAlertResponse.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/JsAlertResponse.swift deleted file mode 100644 index 3e6b3e7883..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/JsAlertResponse.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// JsAlertResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 06/05/22. -// - -import Foundation - -public class JsAlertResponse: NSObject { - var message: String - var confirmButtonTitle: String - var handledByClient: Bool - var action: Int? - - public init(message: String, confirmButtonTitle: String, handledByClient: Bool, action: Int? = nil) { - self.message = message - self.confirmButtonTitle = confirmButtonTitle - self.handledByClient = handledByClient - self.action = action - } - - public static func fromMap(map: [String:Any?]?) -> JsAlertResponse? { - guard let map = map else { - return nil - } - let message = map["message"] as! String - let confirmButtonTitle = map["confirmButtonTitle"] as! String - let handledByClient = map["handledByClient"] as! Bool - let action = map["action"] as? Int - return JsAlertResponse(message: message, confirmButtonTitle: confirmButtonTitle, handledByClient: handledByClient, action: action) - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/JsConfirmResponse.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/JsConfirmResponse.swift deleted file mode 100644 index 76bfbe20e3..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/JsConfirmResponse.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// JsConfirmResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation - -public class JsConfirmResponse: NSObject { - var message: String - var confirmButtonTitle: String - var cancelButtonTitle: String - var handledByClient: Bool - var action: Int? - - public init(message: String, confirmButtonTitle: String, cancelButtonTitle: String, handledByClient: Bool, action: Int? = nil) { - self.message = message - self.confirmButtonTitle = confirmButtonTitle - self.cancelButtonTitle = cancelButtonTitle - self.handledByClient = handledByClient - self.action = action - } - - public static func fromMap(map: [String:Any?]?) -> JsConfirmResponse? { - guard let map = map else { - return nil - } - let message = map["message"] as! String - let confirmButtonTitle = map["confirmButtonTitle"] as! String - let cancelButtonTitle = map["cancelButtonTitle"] as! String - let handledByClient = map["handledByClient"] as! Bool - let action = map["action"] as? Int - return JsConfirmResponse(message: message, confirmButtonTitle: confirmButtonTitle, cancelButtonTitle: cancelButtonTitle, handledByClient: handledByClient, action: action) - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/JsPromptResponse.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/JsPromptResponse.swift deleted file mode 100644 index 5c40b49279..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/JsPromptResponse.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// JsPromptResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation - -public class JsPromptResponse: NSObject { - var message: String - var defaultValue: String - var confirmButtonTitle: String - var cancelButtonTitle: String - var handledByClient: Bool - var value: String? - var action: Int? - - public init(message: String, defaultValue: String, confirmButtonTitle: String, cancelButtonTitle: String, handledByClient: Bool, value: String? = nil, action: Int? = nil) { - self.message = message - self.defaultValue = defaultValue - self.confirmButtonTitle = confirmButtonTitle - self.cancelButtonTitle = cancelButtonTitle - self.handledByClient = handledByClient - self.value = value - self.action = action - } - - public static func fromMap(map: [String:Any?]?) -> JsPromptResponse? { - guard let map = map else { - return nil - } - let message = map["message"] as! String - let defaultValue = map["defaultValue"] as! String - let confirmButtonTitle = map["confirmButtonTitle"] as! String - let cancelButtonTitle = map["cancelButtonTitle"] as! String - let handledByClient = map["handledByClient"] as! Bool - let value = map["value"] as? String - let action = map["action"] as? Int - return JsPromptResponse(message: message, defaultValue: defaultValue, confirmButtonTitle: confirmButtonTitle, cancelButtonTitle: cancelButtonTitle, - handledByClient: handledByClient, value: value, action: action) - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/MethodChannelResult.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/MethodChannelResult.swift deleted file mode 100644 index d1555e3939..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/MethodChannelResult.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// MethodChannelResult.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 06/05/22. -// - -import Foundation - -public protocol MethodChannelResult { - var success: (_ obj: Any?) -> Void { get set } - var error: (_ code: String, _ message: String?, _ details: Any?) -> Void { get set } - var notImplemented: () -> Void { get set } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/NSAttributedString.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/NSAttributedString.swift deleted file mode 100644 index 7bba5cca24..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/NSAttributedString.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// NSAttributedString.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 05/03/21. -// - -import Foundation -import UIKit - -extension NSAttributedString { - public static func fromMap(map: [String:Any?]?) -> NSAttributedString? { - guard let map = map, let string = map["string"] as? String else { - return nil - } - - var attributes: [NSAttributedString.Key : Any] = [:] - - if let backgroundColor = map["backgroundColor"] as? String { - attributes[.backgroundColor] = UIColor(hexString: backgroundColor) - } - if let baselineOffset = map["baselineOffset"] as? Double { - attributes[.baselineOffset] = baselineOffset - } - if let expansion = map["expansion"] as? Double { - attributes[.expansion] = expansion - } - if let foregroundColor = map["foregroundColor"] as? String { - attributes[.foregroundColor] = UIColor(hexString: foregroundColor) - } - if let kern = map["kern"] as? Double { - attributes[.kern] = kern - } - if let ligature = map["ligature"] as? Int64 { - attributes[.ligature] = ligature - } - if let obliqueness = map["obliqueness"] as? Double { - attributes[.obliqueness] = obliqueness - } - if let strikethroughColor = map["strikethroughColor"] as? String { - attributes[.strikethroughColor] = UIColor(hexString: strikethroughColor) - } - if let strikethroughStyle = map["strikethroughStyle"] as? Int64 { - attributes[.strikethroughStyle] = strikethroughStyle - } - if let strokeColor = map["strokeColor"] as? String { - attributes[.strokeColor] = UIColor(hexString: strokeColor) - } - if let strokeWidth = map["strokeWidth"] as? Double { - attributes[.strokeWidth] = strokeWidth - } - if let textEffect = map["textEffect"] as? String { - attributes[.textEffect] = textEffect - } - if let underlineColor = map["underlineColor"] as? String { - attributes[.underlineColor] = UIColor(hexString: underlineColor) - } - if let underlineStyle = map["underlineStyle"] as? Int64 { - attributes[.underlineStyle] = underlineStyle - } - - return NSAttributedString(string: string, attributes: attributes) - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/PermissionRequest.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/PermissionRequest.swift deleted file mode 100644 index a286a3f32b..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/PermissionRequest.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// PermissionRequest.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 21/04/22. -// - -import Foundation -import WebKit - -public class PermissionRequest: NSObject { - var origin: String - var resources: [StringOrInt] - var frame: WKFrameInfo - - public init(origin: String, resources: [StringOrInt], frame: WKFrameInfo) { - self.origin = origin - self.resources = resources - self.frame = frame - } - - public func toMap () -> [String:Any?] { - return [ - "origin": origin, - "resources": resources, - "frame": frame.toMap() - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/PermissionResponse.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/PermissionResponse.swift deleted file mode 100644 index 171817bbc3..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/PermissionResponse.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// PermissionResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation - -public class PermissionResponse: NSObject { - var resources: [Any] - var action: Int? - - public init(resources: [Any], action: Int? = nil) { - self.resources = resources - self.action = action - } - - public static func fromMap(map: [String:Any?]?) -> PermissionResponse? { - guard let map = map else { - return nil - } - let resources = map["resources"] as! [Any] - let action = map["action"] as? Int - return PermissionResponse(resources: resources, action: action) - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/PluginScript.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/PluginScript.swift deleted file mode 100644 index 5917027416..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/PluginScript.swift +++ /dev/null @@ -1,117 +0,0 @@ -// -// PluginScript.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 17/02/21. -// - -import Foundation -import WebKit - -public class PluginScript: UserScript { - var requiredInAllContentWorlds = false - var messageHandlerNames: [String] = [] - - public override init(source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool) { - super.init(source: source, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly) - } - - public init(groupName: String, source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, allowedOriginRules: [String]?, requiredInAllContentWorlds: Bool = false, messageHandlerNames: [String] = []) { - super.init(groupName: groupName, source: source, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly, allowedOriginRules: allowedOriginRules) - self.requiredInAllContentWorlds = requiredInAllContentWorlds - self.messageHandlerNames = messageHandlerNames - } - - @available(iOS 14.0, *) - public override init(source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, in contentWorld: WKContentWorld) { - super.init(source: source, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly, in: contentWorld) - self.contentWorld = contentWorld - } - - @available(iOS 14.0, *) - public init(source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, in contentWorld: WKContentWorld, requiredInAllContentWorlds: Bool = false, messageHandlerNames: [String] = []) { - super.init(source: source, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly, in: contentWorld) - self.requiredInAllContentWorlds = requiredInAllContentWorlds - self.messageHandlerNames = messageHandlerNames - } - - @available(iOS 14.0, *) - public init(groupName: String, source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, in contentWorld: WKContentWorld, - allowedOriginRules: [String]?, requiredInAllContentWorlds: Bool = false, messageHandlerNames: [String] = []) { - super.init(groupName: groupName, source: source, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly, in: contentWorld, allowedOriginRules: allowedOriginRules) - self.requiredInAllContentWorlds = requiredInAllContentWorlds - self.messageHandlerNames = messageHandlerNames - } - - public func copyAndSet(groupName: String? = nil, - source: String? = nil, - injectionTime: WKUserScriptInjectionTime? = nil, - forMainFrameOnly: Bool? = nil, - requiredInAllContentWorlds: Bool? = nil, - allowedOriginRules: [String]? = nil, - messageHandlerNames: [String]? = nil) -> PluginScript { - if #available(iOS 14.0, *) { - return PluginScript( - groupName: groupName ?? self.groupName!, - source: source ?? self.source, - injectionTime: injectionTime ?? self.injectionTime, - forMainFrameOnly: forMainFrameOnly ?? self.isForMainFrameOnly, - in: self.contentWorld, - allowedOriginRules: allowedOriginRules ?? self.allowedOriginRules, - requiredInAllContentWorlds: requiredInAllContentWorlds ?? self.requiredInAllContentWorlds, - messageHandlerNames: messageHandlerNames ?? self.messageHandlerNames - ) - } - return PluginScript( - groupName: groupName ?? self.groupName!, - source: source ?? self.source, - injectionTime: injectionTime ?? self.injectionTime, - forMainFrameOnly: forMainFrameOnly ?? self.isForMainFrameOnly, - allowedOriginRules: allowedOriginRules ?? self.allowedOriginRules, - requiredInAllContentWorlds: requiredInAllContentWorlds ?? self.requiredInAllContentWorlds, - messageHandlerNames: messageHandlerNames ?? self.messageHandlerNames - ) - } - - @available(iOS 14.0, *) - public func copyAndSet(groupName: String? = nil, - source: String? = nil, - injectionTime: WKUserScriptInjectionTime? = nil, - forMainFrameOnly: Bool? = nil, - contentWorld: WKContentWorld? = nil, - allowedOriginRules: [String]? = nil, - requiredInAllContentWorlds: Bool? = nil, - messageHandlerNames: [String]? = nil) -> PluginScript { - return PluginScript( - groupName: groupName ?? self.groupName!, - source: source ?? self.source, - injectionTime: injectionTime ?? self.injectionTime, - forMainFrameOnly: forMainFrameOnly ?? self.isForMainFrameOnly, - in: contentWorld ?? self.contentWorld, - allowedOriginRules: allowedOriginRules ?? self.allowedOriginRules, - requiredInAllContentWorlds: requiredInAllContentWorlds ?? self.requiredInAllContentWorlds, - messageHandlerNames: messageHandlerNames ?? self.messageHandlerNames - ) - } - - static func == (lhs: PluginScript, rhs: PluginScript) -> Bool { - if #available(iOS 14.0, *) { - return lhs.groupName == rhs.groupName && - lhs.source == rhs.source && - lhs.injectionTime == rhs.injectionTime && - lhs.isForMainFrameOnly == rhs.isForMainFrameOnly && - lhs.contentWorld == rhs.contentWorld && - lhs.allowedOriginRules == rhs.allowedOriginRules && - lhs.requiredInAllContentWorlds == rhs.requiredInAllContentWorlds && - lhs.messageHandlerNames == rhs.messageHandlerNames - } else { - return lhs.groupName == rhs.groupName && - lhs.source == rhs.source && - lhs.injectionTime == rhs.injectionTime && - lhs.isForMainFrameOnly == rhs.isForMainFrameOnly && - lhs.allowedOriginRules == rhs.allowedOriginRules && - lhs.requiredInAllContentWorlds == rhs.requiredInAllContentWorlds && - lhs.messageHandlerNames == rhs.messageHandlerNames - } - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/SecCertificate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/SecCertificate.swift deleted file mode 100644 index e7292f2272..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/SecCertificate.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// SecCertificate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation - -extension SecCertificate { - var data: Data { - let serverCertificateCFData = SecCertificateCopyData(self) - return serverCertificateCFData as Data - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ServerTrustAuthResponse.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ServerTrustAuthResponse.swift deleted file mode 100644 index 2a9980573f..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ServerTrustAuthResponse.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// ServerTrustAuthResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation - -public class ServerTrustAuthResponse: NSObject { - var action: Int? - - public init(action: Int? = nil) { - self.action = action - } - - public static func fromMap(map: [String:Any?]?) -> ServerTrustAuthResponse? { - guard let map = map else { - return nil - } - let action = map["action"] as? Int - return ServerTrustAuthResponse(action: action) - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ServerTrustChallenge.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ServerTrustChallenge.swift deleted file mode 100644 index 190c831b1d..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/ServerTrustChallenge.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// ServerTrustChallenge.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 15/02/21. -// - -import Foundation - -public class ServerTrustChallenge: NSObject { - var protectionSpace: URLProtectionSpace! - - public init(fromChallenge: URLAuthenticationChallenge) { - protectionSpace = fromChallenge.protectionSpace - } - - public func toMap () -> [String:Any?] { - return [ - "protectionSpace": protectionSpace.toMap() - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/Size2D.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/Size2D.swift deleted file mode 100644 index de13ffc21c..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/Size2D.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// Size.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 26/03/21. -// - -import Foundation - -public class Size2D: NSObject { - var width: Double - var height: Double - - public init(width: Double, height: Double) { - self.width = width - self.height = height - } - - public static func fromMap(map: [String:Any?]?) -> Size2D? { - guard let map = map else { - return nil - } - return Size2D( - width: map["width"] as? Double ?? -1.0, - height: map["height"] as? Double ?? -1.0 - ) - } - - public func toMap() -> [String:Any?] { - return [ - "width": width, - "height": height - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/SslCertificate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/SslCertificate.swift deleted file mode 100644 index 6b9d9a17fd..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/SslCertificate.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// SslCertificate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 15/02/21. -// - -import Foundation - -public class SslCertificate: NSObject { - var x509Certificate: Data - var issuedBy: Any? - var issuedTo: Any? - var validNotAfterDate: Any? - var validNotBeforeDate: Any? - - public init(x509Certificate: Data) { - self.x509Certificate = x509Certificate - } - - public func toMap () -> [String:Any?] { - return [ - "x509Certificate": x509Certificate, - "issuedBy": issuedBy, - "issuedTo": issuedTo, - "validNotAfterDate": validNotAfterDate, - "validNotBeforeDate": validNotBeforeDate - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/SslError.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/SslError.swift deleted file mode 100644 index 58e3cf94af..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/SslError.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// SslError.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 15/02/21. -// - -import Foundation - -public class SslError: NSObject { - var errorType: SecTrustResultType? - var message: String? - - public init(errorType: SecTrustResultType?) { - self.errorType = errorType - - var sslErrorMessage: String? = nil - switch errorType { - case .deny: - sslErrorMessage = "Indicates a user-configured deny; do not proceed." - break - case .fatalTrustFailure: - sslErrorMessage = "Indicates a trust failure which cannot be overridden by the user." - break - case .invalid: - sslErrorMessage = "Indicates an invalid setting or result." - break - case .otherError: - sslErrorMessage = "Indicates a failure other than that of trust evaluation." - break - case .recoverableTrustFailure: - sslErrorMessage = "Indicates a trust policy failure which can be overridden by the user." - break - case .unspecified: - sslErrorMessage = "Indicates the evaluation succeeded and the certificate is implicitly trusted, but user intent was not explicitly specified." - break - default: - sslErrorMessage = nil - } - - self.message = sslErrorMessage - } - - public func toMap () -> [String:Any?] { - return [ - "code": errorType?.rawValue, - "message": message - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/StringOrInt.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/StringOrInt.swift deleted file mode 100644 index f7cd40c734..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/StringOrInt.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// StringOrInt.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 21/04/22. -// - -import Foundation - -public protocol StringOrInt { } - -extension Int: StringOrInt { } -extension String: StringOrInt { } diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UIColor.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UIColor.swift deleted file mode 100644 index bdf530c0f1..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UIColor.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// UIColor.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import UIKit - -extension UIColor { - convenience init(hexString: String) { - let hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) - var int = UInt64() - Scanner(string: hex).scanHexInt64(&int) - let a, r, g, b: UInt64 - switch hex.count { - case 3: // RGB (12-bit) - (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) - case 6: // RGB (24-bit) - (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) - case 8: // ARGB (32-bit) - (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) - default: - (a, r, g, b) = (255, 0, 0, 0) - } - self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255) - } - - var hexString: String? { - var red: CGFloat = 0 - var green: CGFloat = 0 - var blue: CGFloat = 0 - var alpha: CGFloat = 0 - - let multiplier = CGFloat(255.999999) - - guard self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) else { - return nil - } - - if alpha == 1.0 { - return String( - format: "#%02lX%02lX%02lX", - Int(red * multiplier), - Int(green * multiplier), - Int(blue * multiplier) - ) - } - else { - return String( - format: "#%02lX%02lX%02lX%02lX", - Int(red * multiplier), - Int(green * multiplier), - Int(blue * multiplier), - Int(alpha * multiplier) - ) - } - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UIEdgeInsets.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UIEdgeInsets.swift deleted file mode 100644 index 6506d52910..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UIEdgeInsets.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// UIEdgeInsets.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 11/05/22. -// - -import Foundation -import UIKit - -extension UIEdgeInsets { - public static func fromMap(map: [String: Double]) -> UIEdgeInsets { - return UIEdgeInsets.init(top: map["top"]!, left: map["left"]!, bottom: map["bottom"]!, right: map["right"]!) - } - - public func toMap () -> [String:Any?] { - return [ - "top": top, - "right": self.right, - "bottom": bottom, - "left": self.left - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UIEventAttribution.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UIEventAttribution.swift deleted file mode 100644 index d0207f0139..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UIEventAttribution.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// UIEventAttribution.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 26/10/22. -// - -import Foundation -import UIKit - -@available(iOS 14.5, *) -extension UIEventAttribution { - public static func fromMap(map: [String:Any?]?) -> UIEventAttribution? { - guard let map = map else { - return nil - } - if let sourceIdentifier = map["sourceIdentifier"] as? UInt8, - let destinationURLString = map["destinationURL"] as? String, - let destinationURL = URL(string: destinationURLString), - let sourceDescription = map["sourceDescription"] as? String, - let purchaser = map["purchaser"] as? String { - return UIEventAttribution(sourceIdentifier: sourceIdentifier, - destinationURL: destinationURL, - sourceDescription: sourceDescription, - purchaser: purchaser) - } - return nil - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UIFindSession.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UIFindSession.swift deleted file mode 100644 index dbac46bc68..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UIFindSession.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// UIFindSession.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/10/22. -// - -import Foundation -import UIKit - -public class FindSession: NSObject { - var resultCount: Int - var highlightedResultIndex: Int - var searchResultDisplayStyle: Int - - public init(resultCount: Int, highlightedResultIndex: Int, searchResultDisplayStyle: Int) { - self.resultCount = resultCount - self.highlightedResultIndex = highlightedResultIndex - self.searchResultDisplayStyle = searchResultDisplayStyle - } - - @available(iOS 16.0, *) - public static func fromUIFindSession(uiFindSession: UIFindSession) -> FindSession { - return FindSession(resultCount: uiFindSession.resultCount, - highlightedResultIndex: uiFindSession.highlightedResultIndex, - searchResultDisplayStyle: uiFindSession.searchResultDisplayStyle.rawValue) - } - - public func toMap () -> [String:Any?] { - return [ - "resultCount": resultCount, - "highlightedResultIndex": highlightedResultIndex, - "searchResultDisplayStyle": searchResultDisplayStyle - ] - } -} - -@available(iOS 16.0, *) -extension UIFindSession { - public func toMap () -> [String:Any?] { - return [ - "resultCount": resultCount, - "highlightedResultIndex": highlightedResultIndex, - "searchResultDisplayStyle": searchResultDisplayStyle.rawValue - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UIImage.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UIImage.swift deleted file mode 100644 index 20405c95ef..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UIImage.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// UIImage.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 26/10/22. -// - -import Foundation -import Flutter - -extension UIImage { - public static func fromMap(map: [String:Any?]?) -> UIImage? { - guard let map = map else { - return nil - } - if let name = map["name"] as? String { - return UIImage(named: name) - } - if #available(iOS 13.0, *), let systemName = map["systemName"] as? String { - return UIImage(systemName: systemName) - } - if let data = map["data"] as? FlutterStandardTypedData { - return UIImage(data: data.data) - } - return nil - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/URLAuthenticationChallenge.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/URLAuthenticationChallenge.swift deleted file mode 100644 index 39b21fcec2..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/URLAuthenticationChallenge.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// URLAuthenticationChallenge.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation - -extension URLAuthenticationChallenge { - public func toMap () -> [String:Any?] { - return [ - "protectionSpace": protectionSpace.toMap(), - "previousFailureCount": previousFailureCount, - "failureResponse": failureResponse?.toMap(), - "error": error?.localizedDescription, - "proposedCredential": proposedCredential?.toMap(), - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/URLCredential.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/URLCredential.swift deleted file mode 100644 index 469f1e15a5..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/URLCredential.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// URLCredential.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation - -extension URLCredential { - public func toMap () -> [String:Any?] { - var x509Certificates: [Data] = [] - // certificates could be nil!!! - if certificates != nil { - for certificate in certificates { - x509Certificates.append((certificate as! SecCertificate).data) - } - } - return [ - "password": password, - "username": user, - "certificates": x509Certificates, - "persistence": persistence.rawValue - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/URLProtectionSpace.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/URLProtectionSpace.swift deleted file mode 100644 index 3d6b9022c7..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/URLProtectionSpace.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// URLProtectionSpace.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation - -extension URLProtectionSpace { - - var x509Certificate: Data? { - guard let serverTrust = serverTrust else { - return nil - } - - var secResult = SecTrustResultType.invalid - let secTrustEvaluateStatus = SecTrustEvaluate(serverTrust, &secResult); - - if secTrustEvaluateStatus == errSecSuccess, let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) { - return serverCertificate.data - } - return nil - } - - var sslCertificate: SslCertificate? { - var sslCertificate: SslCertificate? = nil - if let x509Certificate = x509Certificate { - sslCertificate = SslCertificate(x509Certificate: x509Certificate) - } - return sslCertificate - } - - var sslError: SslError? { - guard let serverTrust = serverTrust else { - return nil - } - - var secResult = SecTrustResultType.invalid - SecTrustEvaluate(serverTrust, &secResult); - - guard let sslErrorType = secResult != SecTrustResultType.proceed ? secResult : nil else { - return nil - } - - return SslError(errorType: sslErrorType) - } - - public func toMap () -> [String:Any?] { - return [ - "host": host, - "protocol": self.protocol, - "realm": realm, - "port": port, - "sslCertificate": sslCertificate?.toMap(), - "sslError": sslError?.toMap(), - "authenticationMethod": authenticationMethod, - "distinguishedNames": distinguishedNames, - "receivesCredentialSecurely": receivesCredentialSecurely, - "proxyType": proxyType - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/URLRequest.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/URLRequest.swift deleted file mode 100644 index b28a31726e..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/URLRequest.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// URLRequest.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import Flutter - -extension URLRequest { - public init(fromPluginMap: [String:Any?]) { - if let urlString = fromPluginMap["url"] as? String, let url = URL(string: urlString) { - self.init(url: url) - } else { - self.init(url: URL(string: "about:blank")!) - } - - if let method = fromPluginMap["method"] as? String { - httpMethod = method - } - if let body = fromPluginMap["body"] as? FlutterStandardTypedData { - httpBody = body.data - } - if let headers = fromPluginMap["headers"] as? [String:String] { - for (key, value) in headers { - setValue(value, forHTTPHeaderField: key) - } - } - if let _allowsCellularAccess = fromPluginMap["allowsCellularAccess"] as? Bool { - allowsCellularAccess = _allowsCellularAccess - } - if #available(iOS 13.0, *), let _allowsConstrainedNetworkAccess = fromPluginMap["allowsConstrainedNetworkAccess"] as? Bool { - allowsConstrainedNetworkAccess = _allowsConstrainedNetworkAccess - } - if #available(iOS 13.0, *), let _allowsExpensiveNetworkAccess = fromPluginMap["allowsExpensiveNetworkAccess"] as? Bool { - allowsExpensiveNetworkAccess = _allowsExpensiveNetworkAccess - } - if let _cachePolicy = fromPluginMap["cachePolicy"] as? Int { - cachePolicy = CachePolicy.init(rawValue: UInt(_cachePolicy)) ?? .useProtocolCachePolicy - } - if let _httpShouldHandleCookies = fromPluginMap["httpShouldHandleCookies"] as? Bool { - httpShouldHandleCookies = _httpShouldHandleCookies - } - if let _httpShouldUsePipelining = fromPluginMap["httpShouldUsePipelining"] as? Bool { - httpShouldUsePipelining = _httpShouldUsePipelining - } - if let _networkServiceType = fromPluginMap["networkServiceType"] as? Int { - networkServiceType = NetworkServiceType.init(rawValue: UInt(_networkServiceType)) ?? .default - } - if let _timeoutInterval = fromPluginMap["timeoutInterval"] as? Double { - timeoutInterval = _timeoutInterval - } - if let _mainDocumentURL = fromPluginMap["mainDocumentURL"] as? String { - mainDocumentURL = URL(string: _mainDocumentURL)! - } - if #available(iOS 14.5, *), let _assumesHTTP3Capable = fromPluginMap["assumesHTTP3Capable"] as? Bool { - assumesHTTP3Capable = _assumesHTTP3Capable - } - if #available(iOS 15.0, *), let attributionRawValue = fromPluginMap["attribution"] as? UInt, - let _attribution = URLRequest.Attribution(rawValue: attributionRawValue) { - attribution = _attribution - } - } - - public func toMap () -> [String:Any?] { - var _allowsConstrainedNetworkAccess: Bool? = nil - var _allowsExpensiveNetworkAccess: Bool? = nil - if #available(iOS 13.0, *) { - _allowsConstrainedNetworkAccess = allowsConstrainedNetworkAccess - _allowsExpensiveNetworkAccess = allowsExpensiveNetworkAccess - } - var _assumesHTTP3Capable: Bool? = nil - if #available(iOS 14.5, *) { - _assumesHTTP3Capable = assumesHTTP3Capable - } - var _attribution: UInt? = nil - if #available(iOS 15.0, *) { - _attribution = attribution.rawValue - } - return [ - "url": url?.absoluteString, - "method": httpMethod, - "headers": allHTTPHeaderFields, - "body": httpBody.map(FlutterStandardTypedData.init(bytes:)), - "allowsCellularAccess": allowsCellularAccess, - "allowsConstrainedNetworkAccess": _allowsConstrainedNetworkAccess, - "allowsExpensiveNetworkAccess": _allowsExpensiveNetworkAccess, - "cachePolicy": cachePolicy.rawValue, - "httpShouldHandleCookies": httpShouldHandleCookies, - "httpShouldUsePipelining": httpShouldUsePipelining, - "networkServiceType": networkServiceType.rawValue, - "timeoutInterval": timeoutInterval, - "mainDocumentURL": mainDocumentURL?.absoluteString, - "assumesHTTP3Capable": _assumesHTTP3Capable, - "attribution": _attribution - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/URLResponse.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/URLResponse.swift deleted file mode 100644 index 0a6a483547..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/URLResponse.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// URLResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation - -extension URLResponse { - public convenience init?(fromPluginMap: [String:Any?]) { - let url = URL(string: fromPluginMap["url"] as? String ?? "about:blank")! - let mimeType = fromPluginMap["mimeType"] as? String - let expectedContentLength = fromPluginMap["expectedContentLength"] as? Int64 ?? 0 - let textEncodingName = fromPluginMap["textEncodingName"] as? String - self.init(url: url, mimeType: mimeType, expectedContentLength: Int(expectedContentLength), textEncodingName: textEncodingName) - } - - public func toMap () -> [String:Any?] { - let httpResponse: HTTPURLResponse? = self as? HTTPURLResponse - return [ - "expectedContentLength": expectedContentLength, - "mimeType": mimeType, - "suggestedFilename": suggestedFilename, - "textEncodingName": textEncodingName, - "url": url?.absoluteString, - "headers": httpResponse?.allHeaderFields, - "statusCode": httpResponse?.statusCode - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UserScript.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UserScript.swift deleted file mode 100644 index c12160cb5b..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/UserScript.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// InAppWebViewUserScript.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation -import WebKit - -public class UserScript: WKUserScript { - var groupName: String? - var allowedOriginRules: [String]? - - private var contentWorldWrapper: Any? - @available(iOS 14.0, *) - var contentWorld: WKContentWorld { - get { - if let value = contentWorldWrapper as? WKContentWorld { - return value - } - return .page - } - set { contentWorldWrapper = newValue } - } - - public override init(source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool) { - super.init(source: source, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly) - } - - public init(groupName: String?, source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, allowedOriginRules: [String]?) { - super.init(source: UserScript.wrapSourceCodeAddChecks(source: source, allowedOriginRules: allowedOriginRules), injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly) - self.groupName = groupName - self.allowedOriginRules = allowedOriginRules - } - - @available(iOS 14.0, *) - public override init(source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, in contentWorld: WKContentWorld) { - super.init(source: source, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly, in: contentWorld) - self.contentWorld = contentWorld - } - - @available(iOS 14.0, *) - public init(groupName: String?, source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, in contentWorld: WKContentWorld, allowedOriginRules: [String]?) { - super.init(source: UserScript.wrapSourceCodeAddChecks(source: source, allowedOriginRules: allowedOriginRules), injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly, in: contentWorld) - self.groupName = groupName - self.contentWorld = contentWorld - self.allowedOriginRules = allowedOriginRules - } - - static private func wrapSourceCodeAddChecks(source: String, allowedOriginRules: [String]?) -> String { - var ifStatement = "if (" - if let allowedOriginRules = allowedOriginRules, !allowedOriginRules.contains("*") { - if allowedOriginRules.isEmpty { - // return empty source string if allowedOriginRules is an empty list. - // an empty list means that this UserScript is not allowed for any origin. - return "" - } - var jsRegExpArray = "[" - for allowedOriginRule in allowedOriginRules { - if jsRegExpArray.count > 1 { - jsRegExpArray += "," - } - jsRegExpArray += "new RegExp('\(allowedOriginRule.replacingOccurrences(of: "\'", with: "\\'"))')" - } - if jsRegExpArray.count > 1 { - jsRegExpArray += "]" - ifStatement += "\(jsRegExpArray).some(function(rx) { return rx.test(window.location.origin); })" - } - } - return ifStatement.count > 4 ? "\(ifStatement)) { \(source) }" : source - } - - public static func fromMap(map: [String:Any?]?, windowId: Int64?) -> UserScript? { - guard let map = map else { - return nil - } - - let contentWorldMap = map["contentWorld"] as? [String:Any?] - if #available(iOS 14.0, *), let contentWorldMap = contentWorldMap { - let contentWorld = WKContentWorld.fromMap(map: contentWorldMap, windowId: windowId)! - return UserScript( - groupName: map["groupName"] as? String, - source: map["source"] as! String, - injectionTime: WKUserScriptInjectionTime.init(rawValue: map["injectionTime"] as! Int) ?? .atDocumentStart, - forMainFrameOnly: map["forMainFrameOnly"] as! Bool, - in: contentWorld, - allowedOriginRules: map["allowedOriginRules"] as? [String] - ) - } - return UserScript( - groupName: map["groupName"] as? String, - source: map["source"] as! String, - injectionTime: WKUserScriptInjectionTime.init(rawValue: map["injectionTime"] as! Int) ?? .atDocumentStart, - forMainFrameOnly: map["forMainFrameOnly"] as! Bool, - allowedOriginRules: map["allowedOriginRules"] as? [String] - ) - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKContentWorld.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKContentWorld.swift deleted file mode 100644 index 9ebade3dcd..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKContentWorld.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// WKContentWorld.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import WebKit - -@available(iOS 14.0, *) -extension WKContentWorld { - // Workaround to create stored properties in an extension: - // https://valv0.medium.com/computed-properties-and-extensions-a-pure-swift-approach-64733768112c - - private static var _windowId = [String: Int64?]() - - var windowId: Int64? { - get { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - return WKContentWorld._windowId[tmpAddress] ?? nil - } - set(newValue) { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - WKContentWorld._windowId[tmpAddress] = newValue - } - } - - public static func fromMap(map: [String:Any?]?, windowId: Int64?) -> WKContentWorld? { - guard let map = map else { - return nil - } - var name = map["name"] as! String - name = windowId != nil && name != "page" ? - WKUserContentController.WINDOW_ID_PREFIX + String(windowId!) + "-" + name : - name - let contentWorld = Util.getContentWorld(name: name) - contentWorld.windowId = name != "page" ? windowId : nil - return contentWorld - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKFrameInfo.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKFrameInfo.swift deleted file mode 100644 index 042fe419e2..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKFrameInfo.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// WKFrameInfo.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import WebKit - -extension WKFrameInfo { - - public func toMap () -> [String:Any?] { - var securityOrigin: [String:Any?]? = nil - if #available(iOS 9.0, *) { - securityOrigin = self.securityOrigin.toMap() - } - // fix: self.request throws EXC_BREAKPOINT when coming from WKNavigationAction.sourceFrame - let request: URLRequest? = self.value(forKey: "request") as? URLRequest - return [ - "isMainFrame": isMainFrame, - "request": request?.toMap(), - "securityOrigin": securityOrigin - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKNavigationAction.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKNavigationAction.swift deleted file mode 100644 index 1fdc5c1713..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKNavigationAction.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// WKNavigationAction.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import WebKit - -extension WKNavigationAction { - public func toMap () -> [String:Any?] { - var shouldPerformDownload: Bool? = nil - if #available(iOS 14.5, *) { - shouldPerformDownload = self.shouldPerformDownload - } - return [ - "request": request.toMap(), - "isForMainFrame": targetFrame?.isMainFrame ?? false, - "hasGesture": nil, - "isRedirect": nil, - "navigationType": navigationType.rawValue, - "sourceFrame": sourceFrame.toMap(), - "targetFrame": targetFrame?.toMap(), - "shouldPerformDownload": shouldPerformDownload - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKNavigationResponse.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKNavigationResponse.swift deleted file mode 100644 index 0e6852919b..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKNavigationResponse.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// WKNavigationResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import WebKit - -extension WKNavigationResponse { - public func toMap () -> [String:Any?] { - return [ - "response": response.toMap(), - "isForMainFrame": isForMainFrame, - "canShowMIMEType": canShowMIMEType, - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKSecurityOrigin.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKSecurityOrigin.swift deleted file mode 100644 index a7e8c71439..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKSecurityOrigin.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// WKSecurityOrigin.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import WebKit - -@available(iOS 9.0, *) -extension WKSecurityOrigin { - public func toMap () -> [String:Any?] { - return [ - "host": host, - "port": port, - "protocol": self.protocol - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKUserContentController.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKUserContentController.swift deleted file mode 100644 index 83e235e071..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKUserContentController.swift +++ /dev/null @@ -1,375 +0,0 @@ -// -// UserContentController.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 17/02/21. -// - -import Foundation -import WebKit -import Collections - -extension WKUserContentController { - static var WINDOW_ID_PREFIX = "WINDOW-ID-" - - // Workaround to create stored properties in an extension: - // https://valv0.medium.com/computed-properties-and-extensions-a-pure-swift-approach-64733768112c - - @available(iOS 14.0, *) - private static var _contentWorlds = [String: Set]() - @available(iOS 14.0, *) - var contentWorlds: Set { - get { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - return WKUserContentController._contentWorlds[tmpAddress] ?? [] - } - set(newValue) { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - WKUserContentController._contentWorlds[tmpAddress] = newValue - } - } - - private static var _userOnlyScripts = [String: [WKUserScriptInjectionTime:OrderedSet]]() - var userOnlyScripts: [WKUserScriptInjectionTime:OrderedSet] { - get { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - return WKUserContentController._userOnlyScripts[tmpAddress] ?? [:] - } - set(newValue) { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - WKUserContentController._userOnlyScripts[tmpAddress] = newValue - } - } - - private static var _pluginScripts = [String: [WKUserScriptInjectionTime:OrderedSet]]() - var pluginScripts: [WKUserScriptInjectionTime:OrderedSet] { - get { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - return WKUserContentController._pluginScripts[tmpAddress] ?? [:] - } - set(newValue) { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - WKUserContentController._pluginScripts[tmpAddress] = newValue - } - } - - public func initialize () { - if #available(iOS 14.0, *) { - contentWorlds = Set([WKContentWorld.page]) - } - pluginScripts = [ - .atDocumentStart: [], - .atDocumentEnd: [], - ] - userOnlyScripts = [ - .atDocumentStart: [], - .atDocumentEnd: [], - ] - } - - public func dispose (windowId: Int64?) { - if windowId == nil { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - if #available(iOS 14.0, *) { - contentWorlds.removeAll() - WKUserContentController._contentWorlds.removeValue(forKey: tmpAddress) - } - pluginScripts.removeAll() - WKUserContentController._pluginScripts.removeValue(forKey: tmpAddress) - userOnlyScripts.removeAll() - WKUserContentController._userOnlyScripts.removeValue(forKey: tmpAddress) - } - else if #available(iOS 14.0, *), let windowId = windowId { - let contentWorldsToRemove = contentWorlds.filter({ $0.windowId == windowId }) - for contentWorld in contentWorldsToRemove { - contentWorlds.remove(contentWorld) - removeAllScriptMessageHandlers(from: contentWorld) - } - } - } - - public func sync(scriptMessageHandler: WKScriptMessageHandler) { - let pluginScriptsList = pluginScripts.compactMap({ $0.value }).joined() - for pluginScript in pluginScriptsList { - if !containsPluginScript(pluginScript: pluginScript) { - addUserScript(pluginScript) - for messageHandlerName in pluginScript.messageHandlerNames { - removeScriptMessageHandler(forName: messageHandlerName) - add(scriptMessageHandler, name: messageHandlerName) - } - } - if #available(iOS 14.0, *), pluginScript.requiredInAllContentWorlds { - for contentWorld in contentWorlds { - if !containsPluginScript(pluginScript: pluginScript, in: contentWorld) { - let pluginScriptWithContentWorld = pluginScript.copyAndSet(contentWorld: contentWorld) - addUserScript(pluginScriptWithContentWorld) - for messageHandlerName in pluginScriptWithContentWorld.messageHandlerNames { - removeScriptMessageHandler(forName: messageHandlerName, contentWorld: contentWorld) - add(scriptMessageHandler, contentWorld: contentWorld, name: messageHandlerName) - } - } - } - } - } - - let userOnlyScriptsList = userOnlyScripts.compactMap({ $0.value }).joined() - for userOnlyScript in userOnlyScriptsList { - if !userScripts.contains(userOnlyScript) { - addUserScript(userOnlyScript) - } - } - } - - public func addUserOnlyScript(_ userOnlyScript: UserScript) { - if #available(iOS 14.0, *) { - contentWorlds.insert(userOnlyScript.contentWorld) - } - userOnlyScripts[userOnlyScript.injectionTime]!.append(userOnlyScript) - } - - public func addUserOnlyScripts(_ userOnlyScripts: [UserScript]) { - for userOnlyScript in userOnlyScripts { - addUserOnlyScript(userOnlyScript) - } - } - - public func addPluginScript(_ pluginScript: PluginScript) { - if #available(iOS 14.0, *) { - contentWorlds.insert(pluginScript.contentWorld) - } - pluginScripts[pluginScript.injectionTime]!.append(pluginScript) - } - - public func addPluginScripts(_ pluginScripts: [PluginScript]) { - for pluginScript in pluginScripts { - addPluginScript(pluginScript) - } - } - - public func getPluginScriptsRequiredInAllContentWorlds() -> [PluginScript] { - return pluginScripts.compactMap({ $0.value }) - .joined() - .filter({ $0.injectionTime == .atDocumentStart && $0.requiredInAllContentWorlds }) - } - - @available(iOS 14.0, *) - public func generateCodeForScriptEvaluation(scriptMessageHandler: WKScriptMessageHandler, source: String, contentWorld: WKContentWorld) -> String { - let (inserted, _) = contentWorlds.insert(contentWorld) - if inserted { - var generatedCode = "" - let pluginScriptsRequired = getPluginScriptsRequiredInAllContentWorlds() - for pluginScript in pluginScriptsRequired { - generatedCode += pluginScript.source + "\n" - for messageHandlerName in pluginScript.messageHandlerNames { - removeScriptMessageHandler(forName: messageHandlerName, contentWorld: contentWorld) - add(scriptMessageHandler, contentWorld: contentWorld, name: messageHandlerName) - } - } - if let windowId = contentWorld.windowId { - generatedCode += "\(WindowIdJS.WINDOW_ID_VARIABLE_JS_SOURCE()) = \(String(windowId));\n" - } - return generatedCode + "\n" + source - } - return source - } - - public func removeUserOnlyScript(_ userOnlyScript: UserScript) { - userOnlyScripts[userOnlyScript.injectionTime]!.remove(userOnlyScript) - removeUserScript(scriptToRemove: userOnlyScript) - } - - public func removeUserOnlyScript(at index: Int, injectionTime: WKUserScriptInjectionTime) { - let scriptToRemove = userOnlyScripts[injectionTime]![index] - userOnlyScripts[injectionTime]!.remove(at: index) - removeUserScript(scriptToRemove: scriptToRemove) - } - - public func removeAllUserOnlyScripts() { - let allUserOnlyScripts = Array(userOnlyScripts.compactMap({ $0.value }).joined()) - - userOnlyScripts[.atDocumentStart]!.removeAll() - userOnlyScripts[.atDocumentEnd]!.removeAll() - - removeUserScripts(scriptsToRemove: allUserOnlyScripts) - } - - public func removePluginScript(_ pluginScript: PluginScript) { - pluginScripts[pluginScript.injectionTime]!.remove(pluginScript) - for messageHandlerName in pluginScript.messageHandlerNames { - removeScriptMessageHandler(forName: messageHandlerName) - if #available(iOS 14.0, *) { - for contentWorld in contentWorlds { - removeScriptMessageHandler(forName: messageHandlerName, contentWorld: contentWorld) - } - } - } - removeUserScript(scriptToRemove: pluginScript) - } - - public func removeAllPluginScripts() { - let allPluginScripts = Array(pluginScripts.compactMap({ $0.value }).joined()) - - pluginScripts[.atDocumentStart]!.removeAll() - pluginScripts[.atDocumentEnd]!.removeAll() - - removeUserScripts(scriptsToRemove: allPluginScripts) - } - - public func removeAllPluginScriptMessageHandlers() { - let allPluginScripts = pluginScripts.compactMap({ $0.value }).joined() - for pluginScript in allPluginScripts { - for messageHandlerName in pluginScript.messageHandlerNames { - removeScriptMessageHandler(forName: messageHandlerName) - } - } - if #available(iOS 14.0, *) { - removeAllScriptMessageHandlers() - for contentWorld in contentWorlds { - removeAllScriptMessageHandlers(from: contentWorld) - } - } - } - - @available(iOS 14.0, *) - public func resetContentWorlds(windowId: Int64?) { - let allUserOnlyScripts = userOnlyScripts.compactMap({ $0.value }).joined() - let contentWorldsFiltered = contentWorlds.filter({ $0.windowId == windowId && $0 != WKContentWorld.page }) - for contentWorld in contentWorldsFiltered { - var found = false - for script in allUserOnlyScripts { - if script.contentWorld == contentWorld { - found = true - break - } - } - if !found { - contentWorlds.remove(contentWorld) - } - } - } - - private func removeUserScript(scriptToRemove: WKUserScript, shouldAddPreviousScripts: Bool = true) -> Void { - // there isn't a way to remove a specific user script using WKUserContentController, - // so we remove all the user scripts and, then, we add them again without the one that has been removed - let userScripts = useCopyOfUserScripts() - - var userScriptsUpdated: [WKUserScript] = [] - for script in userScripts { - if script != scriptToRemove { - userScriptsUpdated.append(script) - } - } - - removeAllUserScripts() - - if shouldAddPreviousScripts { - for script in userScriptsUpdated { - addUserScript(script) - } - } - } - - private func removeUserScripts(scriptsToRemove: [WKUserScript], shouldAddPreviousScripts: Bool = true) -> Void { - // there isn't a way to remove a specific user script using WKUserContentController, - // so we remove all the user scripts and, then, we add them again without the one that has been removed - let userScripts = useCopyOfUserScripts() - - var userScriptsUpdated: [WKUserScript] = [] - for script in userScripts { - if !scriptsToRemove.contains(script) { - userScriptsUpdated.append(script) - } - } - - removeAllUserScripts() - - if shouldAddPreviousScripts { - for script in userScriptsUpdated { - addUserScript(script) - } - } - } - - public func removeUserOnlyScripts(with groupName: String, shouldAddPreviousScripts: Bool = true) -> Void { - let allUserOnlyScripts = userOnlyScripts.compactMap({ $0.value }).joined() - var scriptsToRemove: [UserScript] = [] - for script in allUserOnlyScripts { - if let scriptName = script.groupName, scriptName == groupName { - scriptsToRemove.append(script) - userOnlyScripts[script.injectionTime]!.remove(script) - } - } - removeUserScripts(scriptsToRemove: scriptsToRemove, shouldAddPreviousScripts: shouldAddPreviousScripts) - } - - public func removePluginScripts(with groupName: String, shouldAddPreviousScripts: Bool = true) -> Void { - let allPluginScripts = pluginScripts.compactMap({ $0.value }).joined() - var scriptsToRemove: [PluginScript] = [] - for script in allPluginScripts { - if let scriptName = script.groupName, scriptName == groupName { - scriptsToRemove.append(script) - pluginScripts[script.injectionTime]!.remove(script) - } - } - removeUserScripts(scriptsToRemove: scriptsToRemove, shouldAddPreviousScripts: shouldAddPreviousScripts) - } - - public func containsPluginScript(pluginScript: PluginScript) -> Bool { - let userScripts = useCopyOfUserScripts() - for script in userScripts { - if let script = script as? PluginScript, script == pluginScript { - return true - } - } - return false - } - - public func containsPluginScript(with groupName: String) -> Bool { - let userScripts = useCopyOfUserScripts() - for script in userScripts { - if let script = script as? PluginScript, script.groupName == groupName { - return true - } - } - return false - } - - @available(iOS 14.0, *) - public func containsPluginScript(pluginScript: PluginScript, in contentWorld: WKContentWorld) -> Bool { - let userScripts = useCopyOfUserScripts() - for script in userScripts { - if let script = script as? PluginScript, script == pluginScript, script.contentWorld == contentWorld { - return true - } - } - return false - } - - @available(iOS 14.0, *) - public func containsPluginScript(with groupName: String, in contentWorld: WKContentWorld) -> Bool { - let userScripts = useCopyOfUserScripts() - for script in userScripts { - if let script = script as? PluginScript, script.groupName == groupName, script.contentWorld == contentWorld { - return true - } - } - return false - } - - @available(iOS 14.0, *) - public func getContentWorlds(with windowId: Int64?) -> Set { - var contentWorldsFiltered = Set([WKContentWorld.page]) - let contentWorlds = Array(self.contentWorlds) - for contentWorld in contentWorlds { - if contentWorld.windowId == windowId { - contentWorldsFiltered.insert(contentWorld) - } - } - return contentWorldsFiltered - } - - // use a copy of self.userScripts to avoid EXC_BREAKPOINT at runtime if self.userScripts gets removed when another code is looping them - private func useCopyOfUserScripts() -> [WKUserScript] { - return Array(self.userScripts) - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKWindowFeatures.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKWindowFeatures.swift deleted file mode 100644 index 469e2be1d0..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WKWindowFeatures.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// WKWindowFeatures.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import WebKit - -extension WKWindowFeatures { - public func toMap () -> [String:Any?] { - return [ - "allowsResizing": allowsResizing, - "height": height, - "menuBarVisibility": menuBarVisibility, - "statusBarVisibility": statusBarVisibility, - "toolbarsVisibility": toolbarsVisibility, - "width": width, - "x": x, - "y": y - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebMessage.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebMessage.swift deleted file mode 100644 index cacc20e0c3..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebMessage.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// WebMessage.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/03/21. -// - -import Foundation -import Flutter - -public class WebMessage: NSObject, Disposable { - var data: Any? - var type: WebMessageType - var ports: [WebMessagePort]? - - var jsData: String { - var jsData: String = "null" - if let messageData = data { - if type == .arrayBuffer, let messageDataArrayBuffer = messageData as? FlutterStandardTypedData { - jsData = "new Uint8Array(\(Array(messageDataArrayBuffer.data))).buffer" - } else if let messageDataString = messageData as? String { - jsData = "'\(messageDataString.replacingOccurrences(of: "\'", with: "\\'"))'" - } - } - return jsData - } - - public init(data: Any?, type: WebMessageType, ports: [WebMessagePort]?) { - self.type = type - super.init() - self.data = data - self.ports = ports - } - - public static func fromMap(map: [String: Any?]) -> WebMessage { - let portMapList = map["ports"] as? [[String: Any?]] - var ports: [WebMessagePort]? = nil - if let portMapList = portMapList, !portMapList.isEmpty { - ports = [] - portMapList.forEach { (portMap) in - ports?.append(WebMessagePort.fromMap(map: portMap)) - } - } - - return WebMessage( - data: map["data"] as? Any, - type: WebMessageType.init(rawValue: map["type"] as! Int)!, - ports: ports) - } - - public func toMap () -> [String: Any?] { - return [ - "data": type == .arrayBuffer && data is [UInt8] ? Data(data as! [UInt8]) : data, - "type": type.rawValue - ] - } - - public func dispose() { - ports?.removeAll() - } - - deinit { - debugPrint("WebMessage - dealloc") - dispose() - } -} - -public enum WebMessageType: Int { - case string = 0 - case arrayBuffer = 1 -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebMessagePort.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebMessagePort.swift deleted file mode 100644 index 7cb2f3b58e..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebMessagePort.swift +++ /dev/null @@ -1,147 +0,0 @@ -// -// WebMessagePort.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/03/21. -// - -import Foundation - -public class WebMessagePort: NSObject { - var name: String - var index: Int64 - var webMessageChannelId: String - var webMessageChannel: WebMessageChannel? - var isClosed = false - var isTransferred = false - var isStarted = false - - public init(name: String, index: Int64, webMessageChannelId: String, webMessageChannel: WebMessageChannel?) { - self.name = name - self.index = index - self.webMessageChannelId = webMessageChannelId - super.init() - self.webMessageChannel = webMessageChannel - } - - public func setWebMessageCallback(completionHandler: ((Any?) -> Void)? = nil) throws { - if isClosed || isTransferred { - throw NSError(domain: "Port is already closed or transferred", code: 0) - } - self.isStarted = true - if let webMessageChannel = webMessageChannel, let webView = webMessageChannel.webView { - let index = name == "port1" ? 0 : 1 - webView.evaluateJavascript(source: """ - (function() { - var webMessageChannel = \(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())["\(webMessageChannel.id)"]; - if (webMessageChannel != null) { - webMessageChannel.\(self.name).onmessage = function (event) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onWebMessagePortMessageReceived', { - "webMessageChannelId": "\(webMessageChannel.id)", - "index": \(String(index)), - "message": { - "data": window.ArrayBuffer != null && event.data instanceof ArrayBuffer ? Array.from(new Uint8Array(event.data)) : (event.data != null ? event.data.toString() : null), - "type": window.ArrayBuffer != null && event.data instanceof ArrayBuffer ? 1 : 0 - } - }); - } - } - })(); - """) { (_) in - completionHandler?(nil) - } - } else { - completionHandler?(nil) - } - } - - public func postMessage(message: WebMessage, completionHandler: ((Any?) -> Void)? = nil) throws { - if isClosed || isTransferred { - throw NSError(domain: "Port is already closed or transferred", code: 0) - } - if let webMessageChannel = webMessageChannel, let webView = webMessageChannel.webView { - var portsString = "null" - if let ports = message.ports { - var portArrayString: [String] = [] - for port in ports { - if port == self { - throw NSError(domain: "Source port cannot be transferred", code: 0) - } - if port.isStarted { - throw NSError(domain: "Port is already started", code: 0) - } - if port.isClosed || port.isTransferred { - throw NSError(domain: "Port is already closed or transferred", code: 0) - } - port.isTransferred = true - portArrayString.append("\(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())['\(port.webMessageChannel!.id)'].\(port.name)") - } - portsString = "[" + portArrayString.joined(separator: ", ") + "]" - } - - let source = """ - (function() { - var webMessageChannel = \(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())["\(webMessageChannel.id)"]; - if (webMessageChannel != null) { - webMessageChannel.\(self.name).postMessage(\(message.jsData), \(portsString)); - } - })(); - """ - webView.evaluateJavascript(source: source) { (_) in - completionHandler?(nil) - } - } else { - completionHandler?(nil) - } - message.dispose() - } - - public func close(completionHandler: ((Any?) -> Void)? = nil) throws { - if isTransferred { - throw NSError(domain: "Port is already transferred", code: 0) - } - isClosed = true - if let webMessageChannel = webMessageChannel, let webView = webMessageChannel.webView { - let source = """ - (function() { - var webMessageChannel = \(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())["\(webMessageChannel.id)"]; - if (webMessageChannel != null) { - webMessageChannel.\(self.name).close(); - } - })(); - """ - webView.evaluateJavascript(source: source) { (_) in - completionHandler?(nil) - } - } else { - completionHandler?(nil) - } - } - - public static func fromMap(map: [String: Any?]) -> WebMessagePort { - let index = map["index"] as! Int64 - return WebMessagePort( - name: "port\(String(index + 1))", - index: index, - webMessageChannelId: map["webMessageChannelId"] as! String, - webMessageChannel: nil) - } - - public func toMap () -> [String: Any?] { - return [ - "name": name, - "index": index, - "webMessageChannelId": webMessageChannelId - ] - } - - public func dispose() { - isClosed = true - webMessageChannel = nil - } - - deinit { - debugPrint("WebMessagePort - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebResourceError.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebResourceError.swift deleted file mode 100644 index 3183944b47..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebResourceError.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// WebResourceError.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 01/05/22. -// - -import Foundation - -public class WebResourceError: NSObject { - var type: Int - var errorDescription: String - - public init(type: Int, errorDescription: String) { - self.type = type - self.errorDescription = errorDescription - } - - public func toMap () -> [String:Any?] { - return [ - "type": type, - "description": errorDescription - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebResourceRequest.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebResourceRequest.swift deleted file mode 100644 index ad7635c496..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebResourceRequest.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// WebResourceRequest.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 01/05/22. -// - -import Foundation -import WebKit - -public class WebResourceRequest: NSObject { - var url: URL - var headers: [AnyHashable:Any]? - var isRedirect = false - var hasGesture = false - var isForMainFrame = true - var method = "GET" - - public init(url: URL, headers: [AnyHashable:Any]?) { - self.url = url - self.headers = headers - } - - public init(url: URL, headers: [AnyHashable:Any]?, isForMainFrame: Bool) { - self.url = url - self.headers = headers - self.isForMainFrame = isForMainFrame - } - - public init(fromURLRequest: URLRequest) { - self.url = fromURLRequest.url ?? URL(string: "about:blank")! - self.headers = fromURLRequest.allHTTPHeaderFields - self.method = fromURLRequest.httpMethod ?? "GET" - } - - public init(fromWKNavigationResponse: WKNavigationResponse) { - let response = fromWKNavigationResponse.response as? HTTPURLResponse - self.url = response?.url ?? URL(string: "about:blank")! - self.headers = response?.allHeaderFields - self.isForMainFrame = fromWKNavigationResponse.isForMainFrame - } - - public func toMap () -> [String:Any?] { - return [ - "url": url.absoluteString, - "headers": headers, - "isRedirect": isRedirect, - "hasGesture": hasGesture, - "isForMainFrame": isForMainFrame, - "method": method - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebResourceResponse.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebResourceResponse.swift deleted file mode 100644 index 4fcf13e750..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebResourceResponse.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// WebResourceResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 01/05/22. -// - -import Foundation -import WebKit - -public class WebResourceResponse: NSObject { - var contentType: String - var contentEncoding: String - var data: Data? - var headers: [AnyHashable:Any]? - var statusCode: Int? - var reasonPhrase: String? - - public init(contentType: String, contentEncoding: String, data: Data?, - headers: [AnyHashable:Any]?, statusCode: Int?, reasonPhrase: String?) { - self.contentType = contentType - self.contentEncoding = contentEncoding - self.data = data - self.headers = headers - self.statusCode = statusCode - self.reasonPhrase = reasonPhrase - } - - public init(fromWKNavigationResponse: WKNavigationResponse) { - let response = fromWKNavigationResponse.response as? HTTPURLResponse - self.contentType = response?.mimeType ?? "" - self.contentEncoding = response?.textEncodingName ?? "" - self.headers = response?.allHeaderFields - self.statusCode = response?.statusCode - } - - public func toMap () -> [String:Any?] { - return [ - "contentType": contentType, - "contentEncoding": contentEncoding, - "data": data, - "headers": headers, - "statusCode": statusCode, - "reasonPhrase": reasonPhrase - ] - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebViewTransport.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebViewTransport.swift deleted file mode 100644 index 7e21f7e6b1..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Types/WebViewTransport.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// WebViewTransport.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class WebViewTransport: NSObject { - var webView: InAppWebView - var request: URLRequest - - init(webView: InAppWebView, request: URLRequest) { - self.webView = webView - self.request = request - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/UIApplication/VisibleViewController.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/UIApplication/VisibleViewController.swift deleted file mode 100644 index e6d549ca42..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/UIApplication/VisibleViewController.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// VisibleViewController.swift -// flutter_inappwebview -// -// Created by Alexandru Terente on 02.08.2023. -// - -import UIKit - -extension UIApplication { - - var visibleViewController: UIViewController? { - guard let rootViewController = keyWindow?.rootViewController else { - return nil - } - return getVisibleViewController(rootViewController) - } - - private func getVisibleViewController(_ rootViewController: UIViewController) -> UIViewController? { - if let presentedViewController = rootViewController.presentedViewController { - return getVisibleViewController(presentedViewController) - } - if let navigationController = rootViewController as? UINavigationController { - return navigationController.visibleViewController - } - if let tabBarController = rootViewController as? UITabBarController { - return tabBarController.selectedViewController - } - return rootViewController - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Util.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Util.swift deleted file mode 100644 index 2925e19952..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/Util.swift +++ /dev/null @@ -1,226 +0,0 @@ -// -// Util.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 12/02/21. -// - -import Foundation -import WebKit - -var SharedLastTouchPointTimestamp: [InAppWebView: Int64] = [:] - -public class Util { - public static func getUrlAsset(plugin: InAppWebViewFlutterPlugin, assetFilePath: String) throws -> URL { - let key = plugin.registrar.lookupKey(forAsset: assetFilePath) - guard let assetURL = Bundle.main.url(forResource: key, withExtension: nil) else { - throw NSError(domain: assetFilePath + " asset file cannot be found!", code: 0) - } - return assetURL - } - - public static func getAbsPathAsset(plugin: InAppWebViewFlutterPlugin, assetFilePath: String) throws -> String { - let key = plugin.registrar.lookupKey(forAsset: assetFilePath) - guard let assetAbsPath = Bundle.main.path(forResource: key, ofType: nil) else { - throw NSError(domain: assetFilePath + " asset file cannot be found!", code: 0) - } - return assetAbsPath - } - - public static func convertToDictionary(text: String) -> [String: Any]? { - if let data = text.data(using: .utf8) { - do { - return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] - } catch { - print(error.localizedDescription) - } - } - return nil - } - - public static func JSONStringify(value: Any, prettyPrinted: Bool = false) -> String { - let options: JSONSerialization.WritingOptions = prettyPrinted ? .prettyPrinted : .init(rawValue: 0) - if JSONSerialization.isValidJSONObject(value) { - let data = try? JSONSerialization.data(withJSONObject: value, options: options) - if data != nil { - if let string = String(data: data!, encoding: .utf8) { - return string - } - } - } - return "" - } - - @available(iOS 14.0, *) - public static func getContentWorld(name: String) -> WKContentWorld { - switch name { - case "defaultClient": - return WKContentWorld.defaultClient - case "page": - return WKContentWorld.page - default: - return WKContentWorld.world(name: name) - } - } - - @available(iOS 10.0, *) - public static func getDataDetectorType(type: String) -> WKDataDetectorTypes { - switch type { - case "NONE": - return WKDataDetectorTypes.init(rawValue: 0) - case "PHONE_NUMBER": - return .phoneNumber - case "LINK": - return .link - case "ADDRESS": - return .address - case "CALENDAR_EVENT": - return .calendarEvent - case "TRACKING_NUMBER": - return .trackingNumber - case "FLIGHT_NUMBER": - return .flightNumber - case "LOOKUP_SUGGESTION": - return .lookupSuggestion - case "SPOTLIGHT_SUGGESTION": - return .spotlightSuggestion - case "ALL": - return .all - default: - return WKDataDetectorTypes.init(rawValue: 0) - } - } - - @available(iOS 10.0, *) - public static func getDataDetectorTypeString(type: WKDataDetectorTypes) -> [String] { - var dataDetectorTypeString: [String] = [] - if type.contains(.all) { - dataDetectorTypeString.append("ALL") - } else { - if type.contains(.phoneNumber) { - dataDetectorTypeString.append("PHONE_NUMBER") - } - if type.contains(.link) { - dataDetectorTypeString.append("LINK") - } - if type.contains(.address) { - dataDetectorTypeString.append("ADDRESS") - } - if type.contains(.calendarEvent) { - dataDetectorTypeString.append("CALENDAR_EVENT") - } - if type.contains(.trackingNumber) { - dataDetectorTypeString.append("TRACKING_NUMBER") - } - if type.contains(.flightNumber) { - dataDetectorTypeString.append("FLIGHT_NUMBER") - } - if type.contains(.lookupSuggestion) { - dataDetectorTypeString.append("LOOKUP_SUGGESTION") - } - if type.contains(.spotlightSuggestion) { - dataDetectorTypeString.append("SPOTLIGHT_SUGGESTION") - } - } - if dataDetectorTypeString.count == 0 { - dataDetectorTypeString = ["NONE"] - } - return dataDetectorTypeString - } - - public static func getDecelerationRate(type: String) -> UIScrollView.DecelerationRate { - switch type { - case "NORMAL": - return .normal - case "FAST": - return .fast - default: - return .normal - } - } - - public static func getDecelerationRateString(type: UIScrollView.DecelerationRate) -> String { - switch type { - case .normal: - return "NORMAL" - case .fast: - return "FAST" - default: - return "NORMAL" - } - } - - public static func isIPv4(address: String) -> Bool { - var sin = sockaddr_in() - return address.withCString({ cstring in inet_pton(AF_INET, cstring, &sin.sin_addr) }) == 1 - } - - public static func isIPv6(address: String) -> Bool { - var sin6 = sockaddr_in6() - return address.withCString({ cstring in inet_pton(AF_INET6, cstring, &sin6.sin6_addr) }) == 1 - } - - public static func isIpAddress(address: String) -> Bool { - return Util.isIPv6(address: address) || Util.isIPv4(address: address) - } - - public static func normalizeIPv6(address: String) throws -> String { - if !Util.isIPv6(address: address) { - throw NSError(domain: "Invalid address: \(address)", code: 0) - } - var ipString = address - // replace ipv4 address if any - let ipv4Regex = try! NSRegularExpression(pattern: "(.*:)([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$)") - if let match = ipv4Regex.firstMatch(in: address, options: [], range: NSRange(location: 0, length: address.utf16.count)) { - if let ipv6PartRange = Range(match.range(at: 1), in: address) { - ipString = String(address[ipv6PartRange]) - } - if let ipv4Range = Range(match.range(at: 2), in: address) { - let ipv4 = address[ipv4Range] - let ipv4Split = ipv4.split(separator: ".") - var ipv4Converted = Array(repeating: "0000", count: 4) - for i in 0...3 { - let byte = Int(ipv4Split[i])! - let hex = ("0" + String(byte, radix: 16)) - var offset = hex.count - 3 - offset = offset < 0 ? 0 : offset - let fromIndex = hex.index(hex.startIndex, offsetBy: offset) - let toIndex = hex.index(hex.startIndex, offsetBy: hex.count - 1) - let indexRange = Range(uncheckedBounds: (lower: fromIndex, upper: toIndex)) - ipv4Converted[i] = String(hex[indexRange]) - } - ipString += ipv4Converted[0] + ipv4Converted[1] + ":" + ipv4Converted[2] + ipv4Converted[3] - } - } - - // take care of leading and trailing :: - let regex = try! NSRegularExpression(pattern: "^:|:$") - ipString = regex.stringByReplacingMatches(in: ipString, options: [], range: NSRange(location: 0, length: ipString.count), withTemplate: "") - - let ipv6 = ipString.split(separator: ":", omittingEmptySubsequences: false) - var fullIPv6 = Array(repeating: "0000", count: ipv6.count) - - for (i, hex) in ipv6.enumerated() { - if !hex.isEmpty { - // normalize leading zeros - let hexString = String("0000" + hex) - var offset = hexString.count - 5 - offset = offset < 0 ? 0 : offset - let fromIndex = hexString.index(hexString.startIndex, offsetBy: offset) - let toIndex = hexString.index(hexString.startIndex, offsetBy: hexString.count - 1) - let indexRange = Range(uncheckedBounds: (lower: fromIndex, upper: toIndex)) - fullIPv6[i] = String(hexString[indexRange]) - } else { - // normalize grouped zeros :: - var zeros: [String] = [] - for _ in ipv6.count...8 { - zeros.append("0000") - } - fullIPv6[i] = zeros.joined(separator: ":") - } - } - - return fullIPv6.joined(separator: ":") - } - -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/WKProcessPoolManager.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/WKProcessPoolManager.swift deleted file mode 100755 index 038fb4d757..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/WKProcessPoolManager.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// WKProcessPoolManager.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/11/2019. -// - -import Foundation -import WebKit - -public class WKProcessPoolManager { - static let sharedProcessPool = WKProcessPool() -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/WebAuthenticationSession/WebAuthenticationSession.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/WebAuthenticationSession/WebAuthenticationSession.swift deleted file mode 100644 index a09fc102b1..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/WebAuthenticationSession/WebAuthenticationSession.swift +++ /dev/null @@ -1,110 +0,0 @@ -// -// WebAuthenticationSession.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 08/05/22. -// - -import Foundation -import AuthenticationServices -import SafariServices -import Flutter - -public class WebAuthenticationSession: NSObject, ASWebAuthenticationPresentationContextProviding, Disposable { - static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_webauthenticationsession_" - var id: String - var plugin: InAppWebViewFlutterPlugin? - var url: URL - var callbackURLScheme: String? - var settings: WebAuthenticationSessionSettings - var session: Any? - var channelDelegate: WebAuthenticationSessionChannelDelegate? - private var _canStart = true - - public init(plugin: InAppWebViewFlutterPlugin, id: String, url: URL, callbackURLScheme: String?, settings: WebAuthenticationSessionSettings) { - self.id = id - self.plugin = plugin - self.url = url - self.settings = settings - super.init() - self.callbackURLScheme = callbackURLScheme - if #available(iOS 12.0, *) { - let session = ASWebAuthenticationSession(url: self.url, callbackURLScheme: self.callbackURLScheme, completionHandler: self.completionHandler) - if #available(iOS 13.0, *) { - session.presentationContextProvider = self - } - self.session = session - } else if #available(iOS 11.0, *) { - self.session = SFAuthenticationSession(url: self.url, callbackURLScheme: self.callbackURLScheme, completionHandler: self.completionHandler) - } - let channel = FlutterMethodChannel(name: WebAuthenticationSession.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: plugin.registrar.messenger()) - self.channelDelegate = WebAuthenticationSessionChannelDelegate(webAuthenticationSession: self, channel: channel) - } - - public func prepare() { - if #available(iOS 13.0, *), let session = session as? ASWebAuthenticationSession { - session.prefersEphemeralWebBrowserSession = settings.prefersEphemeralWebBrowserSession - } - } - - public func completionHandler(url: URL?, error: Error?) -> Void { - channelDelegate?.onComplete(url: url, errorCode: error?._code) - } - - public func canStart() -> Bool { - guard let session = session else { - return false - } - if #available(iOS 13.4, *), let session = session as? ASWebAuthenticationSession { - return session.canStart - } - return _canStart - } - - public func start() -> Bool { - guard let session = session else { - return false - } - var started = false - if #available(iOS 12.0, *), let session = session as? ASWebAuthenticationSession { - started = session.start() - } else if #available(iOS 11.0, *), let session = session as? SFAuthenticationSession { - started = session.start() - } - if started { - _canStart = false - } - return started - } - - public func cancel() { - guard let session = session else { - return - } - if #available(iOS 12.0, *), let session = session as? ASWebAuthenticationSession { - session.cancel() - } else if #available(iOS 11.0, *), let session = session as? SFAuthenticationSession { - session.cancel() - } - } - - @available(iOS 12.0, *) - public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { - return UIApplication.shared.windows.first { $0.isKeyWindow } ?? ASPresentationAnchor() - } - - public func dispose() { - cancel() - channelDelegate?.dispose() - channelDelegate = nil - session = nil - plugin?.webAuthenticationSessionManager?.sessions[id] = nil - plugin = nil - } - - deinit { - debugPrint("WebAuthenticationSession - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/WebAuthenticationSession/WebAuthenticationSessionChannelDelegate.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/WebAuthenticationSession/WebAuthenticationSessionChannelDelegate.swift deleted file mode 100644 index e657a7b911..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/WebAuthenticationSession/WebAuthenticationSessionChannelDelegate.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// WebAuthenticationSessionChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 08/05/22. -// - -import Foundation -import Flutter - -public class WebAuthenticationSessionChannelDelegate: ChannelDelegate { - private weak var webAuthenticationSession: WebAuthenticationSession? - - public init(webAuthenticationSession: WebAuthenticationSession, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.webAuthenticationSession = webAuthenticationSession - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - // let arguments = call.arguments as? NSDictionary - switch call.method { - case "canStart": - if let webAuthenticationSession = webAuthenticationSession { - result(webAuthenticationSession.canStart()) - } else { - result(false) - } - break - case "start": - if let webAuthenticationSession = webAuthenticationSession { - result(webAuthenticationSession.start()) - } else { - result(false) - } - break - case "cancel": - if let webAuthenticationSession = webAuthenticationSession { - webAuthenticationSession.cancel() - result(true) - } else { - result(false) - } - break - case "dispose": - if let webAuthenticationSession = webAuthenticationSession { - webAuthenticationSession.dispose() - result(true) - } else { - result(false) - } - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func onComplete(url: URL?, errorCode: Int?) { - let arguments: [String: Any?] = [ - "url": url?.absoluteString, - "errorCode": errorCode - ] - channel?.invokeMethod("onComplete", arguments: arguments) - } - - public override func dispose() { - super.dispose() - webAuthenticationSession = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/WebAuthenticationSession/WebAuthenticationSessionManager.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/WebAuthenticationSession/WebAuthenticationSessionManager.swift deleted file mode 100644 index a606acd375..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/WebAuthenticationSession/WebAuthenticationSessionManager.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// WebAuthenticationSessionManager.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 08/05/22. -// - -import Flutter -import UIKit -import WebKit -import Foundation -import AVFoundation -import SafariServices - -public class WebAuthenticationSessionManager: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_webauthenticationsession" - var plugin: InAppWebViewFlutterPlugin? - var sessions: [String: WebAuthenticationSession?] = [:] - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: WebAuthenticationSessionManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger())) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "create": - let id = arguments!["id"] as! String - let url = arguments!["url"] as! String - let callbackURLScheme = arguments!["callbackURLScheme"] as? String - let initialSettings = arguments!["initialSettings"] as! [String: Any?] - create(id: id, url: url, callbackURLScheme: callbackURLScheme, settings: initialSettings, result: result) - break - case "isAvailable": - if #available(iOS 11.0, *) { - result(true) - } else { - result(false) - } - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func create(id: String, url: String, callbackURLScheme: String?, settings: [String: Any?], result: @escaping FlutterResult) { - if #available(iOS 11.0, *), let plugin = plugin { - let sessionUrl = URL(string: url) ?? URL(string: "about:blank")! - let initialSettings = WebAuthenticationSessionSettings() - let _ = initialSettings.parse(settings: settings) - let session = WebAuthenticationSession(plugin: plugin, id: id, url: sessionUrl, callbackURLScheme: callbackURLScheme, settings: initialSettings) - session.prepare() - sessions[id] = session - result(true) - return - } - - result(FlutterError.init(code: "WebAuthenticationSessionManager", message: "WebAuthenticationSession is not available!", details: nil)) - } - - public override func dispose() { - super.dispose() - let sessionValues = sessions.values - sessionValues.forEach { (session: WebAuthenticationSession?) in - session?.cancel() - session?.dispose() - } - sessions.removeAll() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/WebAuthenticationSession/WebAuthenticationSessionSettings.swift b/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/WebAuthenticationSession/WebAuthenticationSessionSettings.swift deleted file mode 100644 index b737381ea8..0000000000 --- a/flutter_inappwebview_ios/ios/flutter_inappwebview_ios/Sources/flutter_inappwebview_ios/WebAuthenticationSession/WebAuthenticationSessionSettings.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// WebAuthenticationSessionSettings.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 08/05/22. -// - -import Foundation -import AuthenticationServices -import SafariServices - -@objcMembers -public class WebAuthenticationSessionSettings: ISettings { - - var prefersEphemeralWebBrowserSession = false - - override init(){ - super.init() - } - - override func getRealSettings(obj: WebAuthenticationSession?) -> [String: Any?] { - var realOptions: [String: Any?] = toMap() - if #available(iOS 12.0, *), let session = obj?.session as? ASWebAuthenticationSession { - if #available(iOS 13.0, *) { - realOptions["prefersEphemeralWebBrowserSession"] = session.prefersEphemeralWebBrowserSession - } - } - return realOptions - } -} diff --git a/flutter_inappwebview_ios/lib/flutter_inappwebview_ios.dart b/flutter_inappwebview_ios/lib/flutter_inappwebview_ios.dart deleted file mode 100644 index 9390a49df5..0000000000 --- a/flutter_inappwebview_ios/lib/flutter_inappwebview_ios.dart +++ /dev/null @@ -1,3 +0,0 @@ -library flutter_inappwebview_ios; - -export 'src/main.dart'; diff --git a/flutter_inappwebview_ios/lib/src/chrome_safari_browser/chrome_safari_browser.dart b/flutter_inappwebview_ios/lib/src/chrome_safari_browser/chrome_safari_browser.dart deleted file mode 100755 index c7e9acaa78..0000000000 --- a/flutter_inappwebview_ios/lib/src/chrome_safari_browser/chrome_safari_browser.dart +++ /dev/null @@ -1,232 +0,0 @@ -import 'dart:async'; -import 'dart:collection'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [IOSChromeSafariBrowser]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformChromeSafariBrowserCreationParams] for -/// more information. -@immutable -class IOSChromeSafariBrowserCreationParams - extends PlatformChromeSafariBrowserCreationParams { - /// Creates a new [IOSChromeSafariBrowserCreationParams] instance. - const IOSChromeSafariBrowserCreationParams(); - - /// Creates a [IOSChromeSafariBrowserCreationParams] instance based on [PlatformChromeSafariBrowserCreationParams]. - factory IOSChromeSafariBrowserCreationParams.fromPlatformChromeSafariBrowserCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformChromeSafariBrowserCreationParams params, - ) { - return IOSChromeSafariBrowserCreationParams(); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser} -class IOSChromeSafariBrowser extends PlatformChromeSafariBrowser - with ChannelController { - @override - final String id = IdGenerator.generate(); - - /// Constructs a [IOSChromeSafariBrowser]. - IOSChromeSafariBrowser(PlatformChromeSafariBrowserCreationParams params) - : super.implementation( - params is IOSChromeSafariBrowserCreationParams - ? params - : IOSChromeSafariBrowserCreationParams.fromPlatformChromeSafariBrowserCreationParams( - params, - ), - ); - - static final IOSChromeSafariBrowser _staticValue = IOSChromeSafariBrowser( - IOSChromeSafariBrowserCreationParams(), - ); - - /// Provide static access. - factory IOSChromeSafariBrowser.static() { - return _staticValue; - } - - Map _menuItems = new HashMap(); - bool _isOpened = false; - static const MethodChannel _staticChannel = const MethodChannel( - 'com.pichillilorenzo/flutter_chromesafaribrowser', - ); - - _init() { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_chromesafaribrowser_$id', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - id: id, - debugLoggingSettings: PlatformChromeSafariBrowser.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - _debugLog(call.method, call.arguments); - - switch (call.method) { - case "onOpened": - eventHandler?.onOpened(); - break; - case "onCompletedInitialLoad": - final bool? didLoadSuccessfully = call.arguments["didLoadSuccessfully"]; - eventHandler?.onCompletedInitialLoad(didLoadSuccessfully); - break; - case "onInitialLoadDidRedirect": - final String? url = call.arguments["url"]; - final WebUri? uri = url != null ? WebUri(url) : null; - eventHandler?.onInitialLoadDidRedirect(uri); - break; - case "onWillOpenInBrowser": - eventHandler?.onWillOpenInBrowser(); - break; - case "onClosed": - _isOpened = false; - final onClosed = eventHandler?.onClosed; - dispose(); - onClosed?.call(); - break; - case "onItemActionPerform": - String url = call.arguments["url"]; - String title = call.arguments["title"]; - int id = call.arguments["id"].toInt(); - if (this._menuItems[id] != null) { - if (this._menuItems[id]?.action != null) { - this._menuItems[id]?.action!(url, title); - } - if (this._menuItems[id]?.onClick != null) { - this._menuItems[id]?.onClick!(WebUri(url), title); - } - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - } - - @override - Future open({ - WebUri? url, - Map? headers, - List? otherLikelyURLs, - WebUri? referrer, - @Deprecated('Use settings instead') - // ignore: deprecated_member_use_from_same_package - ChromeSafariBrowserClassOptions? options, - ChromeSafariBrowserSettings? settings, - }) async { - assert(!_isOpened, 'The browser is already opened.'); - _isOpened = true; - - assert(url != null, 'The specified URL must not be null on iOS.'); - assert( - ['http', 'https'].contains(url!.scheme), - 'The specified URL has an unsupported scheme. Only HTTP and HTTPS URLs are supported on iOS.', - ); - if (url != null) { - assert(url.toString().isNotEmpty, 'The specified URL must not be empty.'); - } - - _init(); - - List> menuItemList = []; - _menuItems.forEach((key, value) { - menuItemList.add(value.toMap()); - }); - - var initialSettings = - settings?.toMap() ?? - options?.toMap() ?? - ChromeSafariBrowserSettings().toMap(); - - Map args = {}; - args.putIfAbsent('id', () => id); - args.putIfAbsent('url', () => url?.toString()); - args.putIfAbsent('headers', () => headers); - args.putIfAbsent( - 'otherLikelyURLs', - () => otherLikelyURLs?.map((e) => e.toString()).toList(), - ); - args.putIfAbsent('referrer', () => referrer?.toString()); - args.putIfAbsent('settings', () => initialSettings); - args.putIfAbsent('menuItemList', () => menuItemList); - await _staticChannel.invokeMethod('open', args); - } - - @override - Future close() async { - Map args = {}; - await channel?.invokeMethod("close", args); - } - - @override - void addMenuItem(ChromeSafariBrowserMenuItem menuItem) { - this._menuItems[menuItem.id] = menuItem; - } - - @override - void addMenuItems(List menuItems) { - menuItems.forEach((menuItem) { - this._menuItems[menuItem.id] = menuItem; - }); - } - - @override - Future isAvailable() async { - Map args = {}; - return await _staticChannel.invokeMethod("isAvailable", args) ?? - false; - } - - @override - Future clearWebsiteData() async { - Map args = {}; - await _staticChannel.invokeMethod("clearWebsiteData", args); - } - - @override - Future prewarmConnections(List URLs) async { - Map args = {}; - args.putIfAbsent('URLs', () => URLs.map((e) => e.toString()).toList()); - Map? result = (await _staticChannel.invokeMethod( - "prewarmConnections", - args, - ))?.cast(); - return PrewarmingToken.fromMap(result); - } - - @override - Future invalidatePrewarmingToken( - PrewarmingToken prewarmingToken, - ) async { - Map args = {}; - args.putIfAbsent('prewarmingToken', () => prewarmingToken.toMap()); - await _staticChannel.invokeMethod("invalidatePrewarmingToken", args); - } - - @override - bool isOpened() { - return _isOpened; - } - - @override - @mustCallSuper - void dispose() { - super.dispose(); - disposeChannel(); - } -} diff --git a/flutter_inappwebview_ios/lib/src/chrome_safari_browser/main.dart b/flutter_inappwebview_ios/lib/src/chrome_safari_browser/main.dart deleted file mode 100644 index 9a6238b706..0000000000 --- a/flutter_inappwebview_ios/lib/src/chrome_safari_browser/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'chrome_safari_browser.dart'; diff --git a/flutter_inappwebview_ios/lib/src/cookie_manager.dart b/flutter_inappwebview_ios/lib/src/cookie_manager.dart deleted file mode 100755 index cf6b3dbf80..0000000000 --- a/flutter_inappwebview_ios/lib/src/cookie_manager.dart +++ /dev/null @@ -1,477 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; - -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import 'in_app_webview/headless_in_app_webview.dart'; -import 'platform_util.dart'; - -/// Object specifying creation parameters for creating a [IOSCookieManager]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformCookieManagerCreationParams] for -/// more information. -@immutable -class IOSCookieManagerCreationParams - extends PlatformCookieManagerCreationParams { - /// Creates a new [IOSCookieManagerCreationParams] instance. - const IOSCookieManagerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformCookieManagerCreationParams params, - ) : super(); - - /// Creates a [IOSCookieManagerCreationParams] instance based on [PlatformCookieManagerCreationParams]. - factory IOSCookieManagerCreationParams.fromPlatformCookieManagerCreationParams( - PlatformCookieManagerCreationParams params, - ) { - return IOSCookieManagerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager} -class IOSCookieManager extends PlatformCookieManager with ChannelController { - /// Creates a new [IOSCookieManager]. - IOSCookieManager(PlatformCookieManagerCreationParams params) - : super.implementation( - params is IOSCookieManagerCreationParams - ? params - : IOSCookieManagerCreationParams.fromPlatformCookieManagerCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_cookiemanager', - ); - handler = handleMethod; - initMethodCallHandler(); - } - - static final IOSCookieManager _staticValue = IOSCookieManager( - IOSCookieManagerCreationParams(PlatformCookieManagerCreationParams()), - ); - - factory IOSCookieManager.static() { - return _staticValue; - } - - static IOSCookieManager? _instance; - - ///Gets the [IOSCookieManager] shared instance. - static IOSCookieManager instance() { - return (_instance != null) ? _instance! : _init(); - } - - static IOSCookieManager _init() { - _instance = IOSCookieManager( - IOSCookieManagerCreationParams( - const PlatformCookieManagerCreationParams(), - ), - ); - return _instance!; - } - - Future _handleMethod(MethodCall call) async {} - - @override - Future setCookie({ - required WebUri url, - required String name, - required String value, - String path = "/", - String? domain, - int? expiresDate, - int? maxAge, - bool? isSecure, - bool? isHttpOnly, - HTTPCookieSameSitePolicy? sameSite, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - webViewController = webViewController ?? iosBelow11WebViewController; - - assert(url.toString().isNotEmpty); - assert(name.isNotEmpty); - assert(path.isNotEmpty); - - if (await _shouldUseJavascript()) { - await _setCookieWithJavaScript( - url: url, - name: name, - value: value, - domain: domain, - path: path, - expiresDate: expiresDate, - maxAge: maxAge, - isSecure: isSecure, - sameSite: sameSite, - webViewController: webViewController, - ); - return true; - } - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - args.putIfAbsent('name', () => name); - args.putIfAbsent('value', () => value); - args.putIfAbsent('domain', () => domain); - args.putIfAbsent('path', () => path); - args.putIfAbsent('expiresDate', () => expiresDate?.toString()); - args.putIfAbsent('maxAge', () => maxAge); - args.putIfAbsent('isSecure', () => isSecure); - args.putIfAbsent('isHttpOnly', () => isHttpOnly); - args.putIfAbsent('sameSite', () => sameSite?.toNativeValue()); - - return await channel?.invokeMethod('setCookie', args) ?? false; - } - - Future _setCookieWithJavaScript({ - required WebUri url, - required String name, - required String value, - String path = "/", - String? domain, - int? expiresDate, - int? maxAge, - bool? isSecure, - HTTPCookieSameSitePolicy? sameSite, - PlatformInAppWebViewController? webViewController, - }) async { - var cookieValue = name + "=" + value + "; Path=" + path; - - if (domain != null) cookieValue += "; Domain=" + domain; - - if (expiresDate != null) - cookieValue += "; Expires=" + await _getCookieExpirationDate(expiresDate); - - if (maxAge != null) cookieValue += "; Max-Age=" + maxAge.toString(); - - if (isSecure != null && isSecure) cookieValue += "; Secure"; - - if (sameSite != null && sameSite.isSupported()) - cookieValue += "; SameSite=" + sameSite.toNativeValue()!; - - cookieValue += ";"; - - if (webViewController != null) { - final javaScriptEnabled = - (await webViewController.getSettings())?.javaScriptEnabled ?? false; - if (javaScriptEnabled) { - await webViewController.evaluateJavascript( - source: 'document.cookie="$cookieValue"', - ); - return; - } - } - - final setCookieCompleter = Completer(); - final headlessWebView = IOSHeadlessInAppWebView( - IOSHeadlessInAppWebViewCreationParams( - initialUrlRequest: URLRequest(url: url), - onLoadStop: (controller, url) async { - await controller.evaluateJavascript( - source: 'document.cookie="$cookieValue"', - ); - setCookieCompleter.complete(); - }, - ), - ); - await headlessWebView.run(); - await setCookieCompleter.future; - await headlessWebView.dispose(); - } - - @override - Future> getCookies({ - required WebUri url, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - assert(url.toString().isNotEmpty); - - webViewController = webViewController ?? iosBelow11WebViewController; - - if (await _shouldUseJavascript()) { - return await _getCookiesWithJavaScript( - url: url, - webViewController: webViewController, - ); - } - - List cookies = []; - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - List cookieListMap = - await channel?.invokeMethod('getCookies', args) ?? []; - cookieListMap = cookieListMap.cast>(); - - cookieListMap.forEach((cookieMap) { - cookies.add( - Cookie( - name: cookieMap["name"], - value: cookieMap["value"], - expiresDate: cookieMap["expiresDate"], - isSessionOnly: cookieMap["isSessionOnly"], - domain: cookieMap["domain"], - sameSite: HTTPCookieSameSitePolicy.fromNativeValue( - cookieMap["sameSite"], - ), - isSecure: cookieMap["isSecure"], - isHttpOnly: cookieMap["isHttpOnly"], - path: cookieMap["path"], - ), - ); - }); - return cookies; - } - - Future> _getCookiesWithJavaScript({ - required WebUri url, - PlatformInAppWebViewController? webViewController, - }) async { - assert(url.toString().isNotEmpty); - - List cookies = []; - - if (webViewController != null) { - final javaScriptEnabled = - (await webViewController.getSettings())?.javaScriptEnabled ?? false; - if (javaScriptEnabled) { - List documentCookies = - (await webViewController.evaluateJavascript( - source: 'document.cookie', - ) - as String) - .split(';') - .map((documentCookie) => documentCookie.trim()) - .toList(); - documentCookies.forEach((documentCookie) { - List cookie = documentCookie.split('='); - if (cookie.length > 1) { - cookies.add(Cookie(name: cookie[0], value: cookie[1])); - } - }); - return cookies; - } - } - - final pageLoaded = Completer(); - final headlessWebView = IOSHeadlessInAppWebView( - IOSHeadlessInAppWebViewCreationParams( - initialUrlRequest: URLRequest(url: url), - onLoadStop: (controller, url) async { - pageLoaded.complete(); - }, - ), - ); - await headlessWebView.run(); - await pageLoaded.future; - - List documentCookies = - (await headlessWebView.webViewController!.evaluateJavascript( - source: 'document.cookie', - ) - as String) - .split(';') - .map((documentCookie) => documentCookie.trim()) - .toList(); - documentCookies.forEach((documentCookie) { - List cookie = documentCookie.split('='); - if (cookie.length > 1) { - cookies.add(Cookie(name: cookie[0], value: cookie[1])); - } - }); - await headlessWebView.dispose(); - return cookies; - } - - @override - Future getCookie({ - required WebUri url, - required String name, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - assert(url.toString().isNotEmpty); - assert(name.isNotEmpty); - - webViewController = webViewController ?? iosBelow11WebViewController; - - if (await _shouldUseJavascript()) { - List cookies = await _getCookiesWithJavaScript( - url: url, - webViewController: webViewController, - ); - return cookies.cast().firstWhere( - (cookie) => cookie!.name == name, - orElse: () => null, - ); - } - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - List cookies = - await channel?.invokeMethod('getCookies', args) ?? []; - cookies = cookies.cast>(); - for (var i = 0; i < cookies.length; i++) { - cookies[i] = cookies[i].cast(); - if (cookies[i]["name"] == name) - return Cookie( - name: cookies[i]["name"], - value: cookies[i]["value"], - expiresDate: cookies[i]["expiresDate"], - isSessionOnly: cookies[i]["isSessionOnly"], - domain: cookies[i]["domain"], - sameSite: HTTPCookieSameSitePolicy.fromNativeValue( - cookies[i]["sameSite"], - ), - isSecure: cookies[i]["isSecure"], - isHttpOnly: cookies[i]["isHttpOnly"], - path: cookies[i]["path"], - ); - } - return null; - } - - @override - Future deleteCookie({ - required WebUri url, - required String name, - String path = "/", - String? domain, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - assert(url.toString().isNotEmpty); - assert(name.isNotEmpty); - - webViewController = webViewController ?? iosBelow11WebViewController; - - if (await _shouldUseJavascript()) { - await _setCookieWithJavaScript( - url: url, - name: name, - value: "", - path: path, - domain: domain, - maxAge: -1, - webViewController: webViewController, - ); - return true; - } - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - args.putIfAbsent('name', () => name); - args.putIfAbsent('domain', () => domain); - args.putIfAbsent('path', () => path); - return await channel?.invokeMethod('deleteCookie', args) ?? false; - } - - @override - Future deleteCookies({ - required WebUri url, - String path = "/", - String? domain, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - assert(url.toString().isNotEmpty); - - webViewController = webViewController ?? iosBelow11WebViewController; - - if (await _shouldUseJavascript()) { - List cookies = await _getCookiesWithJavaScript( - url: url, - webViewController: webViewController, - ); - for (var i = 0; i < cookies.length; i++) { - await _setCookieWithJavaScript( - url: url, - name: cookies[i].name, - value: "", - path: path, - domain: domain, - maxAge: -1, - webViewController: webViewController, - ); - } - return true; - } - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - args.putIfAbsent('domain', () => domain); - args.putIfAbsent('path', () => path); - return await channel?.invokeMethod('deleteCookies', args) ?? false; - } - - @override - Future deleteAllCookies() async { - Map args = {}; - return await channel?.invokeMethod('deleteAllCookies', args) ?? false; - } - - @override - Future> getAllCookies() async { - List cookies = []; - - Map args = {}; - List cookieListMap = - await channel?.invokeMethod('getAllCookies', args) ?? []; - cookieListMap = cookieListMap.cast>(); - - cookieListMap.forEach((cookieMap) { - cookies.add( - Cookie( - name: cookieMap["name"], - value: cookieMap["value"], - expiresDate: cookieMap["expiresDate"], - isSessionOnly: cookieMap["isSessionOnly"], - domain: cookieMap["domain"], - sameSite: HTTPCookieSameSitePolicy.fromNativeValue( - cookieMap["sameSite"], - ), - isSecure: cookieMap["isSecure"], - isHttpOnly: cookieMap["isHttpOnly"], - path: cookieMap["path"], - ), - ); - }); - return cookies; - } - - Future _getCookieExpirationDate(int expiresDate) async { - var platformUtil = PlatformUtil.instance(); - var dateTime = DateTime.fromMillisecondsSinceEpoch(expiresDate).toUtc(); - return await platformUtil.formatDate( - date: dateTime, - format: 'EEE, dd MMM yyyy HH:mm:ss z', - locale: 'en_US', - timezone: 'GMT', - ); - } - - Future _shouldUseJavascript() async { - final platformUtil = PlatformUtil.instance(); - final systemVersion = await platformUtil.getSystemVersion(); - return systemVersion.compareTo("10.13") == -1; - } - - @override - void dispose() { - // empty - } -} - -extension InternalCookieManager on IOSCookieManager { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_ios/lib/src/find_interaction/find_interaction_controller.dart b/flutter_inappwebview_ios/lib/src/find_interaction/find_interaction_controller.dart deleted file mode 100644 index f50cb67797..0000000000 --- a/flutter_inappwebview_ios/lib/src/find_interaction/find_interaction_controller.dart +++ /dev/null @@ -1,169 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [IOSFindInteractionController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformFindInteractionControllerCreationParams] for -/// more information. -@immutable -class IOSFindInteractionControllerCreationParams - extends PlatformFindInteractionControllerCreationParams { - /// Creates a new [IOSFindInteractionControllerCreationParams] instance. - const IOSFindInteractionControllerCreationParams({ - super.onFindResultReceived, - }); - - /// Creates a [IOSFindInteractionControllerCreationParams] instance based on [PlatformFindInteractionControllerCreationParams]. - factory IOSFindInteractionControllerCreationParams.fromPlatformFindInteractionControllerCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformFindInteractionControllerCreationParams params, - ) { - return IOSFindInteractionControllerCreationParams( - onFindResultReceived: params.onFindResultReceived, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController} -class IOSFindInteractionController extends PlatformFindInteractionController - with ChannelController { - /// Constructs a [IOSFindInteractionController]. - IOSFindInteractionController( - PlatformFindInteractionControllerCreationParams params, - ) : super.implementation( - params is IOSFindInteractionControllerCreationParams - ? params - : IOSFindInteractionControllerCreationParams.fromPlatformFindInteractionControllerCreationParams( - params, - ), - ); - - static final IOSFindInteractionController _staticValue = - IOSFindInteractionController( - IOSFindInteractionControllerCreationParams(), - ); - - /// Provide static access. - factory IOSFindInteractionController.static() { - return _staticValue; - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - debugLoggingSettings: - PlatformFindInteractionController.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - _debugLog(call.method, call.arguments); - - switch (call.method) { - case "onFindResultReceived": - if (onFindResultReceived != null) { - int activeMatchOrdinal = call.arguments["activeMatchOrdinal"]; - int numberOfMatches = call.arguments["numberOfMatches"]; - bool isDoneCounting = call.arguments["isDoneCounting"]; - onFindResultReceived!( - this, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findAll} - Future findAll({String? find}) async { - Map args = {}; - args.putIfAbsent('find', () => find); - await channel?.invokeMethod('findAll', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findNext} - Future findNext({bool forward = true}) async { - Map args = {}; - args.putIfAbsent('forward', () => forward); - await channel?.invokeMethod('findNext', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.clearMatches} - Future clearMatches() async { - Map args = {}; - await channel?.invokeMethod('clearMatches', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.setSearchText} - Future setSearchText(String? searchText) async { - Map args = {}; - args.putIfAbsent('searchText', () => searchText); - await channel?.invokeMethod('setSearchText', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getSearchText} - Future getSearchText() async { - Map args = {}; - return await channel?.invokeMethod('getSearchText', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.isFindNavigatorVisible} - Future isFindNavigatorVisible() async { - Map args = {}; - return await channel?.invokeMethod('isFindNavigatorVisible', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.updateResultCount} - Future updateResultCount() async { - Map args = {}; - await channel?.invokeMethod('updateResultCount', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.presentFindNavigator} - Future presentFindNavigator() async { - Map args = {}; - await channel?.invokeMethod('presentFindNavigator', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.dismissFindNavigator} - Future dismissFindNavigator() async { - Map args = {}; - await channel?.invokeMethod('dismissFindNavigator', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getActiveFindSession} - Future getActiveFindSession() async { - Map args = {}; - Map? result = (await channel?.invokeMethod( - 'getActiveFindSession', - args, - ))?.cast(); - return FindSession.fromMap(result); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.dispose} - @override - void dispose({bool isKeepAlive = false}) { - disposeChannel(removeMethodCallHandler: !isKeepAlive); - } -} - -extension InternalFindInteractionController on IOSFindInteractionController { - void init(dynamic id) { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_find_interaction_$id', - ); - handler = _handleMethod; - initMethodCallHandler(); - } -} diff --git a/flutter_inappwebview_ios/lib/src/find_interaction/main.dart b/flutter_inappwebview_ios/lib/src/find_interaction/main.dart deleted file mode 100644 index a7adaacf7b..0000000000 --- a/flutter_inappwebview_ios/lib/src/find_interaction/main.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'find_interaction_controller.dart' - hide InternalFindInteractionController; diff --git a/flutter_inappwebview_ios/lib/src/http_auth_credentials_database.dart b/flutter_inappwebview_ios/lib/src/http_auth_credentials_database.dart deleted file mode 100755 index ae669e0d85..0000000000 --- a/flutter_inappwebview_ios/lib/src/http_auth_credentials_database.dart +++ /dev/null @@ -1,175 +0,0 @@ -import 'dart:async'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [IOSHttpAuthCredentialDatabase]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformHttpAuthCredentialDatabaseCreationParams] for -/// more information. -@immutable -class IOSHttpAuthCredentialDatabaseCreationParams - extends PlatformHttpAuthCredentialDatabaseCreationParams { - /// Creates a new [IOSHttpAuthCredentialDatabaseCreationParams] instance. - const IOSHttpAuthCredentialDatabaseCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) : super(); - - /// Creates a [IOSHttpAuthCredentialDatabaseCreationParams] instance based on [PlatformHttpAuthCredentialDatabaseCreationParams]. - factory IOSHttpAuthCredentialDatabaseCreationParams.fromPlatformHttpAuthCredentialDatabaseCreationParams( - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) { - return IOSHttpAuthCredentialDatabaseCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase} -class IOSHttpAuthCredentialDatabase extends PlatformHttpAuthCredentialDatabase - with ChannelController { - /// Creates a new [IOSHttpAuthCredentialDatabase]. - IOSHttpAuthCredentialDatabase( - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) : super.implementation( - params is IOSHttpAuthCredentialDatabaseCreationParams - ? params - : IOSHttpAuthCredentialDatabaseCreationParams.fromPlatformHttpAuthCredentialDatabaseCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_credential_database', - ); - handler = handleMethod; - initMethodCallHandler(); - } - - static IOSHttpAuthCredentialDatabase? _instance; - - ///Gets the database shared instance. - static IOSHttpAuthCredentialDatabase instance() { - return (_instance != null) ? _instance! : _init(); - } - - static IOSHttpAuthCredentialDatabase _init() { - _instance = IOSHttpAuthCredentialDatabase( - IOSHttpAuthCredentialDatabaseCreationParams( - const PlatformHttpAuthCredentialDatabaseCreationParams(), - ), - ); - return _instance!; - } - - static final IOSHttpAuthCredentialDatabase _staticValue = - IOSHttpAuthCredentialDatabase( - IOSHttpAuthCredentialDatabaseCreationParams( - const PlatformHttpAuthCredentialDatabaseCreationParams(), - ), - ); - - factory IOSHttpAuthCredentialDatabase.static() { - return _staticValue; - } - - Future _handleMethod(MethodCall call) async {} - - @override - Future> - getAllAuthCredentials() async { - Map args = {}; - List allCredentials = - await channel?.invokeMethod('getAllAuthCredentials', args) ?? []; - - List result = []; - - for (Map map in allCredentials) { - var element = URLProtectionSpaceHttpAuthCredentials.fromMap( - map.cast(), - ); - if (element != null) { - result.add(element); - } - } - return result; - } - - @override - Future> getHttpAuthCredentials({ - required URLProtectionSpace protectionSpace, - }) async { - Map args = {}; - args.putIfAbsent("host", () => protectionSpace.host); - args.putIfAbsent("protocol", () => protectionSpace.protocol); - args.putIfAbsent("realm", () => protectionSpace.realm); - args.putIfAbsent("port", () => protectionSpace.port); - List credentialList = - await channel?.invokeMethod('getHttpAuthCredentials', args) ?? []; - List credentials = []; - for (Map map in credentialList) { - var credential = URLCredential.fromMap(map.cast()); - if (credential != null) { - credentials.add(credential); - } - } - return credentials; - } - - @override - Future setHttpAuthCredential({ - required URLProtectionSpace protectionSpace, - required URLCredential credential, - }) async { - Map args = {}; - args.putIfAbsent("host", () => protectionSpace.host); - args.putIfAbsent("protocol", () => protectionSpace.protocol); - args.putIfAbsent("realm", () => protectionSpace.realm); - args.putIfAbsent("port", () => protectionSpace.port); - args.putIfAbsent("username", () => credential.username); - args.putIfAbsent("password", () => credential.password); - await channel?.invokeMethod('setHttpAuthCredential', args); - } - - @override - Future removeHttpAuthCredential({ - required URLProtectionSpace protectionSpace, - required URLCredential credential, - }) async { - Map args = {}; - args.putIfAbsent("host", () => protectionSpace.host); - args.putIfAbsent("protocol", () => protectionSpace.protocol); - args.putIfAbsent("realm", () => protectionSpace.realm); - args.putIfAbsent("port", () => protectionSpace.port); - args.putIfAbsent("username", () => credential.username); - args.putIfAbsent("password", () => credential.password); - await channel?.invokeMethod('removeHttpAuthCredential', args); - } - - @override - Future removeHttpAuthCredentials({ - required URLProtectionSpace protectionSpace, - }) async { - Map args = {}; - args.putIfAbsent("host", () => protectionSpace.host); - args.putIfAbsent("protocol", () => protectionSpace.protocol); - args.putIfAbsent("realm", () => protectionSpace.realm); - args.putIfAbsent("port", () => protectionSpace.port); - await channel?.invokeMethod('removeHttpAuthCredentials', args); - } - - @override - Future clearAllAuthCredentials() async { - Map args = {}; - await channel?.invokeMethod('clearAllAuthCredentials', args); - } - - @override - void dispose() { - // empty - } -} - -extension InternalHttpAuthCredentialDatabase on IOSHttpAuthCredentialDatabase { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_ios/lib/src/in_app_browser/in_app_browser.dart b/flutter_inappwebview_ios/lib/src/in_app_browser/in_app_browser.dart deleted file mode 100755 index 1067dc6f53..0000000000 --- a/flutter_inappwebview_ios/lib/src/in_app_browser/in_app_browser.dart +++ /dev/null @@ -1,403 +0,0 @@ -import 'dart:async'; -import 'dart:collection'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../find_interaction/find_interaction_controller.dart'; -import '../in_app_webview/in_app_webview_controller.dart'; -import '../pull_to_refresh/pull_to_refresh_controller.dart'; - -/// Object specifying creation parameters for creating a [IOSInAppBrowser]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformInAppBrowserCreationParams] for -/// more information. -class IOSInAppBrowserCreationParams extends PlatformInAppBrowserCreationParams { - /// Creates a new [IOSInAppBrowserCreationParams] instance. - IOSInAppBrowserCreationParams({ - super.contextMenu, - this.pullToRefreshController, - this.findInteractionController, - super.initialUserScripts, - super.windowId, - }); - - /// Creates a [IOSInAppBrowserCreationParams] instance based on [PlatformInAppBrowserCreationParams]. - factory IOSInAppBrowserCreationParams.fromPlatformInAppBrowserCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformInAppBrowserCreationParams params, - ) { - return IOSInAppBrowserCreationParams( - contextMenu: params.contextMenu, - pullToRefreshController: - params.pullToRefreshController as IOSPullToRefreshController?, - findInteractionController: - params.findInteractionController as IOSFindInteractionController?, - initialUserScripts: params.initialUserScripts, - windowId: params.windowId, - ); - } - - @override - final IOSFindInteractionController? findInteractionController; - - @override - final IOSPullToRefreshController? pullToRefreshController; -} - -///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser} -class IOSInAppBrowser extends PlatformInAppBrowser with ChannelController { - @override - final String id = IdGenerator.generate(); - - /// Constructs a [IOSInAppBrowser]. - IOSInAppBrowser(PlatformInAppBrowserCreationParams params) - : super.implementation( - params is IOSInAppBrowserCreationParams - ? params - : IOSInAppBrowserCreationParams.fromPlatformInAppBrowserCreationParams( - params, - ), - ) { - _contextMenu = params.contextMenu; - } - - static final IOSInAppBrowser _staticValue = IOSInAppBrowser( - IOSInAppBrowserCreationParams(), - ); - - /// Provide static access. - factory IOSInAppBrowser.static() { - return _staticValue; - } - - IOSInAppBrowserCreationParams get _iosParams => - params as IOSInAppBrowserCreationParams; - - static const MethodChannel _staticChannel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappbrowser', - ); - - ContextMenu? _contextMenu; - - @override - ContextMenu? get contextMenu => _contextMenu; - - Map _menuItems = HashMap(); - bool _isOpened = false; - IOSInAppWebViewController? _webViewController; - - @override - IOSInAppWebViewController? get webViewController { - return _isOpened ? _webViewController : null; - } - - _init() { - channel = MethodChannel('com.pichillilorenzo/flutter_inappbrowser_$id'); - handler = _handleMethod; - initMethodCallHandler(); - - _webViewController = IOSInAppWebViewController.fromInAppBrowser( - IOSInAppWebViewControllerCreationParams(id: id), - channel!, - this, - this.initialUserScripts, - ); - _iosParams.pullToRefreshController?.init(id); - _iosParams.findInteractionController?.init(id); - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - id: id, - debugLoggingSettings: PlatformInAppBrowser.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onBrowserCreated": - _debugLog(call.method, call.arguments); - eventHandler?.onBrowserCreated(); - break; - case "onMenuItemClicked": - _debugLog(call.method, call.arguments); - int id = call.arguments["id"].toInt(); - if (this._menuItems[id] != null) { - if (this._menuItems[id]?.onClick != null) { - this._menuItems[id]?.onClick!(); - } - } - break; - case "onExit": - _debugLog(call.method, call.arguments); - _isOpened = false; - final onExit = eventHandler?.onExit; - dispose(); - onExit?.call(); - break; - default: - return _webViewController?.handleMethod(call); - } - } - - Map _prepareOpenRequest({ - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) { - assert(!_isOpened, 'The browser is already opened.'); - _isOpened = true; - _init(); - - var initialSettings = - settings?.toMap() ?? - options?.toMap() ?? - InAppBrowserClassSettings().toMap(); - - Map pullToRefreshSettings = - pullToRefreshController?.settings.toMap() ?? - pullToRefreshController?.options.toMap() ?? - PullToRefreshSettings(enabled: false).toMap(); - - List> menuItemList = []; - _menuItems.forEach((key, value) { - menuItemList.add(value.toMap()); - }); - - Map args = {}; - args.putIfAbsent('id', () => id); - args.putIfAbsent('settings', () => initialSettings); - args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {}); - args.putIfAbsent('windowId', () => windowId); - args.putIfAbsent( - 'initialUserScripts', - () => initialUserScripts?.map((e) => e.toMap()).toList() ?? [], - ); - args.putIfAbsent('pullToRefreshSettings', () => pullToRefreshSettings); - args.putIfAbsent('menuItems', () => menuItemList); - return args; - } - - @override - Future openUrlRequest({ - required URLRequest urlRequest, - // ignore: deprecated_member_use_from_same_package - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) async { - assert(urlRequest.url != null && urlRequest.url.toString().isNotEmpty); - - Map args = _prepareOpenRequest( - options: options, - settings: settings, - ); - args.putIfAbsent('urlRequest', () => urlRequest.toMap()); - await _staticChannel.invokeMethod('open', args); - } - - @override - Future openFile({ - required String assetFilePath, - // ignore: deprecated_member_use_from_same_package - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) async { - assert(assetFilePath.isNotEmpty); - - Map args = _prepareOpenRequest( - options: options, - settings: settings, - ); - args.putIfAbsent('assetFilePath', () => assetFilePath); - await _staticChannel.invokeMethod('open', args); - } - - @override - Future openData({ - required String data, - String mimeType = "text/html", - String encoding = "utf8", - WebUri? baseUrl, - @Deprecated("Use historyUrl instead") Uri? androidHistoryUrl, - WebUri? historyUrl, - // ignore: deprecated_member_use_from_same_package - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) async { - Map args = _prepareOpenRequest( - options: options, - settings: settings, - ); - args.putIfAbsent('data', () => data); - args.putIfAbsent('mimeType', () => mimeType); - args.putIfAbsent('encoding', () => encoding); - args.putIfAbsent('baseUrl', () => baseUrl?.toString() ?? "about:blank"); - args.putIfAbsent( - 'historyUrl', - () => (historyUrl ?? androidHistoryUrl)?.toString() ?? "about:blank", - ); - await _staticChannel.invokeMethod('open', args); - } - - @override - Future openWithSystemBrowser({required WebUri url}) async { - assert(url.toString().isNotEmpty); - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - return await _staticChannel.invokeMethod('openWithSystemBrowser', args); - } - - @override - void addMenuItem(InAppBrowserMenuItem menuItem) { - _menuItems[menuItem.id] = menuItem; - } - - @override - void addMenuItems(List menuItems) { - menuItems.forEach((menuItem) { - _menuItems[menuItem.id] = menuItem; - }); - } - - @override - bool removeMenuItem(InAppBrowserMenuItem menuItem) { - return _menuItems.remove(menuItem.id) != null; - } - - @override - void removeMenuItems(List menuItems) { - for (final menuItem in menuItems) { - removeMenuItem(menuItem); - } - } - - @override - void removeAllMenuItem() { - _menuItems.clear(); - } - - @override - bool hasMenuItem(InAppBrowserMenuItem menuItem) { - return _menuItems.containsKey(menuItem.id); - } - - @override - Future show() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - await channel?.invokeMethod('show', args); - } - - @override - Future hide() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - await channel?.invokeMethod('hide', args); - } - - @override - Future close() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - await channel?.invokeMethod('close', args); - } - - @override - Future isHidden() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - return await channel?.invokeMethod('isHidden', args) ?? false; - } - - @override - @Deprecated('Use setSettings instead') - Future setOptions({required InAppBrowserClassOptions options}) async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - args.putIfAbsent('settings', () => options.toMap()); - await channel?.invokeMethod('setSettings', args); - } - - @override - @Deprecated('Use getSettings instead') - Future getOptions() async { - assert(_isOpened, 'The browser is not opened.'); - Map args = {}; - - Map? options = await channel?.invokeMethod( - 'getSettings', - args, - ); - if (options != null) { - options = options.cast(); - return InAppBrowserClassOptions.fromMap(options as Map); - } - - return null; - } - - @override - Future setSettings({ - required InAppBrowserClassSettings settings, - }) async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - args.putIfAbsent('settings', () => settings.toMap()); - await channel?.invokeMethod('setSettings', args); - } - - @override - Future getSettings() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - - Map? settings = await channel?.invokeMethod( - 'getSettings', - args, - ); - if (settings != null) { - settings = settings.cast(); - return InAppBrowserClassSettings.fromMap( - settings as Map, - ); - } - - return null; - } - - @override - bool isOpened() { - return this._isOpened; - } - - @override - @mustCallSuper - void dispose() { - super.dispose(); - disposeChannel(); - _webViewController?.dispose(); - _webViewController = null; - pullToRefreshController?.dispose(); - findInteractionController?.dispose(); - } -} - -extension InternalInAppBrowser on IOSInAppBrowser { - void setContextMenu(ContextMenu? contextMenu) { - _contextMenu = contextMenu; - } -} diff --git a/flutter_inappwebview_ios/lib/src/in_app_browser/main.dart b/flutter_inappwebview_ios/lib/src/in_app_browser/main.dart deleted file mode 100644 index e11eb8b182..0000000000 --- a/flutter_inappwebview_ios/lib/src/in_app_browser/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'in_app_browser.dart' hide InternalInAppBrowser; diff --git a/flutter_inappwebview_ios/lib/src/in_app_webview/_static_channel.dart b/flutter_inappwebview_ios/lib/src/in_app_webview/_static_channel.dart deleted file mode 100644 index a02f01ece1..0000000000 --- a/flutter_inappwebview_ios/lib/src/in_app_webview/_static_channel.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:flutter/services.dart'; - -const IN_APP_WEBVIEW_STATIC_CHANNEL = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_manager', -); diff --git a/flutter_inappwebview_ios/lib/src/in_app_webview/headless_in_app_webview.dart b/flutter_inappwebview_ios/lib/src/in_app_webview/headless_in_app_webview.dart deleted file mode 100644 index 7d25c9dd56..0000000000 --- a/flutter_inappwebview_ios/lib/src/in_app_webview/headless_in_app_webview.dart +++ /dev/null @@ -1,464 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import '../find_interaction/find_interaction_controller.dart'; -import '../pull_to_refresh/pull_to_refresh_controller.dart'; -import 'in_app_webview_controller.dart'; - -/// Object specifying creation parameters for creating a [IOSHeadlessInAppWebView]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformHeadlessInAppWebViewCreationParams] for -/// more information. -@immutable -class IOSHeadlessInAppWebViewCreationParams - extends PlatformHeadlessInAppWebViewCreationParams { - /// Creates a new [IOSHeadlessInAppWebViewCreationParams] instance. - IOSHeadlessInAppWebViewCreationParams({ - super.controllerFromPlatform, - super.initialSize, - super.windowId, - super.onWebViewCreated, - super.onLoadStart, - super.onLoadStop, - @Deprecated('Use onReceivedError instead') super.onLoadError, - super.onReceivedError, - @Deprecated("Use onReceivedHttpError instead") super.onLoadHttpError, - super.onReceivedHttpError, - super.onProgressChanged, - super.onConsoleMessage, - super.shouldOverrideUrlLoading, - super.onLoadResource, - super.onScrollChanged, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStart, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStartRequest, - super.onDownloadStarting, - @Deprecated('Use onLoadResourceWithCustomScheme instead') - super.onLoadResourceCustomScheme, - super.onLoadResourceWithCustomScheme, - super.onCreateWindow, - super.onCloseWindow, - super.onJsAlert, - super.onJsConfirm, - super.onJsPrompt, - super.onReceivedHttpAuthRequest, - super.onReceivedServerTrustAuthRequest, - super.onReceivedClientCertRequest, - @Deprecated('Use FindInteractionController.onFindResultReceived instead') - super.onFindResultReceived, - super.shouldInterceptAjaxRequest, - super.onAjaxReadyStateChange, - super.onAjaxProgress, - super.shouldInterceptFetchRequest, - super.onUpdateVisitedHistory, - @Deprecated("Use onPrintRequest instead") super.onPrint, - super.onPrintRequest, - super.onLongPressHitTestResult, - super.onEnterFullscreen, - super.onExitFullscreen, - super.onPageCommitVisible, - super.onTitleChanged, - super.onWindowFocus, - super.onWindowBlur, - super.onOverScrolled, - super.onZoomScaleChanged, - @Deprecated('Use onSafeBrowsingHit instead') super.androidOnSafeBrowsingHit, - super.onSafeBrowsingHit, - @Deprecated('Use onPermissionRequest instead') - super.androidOnPermissionRequest, - super.onPermissionRequest, - @Deprecated('Use onGeolocationPermissionsShowPrompt instead') - super.androidOnGeolocationPermissionsShowPrompt, - super.onGeolocationPermissionsShowPrompt, - @Deprecated('Use onGeolocationPermissionsHidePrompt instead') - super.androidOnGeolocationPermissionsHidePrompt, - super.onGeolocationPermissionsHidePrompt, - @Deprecated('Use shouldInterceptRequest instead') - super.androidShouldInterceptRequest, - super.shouldInterceptRequest, - @Deprecated('Use onRenderProcessGone instead') - super.androidOnRenderProcessGone, - super.onRenderProcessGone, - @Deprecated('Use onRenderProcessResponsive instead') - super.androidOnRenderProcessResponsive, - super.onRenderProcessResponsive, - @Deprecated('Use onRenderProcessUnresponsive instead') - super.androidOnRenderProcessUnresponsive, - super.onRenderProcessUnresponsive, - @Deprecated('Use onFormResubmission instead') - super.androidOnFormResubmission, - super.onFormResubmission, - @Deprecated('Use onZoomScaleChanged instead') super.androidOnScaleChanged, - @Deprecated('Use onReceivedIcon instead') super.androidOnReceivedIcon, - super.onReceivedIcon, - @Deprecated('Use onReceivedTouchIconUrl instead') - super.androidOnReceivedTouchIconUrl, - super.onReceivedTouchIconUrl, - @Deprecated('Use onJsBeforeUnload instead') super.androidOnJsBeforeUnload, - super.onJsBeforeUnload, - @Deprecated('Use onReceivedLoginRequest instead') - super.androidOnReceivedLoginRequest, - super.onReceivedLoginRequest, - super.onPermissionRequestCanceled, - super.onRequestFocus, - @Deprecated('Use onWebContentProcessDidTerminate instead') - super.iosOnWebContentProcessDidTerminate, - super.onWebContentProcessDidTerminate, - @Deprecated( - 'Use onDidReceiveServerRedirectForProvisionalNavigation instead', - ) - super.iosOnDidReceiveServerRedirectForProvisionalNavigation, - super.onDidReceiveServerRedirectForProvisionalNavigation, - @Deprecated('Use onNavigationResponse instead') - super.iosOnNavigationResponse, - super.onNavigationResponse, - @Deprecated('Use shouldAllowDeprecatedTLS instead') - super.iosShouldAllowDeprecatedTLS, - super.shouldAllowDeprecatedTLS, - super.onCameraCaptureStateChanged, - super.onMicrophoneCaptureStateChanged, - super.onContentSizeChanged, - super.initialUrlRequest, - super.initialFile, - super.initialData, - @Deprecated('Use initialSettings instead') super.initialOptions, - super.initialSettings, - super.contextMenu, - super.initialUserScripts, - this.pullToRefreshController, - this.findInteractionController, - }); - - /// Creates a [IOSHeadlessInAppWebViewCreationParams] instance based on [PlatformHeadlessInAppWebViewCreationParams]. - IOSHeadlessInAppWebViewCreationParams.fromPlatformHeadlessInAppWebViewCreationParams( - PlatformHeadlessInAppWebViewCreationParams params, - ) : this( - controllerFromPlatform: params.controllerFromPlatform, - initialSize: params.initialSize, - windowId: params.windowId, - onWebViewCreated: params.onWebViewCreated, - onLoadStart: params.onLoadStart, - onLoadStop: params.onLoadStop, - onLoadError: params.onLoadError, - onReceivedError: params.onReceivedError, - onLoadHttpError: params.onLoadHttpError, - onReceivedHttpError: params.onReceivedHttpError, - onProgressChanged: params.onProgressChanged, - onConsoleMessage: params.onConsoleMessage, - shouldOverrideUrlLoading: params.shouldOverrideUrlLoading, - onLoadResource: params.onLoadResource, - onScrollChanged: params.onScrollChanged, - onDownloadStart: params.onDownloadStart, - onDownloadStartRequest: params.onDownloadStartRequest, - onDownloadStarting: params.onDownloadStarting, - onLoadResourceCustomScheme: params.onLoadResourceCustomScheme, - onLoadResourceWithCustomScheme: params.onLoadResourceWithCustomScheme, - onCreateWindow: params.onCreateWindow, - onCloseWindow: params.onCloseWindow, - onJsAlert: params.onJsAlert, - onJsConfirm: params.onJsConfirm, - onJsPrompt: params.onJsPrompt, - onReceivedHttpAuthRequest: params.onReceivedHttpAuthRequest, - onReceivedServerTrustAuthRequest: - params.onReceivedServerTrustAuthRequest, - onReceivedClientCertRequest: params.onReceivedClientCertRequest, - onFindResultReceived: params.onFindResultReceived, - shouldInterceptAjaxRequest: params.shouldInterceptAjaxRequest, - onAjaxReadyStateChange: params.onAjaxReadyStateChange, - onAjaxProgress: params.onAjaxProgress, - shouldInterceptFetchRequest: params.shouldInterceptFetchRequest, - onUpdateVisitedHistory: params.onUpdateVisitedHistory, - onPrint: params.onPrint, - onPrintRequest: params.onPrintRequest, - onLongPressHitTestResult: params.onLongPressHitTestResult, - onEnterFullscreen: params.onEnterFullscreen, - onExitFullscreen: params.onExitFullscreen, - onPageCommitVisible: params.onPageCommitVisible, - onTitleChanged: params.onTitleChanged, - onWindowFocus: params.onWindowFocus, - onWindowBlur: params.onWindowBlur, - onOverScrolled: params.onOverScrolled, - onZoomScaleChanged: params.onZoomScaleChanged, - androidOnSafeBrowsingHit: params.androidOnSafeBrowsingHit, - onSafeBrowsingHit: params.onSafeBrowsingHit, - androidOnPermissionRequest: params.androidOnPermissionRequest, - onPermissionRequest: params.onPermissionRequest, - androidOnGeolocationPermissionsShowPrompt: - params.androidOnGeolocationPermissionsShowPrompt, - onGeolocationPermissionsShowPrompt: - params.onGeolocationPermissionsShowPrompt, - androidOnGeolocationPermissionsHidePrompt: - params.androidOnGeolocationPermissionsHidePrompt, - onGeolocationPermissionsHidePrompt: - params.onGeolocationPermissionsHidePrompt, - androidShouldInterceptRequest: params.androidShouldInterceptRequest, - shouldInterceptRequest: params.shouldInterceptRequest, - androidOnRenderProcessGone: params.androidOnRenderProcessGone, - onRenderProcessGone: params.onRenderProcessGone, - androidOnRenderProcessResponsive: - params.androidOnRenderProcessResponsive, - onRenderProcessResponsive: params.onRenderProcessResponsive, - androidOnRenderProcessUnresponsive: - params.androidOnRenderProcessUnresponsive, - onRenderProcessUnresponsive: params.onRenderProcessUnresponsive, - androidOnFormResubmission: params.androidOnFormResubmission, - onFormResubmission: params.onFormResubmission, - androidOnScaleChanged: params.androidOnScaleChanged, - androidOnReceivedIcon: params.androidOnReceivedIcon, - onReceivedIcon: params.onReceivedIcon, - androidOnReceivedTouchIconUrl: params.androidOnReceivedTouchIconUrl, - onReceivedTouchIconUrl: params.onReceivedTouchIconUrl, - androidOnJsBeforeUnload: params.androidOnJsBeforeUnload, - onJsBeforeUnload: params.onJsBeforeUnload, - androidOnReceivedLoginRequest: params.androidOnReceivedLoginRequest, - onReceivedLoginRequest: params.onReceivedLoginRequest, - onPermissionRequestCanceled: params.onPermissionRequestCanceled, - onRequestFocus: params.onRequestFocus, - iosOnWebContentProcessDidTerminate: - params.iosOnWebContentProcessDidTerminate, - onWebContentProcessDidTerminate: params.onWebContentProcessDidTerminate, - iosOnDidReceiveServerRedirectForProvisionalNavigation: - params.iosOnDidReceiveServerRedirectForProvisionalNavigation, - onDidReceiveServerRedirectForProvisionalNavigation: - params.onDidReceiveServerRedirectForProvisionalNavigation, - iosOnNavigationResponse: params.iosOnNavigationResponse, - onNavigationResponse: params.onNavigationResponse, - iosShouldAllowDeprecatedTLS: params.iosShouldAllowDeprecatedTLS, - shouldAllowDeprecatedTLS: params.shouldAllowDeprecatedTLS, - onCameraCaptureStateChanged: params.onCameraCaptureStateChanged, - onMicrophoneCaptureStateChanged: params.onMicrophoneCaptureStateChanged, - onContentSizeChanged: params.onContentSizeChanged, - initialUrlRequest: params.initialUrlRequest, - initialFile: params.initialFile, - initialData: params.initialData, - initialOptions: params.initialOptions, - initialSettings: params.initialSettings, - contextMenu: params.contextMenu, - initialUserScripts: params.initialUserScripts, - pullToRefreshController: - params.pullToRefreshController as IOSPullToRefreshController?, - findInteractionController: - params.findInteractionController as IOSFindInteractionController?, - ); - - @override - final IOSFindInteractionController? findInteractionController; - - @override - final IOSPullToRefreshController? pullToRefreshController; -} - -///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView} -class IOSHeadlessInAppWebView extends PlatformHeadlessInAppWebView - with ChannelController { - @override - late final String id; - - bool _started = false; - bool _running = false; - - static const MethodChannel _sharedChannel = const MethodChannel( - 'com.pichillilorenzo/flutter_headless_inappwebview', - ); - - IOSInAppWebViewController? _webViewController; - - /// Constructs a [IOSHeadlessInAppWebView]. - IOSHeadlessInAppWebView(PlatformHeadlessInAppWebViewCreationParams params) - : super.implementation( - params is IOSHeadlessInAppWebViewCreationParams - ? params - : IOSHeadlessInAppWebViewCreationParams.fromPlatformHeadlessInAppWebViewCreationParams( - params, - ), - ) { - id = IdGenerator.generate(); - } - - static final IOSHeadlessInAppWebView _staticValue = IOSHeadlessInAppWebView( - IOSHeadlessInAppWebViewCreationParams(), - ); - - factory IOSHeadlessInAppWebView.static() { - return _staticValue; - } - - @override - IOSInAppWebViewController? get webViewController => _webViewController; - - dynamic _controllerFromPlatform; - - IOSHeadlessInAppWebViewCreationParams get _iosParams => - params as IOSHeadlessInAppWebViewCreationParams; - - _init() { - _webViewController = IOSInAppWebViewController( - IOSInAppWebViewControllerCreationParams(id: id, webviewParams: params), - ); - _controllerFromPlatform = - params.controllerFromPlatform?.call(_webViewController!) ?? - _webViewController!; - _iosParams.pullToRefreshController?.init(id); - _iosParams.findInteractionController?.init(id); - channel = MethodChannel( - 'com.pichillilorenzo/flutter_headless_inappwebview_$id', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onWebViewCreated": - if (params.onWebViewCreated != null && _webViewController != null) { - params.onWebViewCreated!(_controllerFromPlatform); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - Future run() async { - if (_started) { - return; - } - _started = true; - _init(); - - final initialSettings = params.initialSettings ?? InAppWebViewSettings(); - _inferInitialSettings(initialSettings); - - Map settingsMap = - (params.initialSettings != null ? initialSettings.toMap() : null) ?? - params.initialOptions?.toMap() ?? - initialSettings.toMap(); - - Map pullToRefreshSettings = - _iosParams.pullToRefreshController?.params.settings.toMap() ?? - _iosParams.pullToRefreshController?.params.options.toMap() ?? - PullToRefreshSettings(enabled: false).toMap(); - - Map args = {}; - args.putIfAbsent('id', () => id); - args.putIfAbsent( - 'params', - () => { - 'initialUrlRequest': params.initialUrlRequest?.toMap(), - 'initialFile': params.initialFile, - 'initialData': params.initialData?.toMap(), - 'initialSettings': settingsMap, - 'contextMenu': params.contextMenu?.toMap() ?? {}, - 'windowId': params.windowId, - 'initialUserScripts': - params.initialUserScripts?.map((e) => e.toMap()).toList() ?? [], - 'pullToRefreshSettings': pullToRefreshSettings, - 'initialSize': params.initialSize.toMap(), - }, - ); - await _sharedChannel.invokeMethod('run', args); - _running = true; - } - - void _inferInitialSettings(InAppWebViewSettings settings) { - if (params.shouldOverrideUrlLoading != null && - settings.useShouldOverrideUrlLoading == null) { - settings.useShouldOverrideUrlLoading = true; - } - if (params.onLoadResource != null && settings.useOnLoadResource == null) { - settings.useOnLoadResource = true; - } - if ((params.onDownloadStartRequest != null || - params.onDownloadStarting != null) && - settings.useOnDownloadStart == null) { - settings.useOnDownloadStart = true; - } - if ((params.shouldInterceptAjaxRequest != null || - params.onAjaxProgress != null || - params.onAjaxReadyStateChange != null)) { - if (settings.useShouldInterceptAjaxRequest == null) { - settings.useShouldInterceptAjaxRequest = true; - } - if (params.onAjaxReadyStateChange != null && - settings.useOnAjaxReadyStateChange == null) { - settings.useOnAjaxReadyStateChange = true; - } - if (params.onAjaxProgress != null && settings.useOnAjaxProgress == null) { - settings.useOnAjaxProgress = true; - } - } - if (params.shouldInterceptFetchRequest != null && - settings.useShouldInterceptFetchRequest == null) { - settings.useShouldInterceptFetchRequest = true; - } - if (params.shouldInterceptRequest != null && - settings.useShouldInterceptRequest == null) { - settings.useShouldInterceptRequest = true; - } - if (params.onRenderProcessGone != null && - settings.useOnRenderProcessGone == null) { - settings.useOnRenderProcessGone = true; - } - if (params.onNavigationResponse != null && - settings.useOnNavigationResponse == null) { - settings.useOnNavigationResponse = true; - } - } - - @override - bool isRunning() { - return _running; - } - - @override - Future setSize(Size size) async { - if (!_running) { - return; - } - - Map args = {}; - args.putIfAbsent('size', () => size.toMap()); - await channel?.invokeMethod('setSize', args); - } - - @override - Future getSize() async { - if (!_running) { - return null; - } - - Map args = {}; - Map sizeMap = (await channel?.invokeMethod( - 'getSize', - args, - ))?.cast(); - return MapSize.fromMap(sizeMap); - } - - @override - Future dispose() async { - if (!_running) { - return; - } - Map args = {}; - await channel?.invokeMethod('dispose', args); - disposeChannel(); - _started = false; - _running = false; - _webViewController?.dispose(); - _webViewController = null; - _controllerFromPlatform = null; - _iosParams.pullToRefreshController?.dispose(); - _iosParams.findInteractionController?.dispose(); - } -} - -extension InternalHeadlessInAppWebView on IOSHeadlessInAppWebView { - Future internalDispose() async { - _started = false; - _running = false; - } -} diff --git a/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview.dart b/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview.dart deleted file mode 100755 index 8223a67f4a..0000000000 --- a/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview.dart +++ /dev/null @@ -1,438 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../find_interaction/find_interaction_controller.dart'; -import '../pull_to_refresh/pull_to_refresh_controller.dart'; -import 'headless_in_app_webview.dart'; -import 'in_app_webview_controller.dart'; - -/// Object specifying creation parameters for creating a [PlatformInAppWebViewWidget]. -/// -/// Platform specific implementations can add additional fields by extending -/// this class. -class IOSInAppWebViewWidgetCreationParams - extends PlatformInAppWebViewWidgetCreationParams { - IOSInAppWebViewWidgetCreationParams({ - super.controllerFromPlatform, - super.key, - super.layoutDirection, - super.gestureRecognizers, - super.headlessWebView, - super.keepAlive, - super.preventGestureDelay, - super.windowId, - super.onWebViewCreated, - super.onLoadStart, - super.onLoadStop, - @Deprecated('Use onReceivedError instead') super.onLoadError, - super.onReceivedError, - @Deprecated("Use onReceivedHttpError instead") super.onLoadHttpError, - super.onReceivedHttpError, - super.onProgressChanged, - super.onConsoleMessage, - super.shouldOverrideUrlLoading, - super.onLoadResource, - super.onScrollChanged, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStart, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStartRequest, - super.onDownloadStarting, - @Deprecated('Use onLoadResourceWithCustomScheme instead') - super.onLoadResourceCustomScheme, - super.onLoadResourceWithCustomScheme, - super.onCreateWindow, - super.onCloseWindow, - super.onJsAlert, - super.onJsConfirm, - super.onJsPrompt, - super.onReceivedHttpAuthRequest, - super.onReceivedServerTrustAuthRequest, - super.onReceivedClientCertRequest, - @Deprecated('Use FindInteractionController.onFindResultReceived instead') - super.onFindResultReceived, - super.shouldInterceptAjaxRequest, - super.onAjaxReadyStateChange, - super.onAjaxProgress, - super.shouldInterceptFetchRequest, - super.onUpdateVisitedHistory, - @Deprecated("Use onPrintRequest instead") super.onPrint, - super.onPrintRequest, - super.onLongPressHitTestResult, - super.onEnterFullscreen, - super.onExitFullscreen, - super.onPageCommitVisible, - super.onTitleChanged, - super.onWindowFocus, - super.onWindowBlur, - super.onOverScrolled, - super.onZoomScaleChanged, - @Deprecated('Use onSafeBrowsingHit instead') super.androidOnSafeBrowsingHit, - super.onSafeBrowsingHit, - @Deprecated('Use onPermissionRequest instead') - super.androidOnPermissionRequest, - super.onPermissionRequest, - @Deprecated('Use onGeolocationPermissionsShowPrompt instead') - super.androidOnGeolocationPermissionsShowPrompt, - super.onGeolocationPermissionsShowPrompt, - @Deprecated('Use onGeolocationPermissionsHidePrompt instead') - super.androidOnGeolocationPermissionsHidePrompt, - super.onGeolocationPermissionsHidePrompt, - @Deprecated('Use shouldInterceptRequest instead') - super.androidShouldInterceptRequest, - super.shouldInterceptRequest, - @Deprecated('Use onRenderProcessGone instead') - super.androidOnRenderProcessGone, - super.onRenderProcessGone, - @Deprecated('Use onRenderProcessResponsive instead') - super.androidOnRenderProcessResponsive, - super.onRenderProcessResponsive, - @Deprecated('Use onRenderProcessUnresponsive instead') - super.androidOnRenderProcessUnresponsive, - super.onRenderProcessUnresponsive, - @Deprecated('Use onFormResubmission instead') - super.androidOnFormResubmission, - super.onFormResubmission, - @Deprecated('Use onZoomScaleChanged instead') super.androidOnScaleChanged, - @Deprecated('Use onReceivedIcon instead') super.androidOnReceivedIcon, - super.onReceivedIcon, - @Deprecated('Use onReceivedTouchIconUrl instead') - super.androidOnReceivedTouchIconUrl, - super.onReceivedTouchIconUrl, - @Deprecated('Use onJsBeforeUnload instead') super.androidOnJsBeforeUnload, - super.onJsBeforeUnload, - @Deprecated('Use onReceivedLoginRequest instead') - super.androidOnReceivedLoginRequest, - super.onReceivedLoginRequest, - super.onPermissionRequestCanceled, - super.onRequestFocus, - @Deprecated('Use onWebContentProcessDidTerminate instead') - super.iosOnWebContentProcessDidTerminate, - super.onWebContentProcessDidTerminate, - @Deprecated( - 'Use onDidReceiveServerRedirectForProvisionalNavigation instead', - ) - super.iosOnDidReceiveServerRedirectForProvisionalNavigation, - super.onDidReceiveServerRedirectForProvisionalNavigation, - @Deprecated('Use onNavigationResponse instead') - super.iosOnNavigationResponse, - super.onNavigationResponse, - @Deprecated('Use shouldAllowDeprecatedTLS instead') - super.iosShouldAllowDeprecatedTLS, - super.shouldAllowDeprecatedTLS, - super.onCameraCaptureStateChanged, - super.onMicrophoneCaptureStateChanged, - super.onContentSizeChanged, - super.initialUrlRequest, - super.initialFile, - super.initialData, - @Deprecated('Use initialSettings instead') super.initialOptions, - super.initialSettings, - super.contextMenu, - super.initialUserScripts, - this.pullToRefreshController, - this.findInteractionController, - }); - - /// Constructs a [IOSInAppWebViewWidgetCreationParams] using a - /// [PlatformInAppWebViewWidgetCreationParams]. - IOSInAppWebViewWidgetCreationParams.fromPlatformInAppWebViewWidgetCreationParams( - PlatformInAppWebViewWidgetCreationParams params, - ) : this( - controllerFromPlatform: params.controllerFromPlatform, - key: params.key, - layoutDirection: params.layoutDirection, - gestureRecognizers: params.gestureRecognizers, - headlessWebView: params.headlessWebView, - keepAlive: params.keepAlive, - preventGestureDelay: params.preventGestureDelay, - windowId: params.windowId, - onWebViewCreated: params.onWebViewCreated, - onLoadStart: params.onLoadStart, - onLoadStop: params.onLoadStop, - onLoadError: params.onLoadError, - onReceivedError: params.onReceivedError, - onLoadHttpError: params.onLoadHttpError, - onReceivedHttpError: params.onReceivedHttpError, - onProgressChanged: params.onProgressChanged, - onConsoleMessage: params.onConsoleMessage, - shouldOverrideUrlLoading: params.shouldOverrideUrlLoading, - onLoadResource: params.onLoadResource, - onScrollChanged: params.onScrollChanged, - onDownloadStart: params.onDownloadStart, - onDownloadStartRequest: params.onDownloadStartRequest, - onDownloadStarting: params.onDownloadStarting, - onLoadResourceCustomScheme: params.onLoadResourceCustomScheme, - onLoadResourceWithCustomScheme: params.onLoadResourceWithCustomScheme, - onCreateWindow: params.onCreateWindow, - onCloseWindow: params.onCloseWindow, - onJsAlert: params.onJsAlert, - onJsConfirm: params.onJsConfirm, - onJsPrompt: params.onJsPrompt, - onReceivedHttpAuthRequest: params.onReceivedHttpAuthRequest, - onReceivedServerTrustAuthRequest: - params.onReceivedServerTrustAuthRequest, - onReceivedClientCertRequest: params.onReceivedClientCertRequest, - onFindResultReceived: params.onFindResultReceived, - shouldInterceptAjaxRequest: params.shouldInterceptAjaxRequest, - onAjaxReadyStateChange: params.onAjaxReadyStateChange, - onAjaxProgress: params.onAjaxProgress, - shouldInterceptFetchRequest: params.shouldInterceptFetchRequest, - onUpdateVisitedHistory: params.onUpdateVisitedHistory, - onPrint: params.onPrint, - onPrintRequest: params.onPrintRequest, - onLongPressHitTestResult: params.onLongPressHitTestResult, - onEnterFullscreen: params.onEnterFullscreen, - onExitFullscreen: params.onExitFullscreen, - onPageCommitVisible: params.onPageCommitVisible, - onTitleChanged: params.onTitleChanged, - onWindowFocus: params.onWindowFocus, - onWindowBlur: params.onWindowBlur, - onOverScrolled: params.onOverScrolled, - onZoomScaleChanged: params.onZoomScaleChanged, - androidOnSafeBrowsingHit: params.androidOnSafeBrowsingHit, - onSafeBrowsingHit: params.onSafeBrowsingHit, - androidOnPermissionRequest: params.androidOnPermissionRequest, - onPermissionRequest: params.onPermissionRequest, - androidOnGeolocationPermissionsShowPrompt: - params.androidOnGeolocationPermissionsShowPrompt, - onGeolocationPermissionsShowPrompt: - params.onGeolocationPermissionsShowPrompt, - androidOnGeolocationPermissionsHidePrompt: - params.androidOnGeolocationPermissionsHidePrompt, - onGeolocationPermissionsHidePrompt: - params.onGeolocationPermissionsHidePrompt, - androidShouldInterceptRequest: params.androidShouldInterceptRequest, - shouldInterceptRequest: params.shouldInterceptRequest, - androidOnRenderProcessGone: params.androidOnRenderProcessGone, - onRenderProcessGone: params.onRenderProcessGone, - androidOnRenderProcessResponsive: - params.androidOnRenderProcessResponsive, - onRenderProcessResponsive: params.onRenderProcessResponsive, - androidOnRenderProcessUnresponsive: - params.androidOnRenderProcessUnresponsive, - onRenderProcessUnresponsive: params.onRenderProcessUnresponsive, - androidOnFormResubmission: params.androidOnFormResubmission, - onFormResubmission: params.onFormResubmission, - androidOnScaleChanged: params.androidOnScaleChanged, - androidOnReceivedIcon: params.androidOnReceivedIcon, - onReceivedIcon: params.onReceivedIcon, - androidOnReceivedTouchIconUrl: params.androidOnReceivedTouchIconUrl, - onReceivedTouchIconUrl: params.onReceivedTouchIconUrl, - androidOnJsBeforeUnload: params.androidOnJsBeforeUnload, - onJsBeforeUnload: params.onJsBeforeUnload, - androidOnReceivedLoginRequest: params.androidOnReceivedLoginRequest, - onReceivedLoginRequest: params.onReceivedLoginRequest, - onPermissionRequestCanceled: params.onPermissionRequestCanceled, - onRequestFocus: params.onRequestFocus, - iosOnWebContentProcessDidTerminate: - params.iosOnWebContentProcessDidTerminate, - onWebContentProcessDidTerminate: params.onWebContentProcessDidTerminate, - iosOnDidReceiveServerRedirectForProvisionalNavigation: - params.iosOnDidReceiveServerRedirectForProvisionalNavigation, - onDidReceiveServerRedirectForProvisionalNavigation: - params.onDidReceiveServerRedirectForProvisionalNavigation, - iosOnNavigationResponse: params.iosOnNavigationResponse, - onNavigationResponse: params.onNavigationResponse, - iosShouldAllowDeprecatedTLS: params.iosShouldAllowDeprecatedTLS, - shouldAllowDeprecatedTLS: params.shouldAllowDeprecatedTLS, - onCameraCaptureStateChanged: params.onCameraCaptureStateChanged, - onMicrophoneCaptureStateChanged: params.onMicrophoneCaptureStateChanged, - onContentSizeChanged: params.onContentSizeChanged, - initialUrlRequest: params.initialUrlRequest, - initialFile: params.initialFile, - initialData: params.initialData, - initialOptions: params.initialOptions, - initialSettings: params.initialSettings, - contextMenu: params.contextMenu, - initialUserScripts: params.initialUserScripts, - pullToRefreshController: - params.pullToRefreshController as IOSPullToRefreshController?, - findInteractionController: - params.findInteractionController as IOSFindInteractionController?, - ); - - @override - final IOSFindInteractionController? findInteractionController; - - @override - final IOSPullToRefreshController? pullToRefreshController; -} - -///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewWidget} -class IOSInAppWebViewWidget extends PlatformInAppWebViewWidget { - /// Constructs a [IOSInAppWebViewWidget]. - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewWidget} - IOSInAppWebViewWidget(PlatformInAppWebViewWidgetCreationParams params) - : super.implementation( - params is IOSInAppWebViewWidgetCreationParams - ? params - : IOSInAppWebViewWidgetCreationParams.fromPlatformInAppWebViewWidgetCreationParams( - params, - ), - ); - - IOSInAppWebViewWidgetCreationParams get _iosParams => - params as IOSInAppWebViewWidgetCreationParams; - - IOSInAppWebViewController? _controller; - - IOSHeadlessInAppWebView? get _iosHeadlessInAppWebView => - params.headlessWebView as IOSHeadlessInAppWebView?; - - static final IOSInAppWebViewWidget _staticValue = IOSInAppWebViewWidget( - IOSInAppWebViewWidgetCreationParams(), - ); - - factory IOSInAppWebViewWidget.static() { - return _staticValue; - } - - @override - Widget build(BuildContext context) { - final initialSettings = params.initialSettings ?? InAppWebViewSettings(); - _inferInitialSettings(initialSettings); - - Map settingsMap = - (params.initialSettings != null ? initialSettings.toMap() : null) ?? - // ignore: deprecated_member_use_from_same_package - params.initialOptions?.toMap() ?? - initialSettings.toMap(); - - Map pullToRefreshSettings = - params.pullToRefreshController?.params.settings.toMap() ?? - // ignore: deprecated_member_use_from_same_package - params.pullToRefreshController?.params.options.toMap() ?? - PullToRefreshSettings(enabled: false).toMap(); - - if ((params.headlessWebView?.isRunning() ?? false) && - params.keepAlive != null) { - final headlessId = params.headlessWebView?.id; - if (headlessId != null) { - // force keep alive id to match headless webview id - params.keepAlive?.id = headlessId; - } - } - - return UiKitView( - viewType: 'com.pichillilorenzo/flutter_inappwebview', - onPlatformViewCreated: _onPlatformViewCreated, - gestureRecognizers: params.gestureRecognizers, - creationParams: { - 'initialUrlRequest': params.initialUrlRequest?.toMap(), - 'initialFile': params.initialFile, - 'initialData': params.initialData?.toMap(), - 'initialSettings': settingsMap, - 'contextMenu': params.contextMenu?.toMap() ?? {}, - 'windowId': params.windowId, - 'headlessWebViewId': params.headlessWebView?.isRunning() ?? false - ? params.headlessWebView?.id - : null, - 'initialUserScripts': - params.initialUserScripts?.map((e) => e.toMap()).toList() ?? [], - 'pullToRefreshSettings': pullToRefreshSettings, - 'keepAliveId': params.keepAlive?.id, - 'preventGestureDelay': params.preventGestureDelay, - }, - creationParamsCodec: const StandardMessageCodec(), - ); - } - - void _onPlatformViewCreated(int id) { - dynamic viewId = id; - if (params.headlessWebView?.isRunning() ?? false) { - viewId = params.headlessWebView?.id; - } - viewId = params.keepAlive?.id ?? viewId ?? id; - _iosHeadlessInAppWebView?.internalDispose(); - _controller = IOSInAppWebViewController( - PlatformInAppWebViewControllerCreationParams( - id: viewId, - webviewParams: params, - ), - ); - _iosParams.pullToRefreshController?.init(viewId); - _iosParams.findInteractionController?.init(viewId); - debugLog( - className: runtimeType.toString(), - id: viewId?.toString(), - debugLoggingSettings: PlatformInAppWebViewController.debugLoggingSettings, - method: "onWebViewCreated", - args: [], - ); - if (params.onWebViewCreated != null) { - params.onWebViewCreated!( - params.controllerFromPlatform?.call(_controller!) ?? _controller!, - ); - } - } - - void _inferInitialSettings(InAppWebViewSettings settings) { - if (params.shouldOverrideUrlLoading != null && - settings.useShouldOverrideUrlLoading == null) { - settings.useShouldOverrideUrlLoading = true; - } - if (params.onLoadResource != null && settings.useOnLoadResource == null) { - settings.useOnLoadResource = true; - } - if ((params.onDownloadStartRequest != null || - params.onDownloadStarting != null) && - settings.useOnDownloadStart == null) { - settings.useOnDownloadStart = true; - } - if ((params.shouldInterceptAjaxRequest != null || - params.onAjaxProgress != null || - params.onAjaxReadyStateChange != null)) { - if (settings.useShouldInterceptAjaxRequest == null) { - settings.useShouldInterceptAjaxRequest = true; - } - if (params.onAjaxReadyStateChange != null && - settings.useOnAjaxReadyStateChange == null) { - settings.useOnAjaxReadyStateChange = true; - } - if (params.onAjaxProgress != null && settings.useOnAjaxProgress == null) { - settings.useOnAjaxProgress = true; - } - } - if (params.shouldInterceptFetchRequest != null && - settings.useShouldInterceptFetchRequest == null) { - settings.useShouldInterceptFetchRequest = true; - } - if (params.shouldInterceptRequest != null && - settings.useShouldInterceptRequest == null) { - settings.useShouldInterceptRequest = true; - } - if (params.onRenderProcessGone != null && - settings.useOnRenderProcessGone == null) { - settings.useOnRenderProcessGone = true; - } - if (params.onNavigationResponse != null && - settings.useOnNavigationResponse == null) { - settings.useOnNavigationResponse = true; - } - } - - @override - void dispose() { - dynamic viewId = _controller?.getViewId(); - debugLog( - className: runtimeType.toString(), - id: viewId?.toString(), - debugLoggingSettings: PlatformInAppWebViewController.debugLoggingSettings, - method: "dispose", - args: [], - ); - final isKeepAlive = params.keepAlive != null; - _controller?.dispose(isKeepAlive: isKeepAlive); - _controller = null; - params.pullToRefreshController?.dispose(isKeepAlive: isKeepAlive); - params.findInteractionController?.dispose(isKeepAlive: isKeepAlive); - } - - @override - T controllerFromPlatform(PlatformInAppWebViewController controller) { - // unused - throw UnimplementedError(); - } -} diff --git a/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart deleted file mode 100644 index ab02e7ff7f..0000000000 --- a/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart +++ /dev/null @@ -1,3182 +0,0 @@ -import 'dart:collection'; -import 'dart:convert'; -import 'dart:core'; -import 'dart:developer' as developer; -import 'dart:io'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; - -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../in_app_browser/in_app_browser.dart'; -import '../print_job/main.dart'; -import '../web_message/main.dart'; -import '../web_storage/web_storage.dart'; - -import '_static_channel.dart'; -import 'headless_in_app_webview.dart'; - -/// Object specifying creation parameters for creating a [IOSInAppWebViewController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformInAppWebViewControllerCreationParams] for -/// more information. -@immutable -class IOSInAppWebViewControllerCreationParams - extends PlatformInAppWebViewControllerCreationParams { - /// Creates a new [IOSInAppWebViewControllerCreationParams] instance. - const IOSInAppWebViewControllerCreationParams({ - required super.id, - super.webviewParams, - }); - - /// Creates a [IOSInAppWebViewControllerCreationParams] instance based on [PlatformInAppWebViewControllerCreationParams]. - factory IOSInAppWebViewControllerCreationParams.fromPlatformInAppWebViewControllerCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformInAppWebViewControllerCreationParams params, - ) { - return IOSInAppWebViewControllerCreationParams( - id: params.id, - webviewParams: params.webviewParams, - ); - } -} - -///Controls a WebView, such as an [InAppWebView] widget instance, a [IOSHeadlessInAppWebView] instance or [IOSInAppBrowser] WebView instance. -/// -///If you are using the [InAppWebView] widget, an [InAppWebViewController] instance can be obtained by setting the [InAppWebView.onWebViewCreated] -///callback. Instead, if you are using an [IOSInAppBrowser] instance, you can get it through the [IOSInAppBrowser.webViewController] attribute. -class IOSInAppWebViewController extends PlatformInAppWebViewController - with ChannelController { - static final MethodChannel _staticChannel = IN_APP_WEBVIEW_STATIC_CHANNEL; - - // List of properties to be saved and restored for keep alive feature - Map _javaScriptHandlersMap = HashMap(); - Map> _userScripts = { - UserScriptInjectionTime.AT_DOCUMENT_START: [], - UserScriptInjectionTime.AT_DOCUMENT_END: [], - }; - Set _webMessageListenerObjNames = Set(); - Map _injectedScriptsFromURL = {}; - Set _webMessageChannels = Set(); - Set _webMessageListeners = Set(); - - // static map that contains the properties to be saved and restored for keep alive feature - static final Map - _keepAliveMap = {}; - - IOSInAppBrowser? _inAppBrowser; - - PlatformInAppBrowserEvents? get _inAppBrowserEventHandler => - _inAppBrowser?.eventHandler; - - dynamic _controllerFromPlatform; - - @override - late IOSWebStorage webStorage; - - IOSInAppWebViewController(PlatformInAppWebViewControllerCreationParams params) - : super.implementation( - params is IOSInAppWebViewControllerCreationParams - ? params - : IOSInAppWebViewControllerCreationParams.fromPlatformInAppWebViewControllerCreationParams( - params, - ), - ) { - channel = MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id'); - handler = handleMethod; - initMethodCallHandler(); - - final initialUserScripts = webviewParams?.initialUserScripts; - if (initialUserScripts != null) { - for (final userScript in initialUserScripts) { - if (userScript.injectionTime == - UserScriptInjectionTime.AT_DOCUMENT_START) { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.add( - userScript, - ); - } else { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.add( - userScript, - ); - } - } - } - - this._init(params); - } - - static final IOSInAppWebViewController _staticValue = - IOSInAppWebViewController( - IOSInAppWebViewControllerCreationParams(id: null), - ); - - factory IOSInAppWebViewController.static() { - return _staticValue; - } - - IOSInAppWebViewController.fromInAppBrowser( - PlatformInAppWebViewControllerCreationParams params, - MethodChannel channel, - IOSInAppBrowser inAppBrowser, - UnmodifiableListView? initialUserScripts, - ) : super.implementation( - params is IOSInAppWebViewControllerCreationParams - ? params - : IOSInAppWebViewControllerCreationParams.fromPlatformInAppWebViewControllerCreationParams( - params, - ), - ) { - this.channel = channel; - this._inAppBrowser = inAppBrowser; - - if (initialUserScripts != null) { - for (final userScript in initialUserScripts) { - if (userScript.injectionTime == - UserScriptInjectionTime.AT_DOCUMENT_START) { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.add( - userScript, - ); - } else { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.add( - userScript, - ); - } - } - } - this._init(params); - } - - void _init(PlatformInAppWebViewControllerCreationParams params) { - _controllerFromPlatform = - params.webviewParams?.controllerFromPlatform?.call(this) ?? this; - - webStorage = IOSWebStorage( - IOSWebStorageCreationParams( - localStorage: IOSLocalStorage.defaultStorage(controller: this), - sessionStorage: IOSSessionStorage.defaultStorage(controller: this), - ), - ); - - if (params.webviewParams is PlatformInAppWebViewWidgetCreationParams) { - final keepAlive = - (params.webviewParams as PlatformInAppWebViewWidgetCreationParams) - .keepAlive; - if (keepAlive != null) { - InAppWebViewControllerKeepAliveProps? props = _keepAliveMap[keepAlive]; - if (props == null) { - // save controller properties to restore it later - _keepAliveMap[keepAlive] = InAppWebViewControllerKeepAliveProps( - injectedScriptsFromURL: _injectedScriptsFromURL, - javaScriptHandlersMap: _javaScriptHandlersMap, - userScripts: _userScripts, - webMessageListenerObjNames: _webMessageListenerObjNames, - webMessageChannels: _webMessageChannels, - webMessageListeners: _webMessageListeners, - ); - } else { - // restore controller properties - _injectedScriptsFromURL = props.injectedScriptsFromURL; - _javaScriptHandlersMap = props.javaScriptHandlersMap; - _userScripts = props.userScripts; - _webMessageListenerObjNames = props.webMessageListenerObjNames; - _webMessageChannels = - props.webMessageChannels as Set; - _webMessageListeners = - props.webMessageListeners as Set; - } - } - } - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - name: _inAppBrowser == null - ? "WebView" - : _inAppBrowser.runtimeType.toString(), - id: (getViewId() ?? _inAppBrowser?.id).toString(), - debugLoggingSettings: PlatformInAppWebViewController.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - if (PlatformInAppWebViewController.debugLoggingSettings.enabled && - call.method != "onCallJsHandler") { - _debugLog(call.method, call.arguments); - } - - switch (call.method) { - case "onLoadStart": - _injectedScriptsFromURL.clear(); - if ((webviewParams != null && webviewParams!.onLoadStart != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - if (webviewParams != null && webviewParams!.onLoadStart != null) - webviewParams!.onLoadStart!(_controllerFromPlatform, uri); - else - _inAppBrowserEventHandler!.onLoadStart(uri); - } - break; - case "onLoadStop": - if ((webviewParams != null && webviewParams!.onLoadStop != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - if (webviewParams != null && webviewParams!.onLoadStop != null) - webviewParams!.onLoadStop!(_controllerFromPlatform, uri); - else - _inAppBrowserEventHandler!.onLoadStop(uri); - } - break; - case "onReceivedError": - if ((webviewParams != null && - (webviewParams!.onReceivedError != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadError != null)) || - _inAppBrowserEventHandler != null) { - WebResourceRequest request = WebResourceRequest.fromMap( - call.arguments["request"].cast(), - )!; - WebResourceError error = WebResourceError.fromMap( - call.arguments["error"].cast(), - )!; - var isForMainFrame = request.isForMainFrame ?? false; - - if (webviewParams != null) { - if (webviewParams!.onReceivedError != null) - webviewParams!.onReceivedError!( - _controllerFromPlatform, - request, - error, - ); - else if (isForMainFrame) { - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadError!( - _controllerFromPlatform, - request.url, - error.type.toNativeValue() ?? -1, - error.description, - ); - } - } else { - if (isForMainFrame) { - _inAppBrowserEventHandler!.onLoadError( - request.url, - error.type.toNativeValue() ?? -1, - error.description, - ); - } - _inAppBrowserEventHandler!.onReceivedError(request, error); - } - } - break; - case "onReceivedHttpError": - if ((webviewParams != null && - (webviewParams!.onReceivedHttpError != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadHttpError != null)) || - _inAppBrowserEventHandler != null) { - WebResourceRequest request = WebResourceRequest.fromMap( - call.arguments["request"].cast(), - )!; - WebResourceResponse errorResponse = WebResourceResponse.fromMap( - call.arguments["errorResponse"].cast(), - )!; - var isForMainFrame = request.isForMainFrame ?? false; - - if (webviewParams != null) { - if (webviewParams!.onReceivedHttpError != null) - webviewParams!.onReceivedHttpError!( - _controllerFromPlatform, - request, - errorResponse, - ); - else if (isForMainFrame) { - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadHttpError!( - _controllerFromPlatform, - request.url, - errorResponse.statusCode ?? -1, - errorResponse.reasonPhrase ?? '', - ); - } - } else { - if (isForMainFrame) { - _inAppBrowserEventHandler!.onLoadHttpError( - request.url, - errorResponse.statusCode ?? -1, - errorResponse.reasonPhrase ?? '', - ); - } - _inAppBrowserEventHandler!.onReceivedHttpError( - request, - errorResponse, - ); - } - } - break; - case "onProgressChanged": - if ((webviewParams != null && - webviewParams!.onProgressChanged != null) || - _inAppBrowserEventHandler != null) { - int progress = call.arguments["progress"]; - if (webviewParams != null && webviewParams!.onProgressChanged != null) - webviewParams!.onProgressChanged!( - _controllerFromPlatform, - progress, - ); - else - _inAppBrowserEventHandler!.onProgressChanged(progress); - } - break; - case "shouldOverrideUrlLoading": - if ((webviewParams != null && - webviewParams!.shouldOverrideUrlLoading != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - NavigationAction navigationAction = NavigationAction.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.shouldOverrideUrlLoading != null) - return (await webviewParams!.shouldOverrideUrlLoading!( - _controllerFromPlatform, - navigationAction, - ))?.toNativeValue(); - return (await _inAppBrowserEventHandler!.shouldOverrideUrlLoading( - navigationAction, - ))?.toNativeValue(); - } - break; - case "onConsoleMessage": - if ((webviewParams != null && - webviewParams!.onConsoleMessage != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - ConsoleMessage consoleMessage = ConsoleMessage.fromMap(arguments)!; - if (webviewParams != null && webviewParams!.onConsoleMessage != null) - webviewParams!.onConsoleMessage!( - _controllerFromPlatform, - consoleMessage, - ); - else - _inAppBrowserEventHandler!.onConsoleMessage(consoleMessage); - } - break; - case "onScrollChanged": - if ((webviewParams != null && webviewParams!.onScrollChanged != null) || - _inAppBrowserEventHandler != null) { - int x = call.arguments["x"]; - int y = call.arguments["y"]; - if (webviewParams != null && webviewParams!.onScrollChanged != null) - webviewParams!.onScrollChanged!(_controllerFromPlatform, x, y); - else - _inAppBrowserEventHandler!.onScrollChanged(x, y); - } - break; - case "onDownloadStarting": - if ((webviewParams != null && - (webviewParams!.onDownloadStart != null || - webviewParams!.onDownloadStartRequest != null || - webviewParams!.onDownloadStarting != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - DownloadStartRequest downloadStartRequest = - DownloadStartRequest.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.onDownloadStarting != null) - return (await webviewParams!.onDownloadStarting!( - _controllerFromPlatform, - downloadStartRequest, - ))?.toMap(); - else if (webviewParams!.onDownloadStartRequest != null) - webviewParams!.onDownloadStartRequest!( - _controllerFromPlatform, - downloadStartRequest, - ); - else { - webviewParams!.onDownloadStart!( - _controllerFromPlatform, - downloadStartRequest.url, - ); - } - } else { - _inAppBrowserEventHandler!.onDownloadStart( - downloadStartRequest.url, - ); - _inAppBrowserEventHandler!.onDownloadStartRequest( - downloadStartRequest, - ); - return (await _inAppBrowserEventHandler!.onDownloadStarting( - downloadStartRequest, - ))?.toMap(); - } - } - break; - case "onLoadResourceWithCustomScheme": - if ((webviewParams != null && - (webviewParams!.onLoadResourceWithCustomScheme != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadResourceCustomScheme != null)) || - _inAppBrowserEventHandler != null) { - Map requestMap = call.arguments["request"] - .cast(); - WebResourceRequest request = WebResourceRequest.fromMap(requestMap)!; - - if (webviewParams != null) { - if (webviewParams!.onLoadResourceWithCustomScheme != null) - return (await webviewParams!.onLoadResourceWithCustomScheme!( - _controllerFromPlatform, - request, - ))?.toMap(); - else { - return (await params - .webviewParams! - // ignore: deprecated_member_use_from_same_package - .onLoadResourceCustomScheme!( - _controllerFromPlatform, - request.url, - )) - ?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler! - .onLoadResourceWithCustomScheme(request)) ?? - (await _inAppBrowserEventHandler! - .onLoadResourceCustomScheme(request.url))) - ?.toMap(); - } - } - break; - case "onCreateWindow": - if ((webviewParams != null && webviewParams!.onCreateWindow != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - CreateWindowAction createWindowAction = CreateWindowAction.fromMap( - arguments, - )!; - - if (webviewParams != null && webviewParams!.onCreateWindow != null) - return await webviewParams!.onCreateWindow!( - _controllerFromPlatform, - createWindowAction, - ); - else - return await _inAppBrowserEventHandler!.onCreateWindow( - createWindowAction, - ); - } - break; - case "onCloseWindow": - if (webviewParams != null && webviewParams!.onCloseWindow != null) - webviewParams!.onCloseWindow!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onCloseWindow(); - break; - case "onTitleChanged": - if ((webviewParams != null && webviewParams!.onTitleChanged != null) || - _inAppBrowserEventHandler != null) { - String? title = call.arguments["title"]; - if (webviewParams != null && webviewParams!.onTitleChanged != null) - webviewParams!.onTitleChanged!(_controllerFromPlatform, title); - else - _inAppBrowserEventHandler!.onTitleChanged(title); - } - break; - case "onGeolocationPermissionsShowPrompt": - if ((webviewParams != null && - (webviewParams!.onGeolocationPermissionsShowPrompt != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnGeolocationPermissionsShowPrompt != - null)) || - _inAppBrowserEventHandler != null) { - String origin = call.arguments["origin"]; - - if (webviewParams != null) { - if (webviewParams!.onGeolocationPermissionsShowPrompt != null) - return (await webviewParams!.onGeolocationPermissionsShowPrompt!( - _controllerFromPlatform, - origin, - ))?.toMap(); - else { - return (await params - .webviewParams! - // ignore: deprecated_member_use_from_same_package - .androidOnGeolocationPermissionsShowPrompt!( - _controllerFromPlatform, - origin, - )) - ?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler! - .onGeolocationPermissionsShowPrompt(origin)) ?? - (await _inAppBrowserEventHandler! - .androidOnGeolocationPermissionsShowPrompt(origin))) - ?.toMap(); - } - } - break; - case "onGeolocationPermissionsHidePrompt": - if (webviewParams != null && - (webviewParams!.onGeolocationPermissionsHidePrompt != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnGeolocationPermissionsHidePrompt != - null)) { - if (webviewParams!.onGeolocationPermissionsHidePrompt != null) - webviewParams!.onGeolocationPermissionsHidePrompt!( - _controllerFromPlatform, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnGeolocationPermissionsHidePrompt!( - _controllerFromPlatform, - ); - } - } else if (_inAppBrowserEventHandler != null) { - _inAppBrowserEventHandler!.onGeolocationPermissionsHidePrompt(); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler! - .androidOnGeolocationPermissionsHidePrompt(); - } - break; - case "shouldInterceptRequest": - if ((webviewParams != null && - (webviewParams!.shouldInterceptRequest != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidShouldInterceptRequest != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - WebResourceRequest request = WebResourceRequest.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.shouldInterceptRequest != null) - return (await webviewParams!.shouldInterceptRequest!( - _controllerFromPlatform, - request, - ))?.toMap(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidShouldInterceptRequest!( - _controllerFromPlatform, - request, - ))?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler!.shouldInterceptRequest( - request, - )) ?? - (await _inAppBrowserEventHandler! - .androidShouldInterceptRequest(request))) - ?.toMap(); - } - } - break; - case "onRenderProcessUnresponsive": - if ((webviewParams != null && - (webviewParams!.onRenderProcessUnresponsive != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnRenderProcessUnresponsive != - null)) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - - if (webviewParams != null) { - if (webviewParams!.onRenderProcessUnresponsive != null) - return (await webviewParams!.onRenderProcessUnresponsive!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidOnRenderProcessUnresponsive!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - } - } else { - return ((await _inAppBrowserEventHandler! - .onRenderProcessUnresponsive(uri)) ?? - (await _inAppBrowserEventHandler! - .androidOnRenderProcessUnresponsive(uri))) - ?.toNativeValue(); - } - } - break; - case "onRenderProcessResponsive": - if ((webviewParams != null && - (webviewParams!.onRenderProcessResponsive != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnRenderProcessResponsive != null)) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - - if (webviewParams != null) { - if (webviewParams!.onRenderProcessResponsive != null) - return (await webviewParams!.onRenderProcessResponsive!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidOnRenderProcessResponsive!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - } - } else { - return ((await _inAppBrowserEventHandler!.onRenderProcessResponsive( - uri, - )) ?? - (await _inAppBrowserEventHandler! - .androidOnRenderProcessResponsive(uri))) - ?.toNativeValue(); - } - } - break; - case "onRenderProcessGone": - if ((webviewParams != null && - (webviewParams!.onRenderProcessGone != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnRenderProcessGone != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - RenderProcessGoneDetail detail = RenderProcessGoneDetail.fromMap( - arguments, - )!; - - if (webviewParams != null) { - if (webviewParams!.onRenderProcessGone != null) - webviewParams!.onRenderProcessGone!( - _controllerFromPlatform, - detail, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnRenderProcessGone!( - _controllerFromPlatform, - detail, - ); - } - } else if (_inAppBrowserEventHandler != null) { - _inAppBrowserEventHandler!.onRenderProcessGone(detail); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.androidOnRenderProcessGone(detail); - } - } - break; - case "onFormResubmission": - if ((webviewParams != null && - (webviewParams!.onFormResubmission != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnFormResubmission != null)) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - - if (webviewParams != null) { - if (webviewParams!.onFormResubmission != null) - return (await webviewParams!.onFormResubmission!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidOnFormResubmission!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - } - } else { - return ((await _inAppBrowserEventHandler!.onFormResubmission( - uri, - )) ?? - // ignore: deprecated_member_use_from_same_package - (await _inAppBrowserEventHandler!.androidOnFormResubmission( - uri, - ))) - ?.toNativeValue(); - } - } - break; - case "onZoomScaleChanged": - if ((webviewParams != null && - // ignore: deprecated_member_use_from_same_package - (webviewParams!.androidOnScaleChanged != null || - webviewParams!.onZoomScaleChanged != null)) || - _inAppBrowserEventHandler != null) { - double oldScale = call.arguments["oldScale"]; - double newScale = call.arguments["newScale"]; - - if (webviewParams != null) { - if (webviewParams!.onZoomScaleChanged != null) - webviewParams!.onZoomScaleChanged!( - _controllerFromPlatform, - oldScale, - newScale, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnScaleChanged!( - _controllerFromPlatform, - oldScale, - newScale, - ); - } - } else { - _inAppBrowserEventHandler!.onZoomScaleChanged(oldScale, newScale); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.androidOnScaleChanged( - oldScale, - newScale, - ); - } - } - break; - case "onReceivedIcon": - if ((webviewParams != null && - (webviewParams!.onReceivedIcon != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedIcon != null)) || - _inAppBrowserEventHandler != null) { - Uint8List icon = Uint8List.fromList( - call.arguments["icon"].cast(), - ); - - if (webviewParams != null) { - if (webviewParams!.onReceivedIcon != null) - webviewParams!.onReceivedIcon!(_controllerFromPlatform, icon); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedIcon!( - _controllerFromPlatform, - icon, - ); - } - } else { - _inAppBrowserEventHandler!.onReceivedIcon(icon); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.androidOnReceivedIcon(icon); - } - } - break; - case "onReceivedTouchIconUrl": - if ((webviewParams != null && - (webviewParams!.onReceivedTouchIconUrl != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedTouchIconUrl != null)) || - _inAppBrowserEventHandler != null) { - String url = call.arguments["url"]; - bool precomposed = call.arguments["precomposed"]; - WebUri uri = WebUri(url); - - if (webviewParams != null) { - if (webviewParams!.onReceivedTouchIconUrl != null) - webviewParams!.onReceivedTouchIconUrl!( - _controllerFromPlatform, - uri, - precomposed, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedTouchIconUrl!( - _controllerFromPlatform, - uri, - precomposed, - ); - } - } else { - _inAppBrowserEventHandler!.onReceivedTouchIconUrl(uri, precomposed); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.androidOnReceivedTouchIconUrl( - uri, - precomposed, - ); - } - } - break; - case "onJsAlert": - if ((webviewParams != null && webviewParams!.onJsAlert != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsAlertRequest jsAlertRequest = JsAlertRequest.fromMap(arguments)!; - - if (webviewParams != null && webviewParams!.onJsAlert != null) - return (await webviewParams!.onJsAlert!( - _controllerFromPlatform, - jsAlertRequest, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onJsAlert( - jsAlertRequest, - ))?.toMap(); - } - break; - case "onJsConfirm": - if ((webviewParams != null && webviewParams!.onJsConfirm != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsConfirmRequest jsConfirmRequest = JsConfirmRequest.fromMap( - arguments, - )!; - - if (webviewParams != null && webviewParams!.onJsConfirm != null) - return (await webviewParams!.onJsConfirm!( - _controllerFromPlatform, - jsConfirmRequest, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onJsConfirm( - jsConfirmRequest, - ))?.toMap(); - } - break; - case "onJsPrompt": - if ((webviewParams != null && webviewParams!.onJsPrompt != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsPromptRequest jsPromptRequest = JsPromptRequest.fromMap(arguments)!; - - if (webviewParams != null && webviewParams!.onJsPrompt != null) - return (await webviewParams!.onJsPrompt!( - _controllerFromPlatform, - jsPromptRequest, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onJsPrompt( - jsPromptRequest, - ))?.toMap(); - } - break; - case "onJsBeforeUnload": - if ((webviewParams != null && - (webviewParams!.onJsBeforeUnload != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnJsBeforeUnload != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsBeforeUnloadRequest jsBeforeUnloadRequest = - JsBeforeUnloadRequest.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.onJsBeforeUnload != null) - return (await webviewParams!.onJsBeforeUnload!( - _controllerFromPlatform, - jsBeforeUnloadRequest, - ))?.toMap(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidOnJsBeforeUnload!( - _controllerFromPlatform, - jsBeforeUnloadRequest, - ))?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler!.onJsBeforeUnload( - jsBeforeUnloadRequest, - )) ?? - (await _inAppBrowserEventHandler!.androidOnJsBeforeUnload( - jsBeforeUnloadRequest, - ))) - ?.toMap(); - } - } - break; - case "onSafeBrowsingHit": - if ((webviewParams != null && - (webviewParams!.onSafeBrowsingHit != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnSafeBrowsingHit != null)) || - _inAppBrowserEventHandler != null) { - String url = call.arguments["url"]; - SafeBrowsingThreat? threatType = SafeBrowsingThreat.fromNativeValue( - call.arguments["threatType"], - ); - WebUri uri = WebUri(url); - - if (webviewParams != null) { - if (webviewParams!.onSafeBrowsingHit != null) - return (await webviewParams!.onSafeBrowsingHit!( - _controllerFromPlatform, - uri, - threatType, - ))?.toMap(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidOnSafeBrowsingHit!( - _controllerFromPlatform, - uri, - threatType, - ))?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler!.onSafeBrowsingHit( - uri, - threatType, - )) ?? - (await _inAppBrowserEventHandler!.androidOnSafeBrowsingHit( - uri, - threatType, - ))) - ?.toMap(); - } - } - break; - case "onReceivedLoginRequest": - if ((webviewParams != null && - (webviewParams!.onReceivedLoginRequest != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedLoginRequest != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - LoginRequest loginRequest = LoginRequest.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.onReceivedLoginRequest != null) - webviewParams!.onReceivedLoginRequest!( - _controllerFromPlatform, - loginRequest, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedLoginRequest!( - _controllerFromPlatform, - loginRequest, - ); - } - } else { - _inAppBrowserEventHandler!.onReceivedLoginRequest(loginRequest); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.androidOnReceivedLoginRequest( - loginRequest, - ); - } - } - break; - case "onPermissionRequestCanceled": - if ((webviewParams != null && - webviewParams!.onPermissionRequestCanceled != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - PermissionRequest permissionRequest = PermissionRequest.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.onPermissionRequestCanceled != null) - webviewParams!.onPermissionRequestCanceled!( - _controllerFromPlatform, - permissionRequest, - ); - else - _inAppBrowserEventHandler!.onPermissionRequestCanceled( - permissionRequest, - ); - } - break; - case "onRequestFocus": - if ((webviewParams != null && webviewParams!.onRequestFocus != null) || - _inAppBrowserEventHandler != null) { - if (webviewParams != null && webviewParams!.onRequestFocus != null) - webviewParams!.onRequestFocus!(_controllerFromPlatform); - else - _inAppBrowserEventHandler!.onRequestFocus(); - } - break; - case "onReceivedHttpAuthRequest": - if ((webviewParams != null && - webviewParams!.onReceivedHttpAuthRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - HttpAuthenticationChallenge challenge = - HttpAuthenticationChallenge.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onReceivedHttpAuthRequest != null) - return (await webviewParams!.onReceivedHttpAuthRequest!( - _controllerFromPlatform, - challenge, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onReceivedHttpAuthRequest( - challenge, - ))?.toMap(); - } - break; - case "onReceivedServerTrustAuthRequest": - if ((webviewParams != null && - webviewParams!.onReceivedServerTrustAuthRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - ServerTrustChallenge challenge = ServerTrustChallenge.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.onReceivedServerTrustAuthRequest != null) - return (await webviewParams!.onReceivedServerTrustAuthRequest!( - _controllerFromPlatform, - challenge, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler! - .onReceivedServerTrustAuthRequest(challenge)) - ?.toMap(); - } - break; - case "onReceivedClientCertRequest": - if ((webviewParams != null && - webviewParams!.onReceivedClientCertRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - ClientCertChallenge challenge = ClientCertChallenge.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.onReceivedClientCertRequest != null) - return (await webviewParams!.onReceivedClientCertRequest!( - _controllerFromPlatform, - challenge, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler! - .onReceivedClientCertRequest(challenge)) - ?.toMap(); - } - break; - case "onFindResultReceived": - if ((webviewParams != null && - (webviewParams!.onFindResultReceived != null || - (webviewParams!.findInteractionController != null && - webviewParams! - .findInteractionController! - .params - .onFindResultReceived != - null))) || - _inAppBrowserEventHandler != null) { - int activeMatchOrdinal = call.arguments["activeMatchOrdinal"]; - int numberOfMatches = call.arguments["numberOfMatches"]; - bool isDoneCounting = call.arguments["isDoneCounting"]; - if (webviewParams != null) { - if (webviewParams!.findInteractionController != null && - webviewParams! - .findInteractionController! - .params - .onFindResultReceived != - null) - webviewParams! - .findInteractionController! - .params - .onFindResultReceived!( - webviewParams!.findInteractionController!, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - else - webviewParams!.onFindResultReceived!( - _controllerFromPlatform, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - } else { - if (_inAppBrowser!.findInteractionController != null && - _inAppBrowser! - .findInteractionController! - .onFindResultReceived != - null) - _inAppBrowser!.findInteractionController!.onFindResultReceived!( - webviewParams!.findInteractionController!, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - else - _inAppBrowserEventHandler!.onFindResultReceived( - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - } - } - break; - case "onPermissionRequest": - if ((webviewParams != null && - (webviewParams!.onPermissionRequest != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnPermissionRequest != null)) || - _inAppBrowserEventHandler != null) { - String origin = call.arguments["origin"]; - List resources = call.arguments["resources"].cast(); - - Map arguments = call.arguments - .cast(); - PermissionRequest permissionRequest = PermissionRequest.fromMap( - arguments, - )!; - - if (webviewParams != null) { - if (webviewParams!.onPermissionRequest != null) - return (await webviewParams!.onPermissionRequest!( - _controllerFromPlatform, - permissionRequest, - ))?.toMap(); - else { - return (await webviewParams!.androidOnPermissionRequest!( - _controllerFromPlatform, - origin, - resources, - ))?.toMap(); - } - } else { - return (await _inAppBrowserEventHandler!.onPermissionRequest( - permissionRequest, - ))?.toMap() ?? - (await _inAppBrowserEventHandler!.androidOnPermissionRequest( - origin, - resources, - ))?.toMap(); - } - } - break; - case "onUpdateVisitedHistory": - if ((webviewParams != null && - webviewParams!.onUpdateVisitedHistory != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - bool? isReload = call.arguments["isReload"]; - WebUri? uri = url != null ? WebUri(url) : null; - if (webviewParams != null && - webviewParams!.onUpdateVisitedHistory != null) - webviewParams!.onUpdateVisitedHistory!( - _controllerFromPlatform, - uri, - isReload, - ); - else - _inAppBrowserEventHandler!.onUpdateVisitedHistory(uri, isReload); - } - break; - case "onWebContentProcessDidTerminate": - if (webviewParams != null && - (webviewParams!.onWebContentProcessDidTerminate != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.iosOnWebContentProcessDidTerminate != null)) { - if (webviewParams!.onWebContentProcessDidTerminate != null) - webviewParams!.onWebContentProcessDidTerminate!( - _controllerFromPlatform, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.iosOnWebContentProcessDidTerminate!( - _controllerFromPlatform, - ); - } - } else if (_inAppBrowserEventHandler != null) { - _inAppBrowserEventHandler!.onWebContentProcessDidTerminate(); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.iosOnWebContentProcessDidTerminate(); - } - break; - case "onPageCommitVisible": - if ((webviewParams != null && - webviewParams!.onPageCommitVisible != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - if (webviewParams != null && - webviewParams!.onPageCommitVisible != null) - webviewParams!.onPageCommitVisible!(_controllerFromPlatform, uri); - else - _inAppBrowserEventHandler!.onPageCommitVisible(uri); - } - break; - case "onDidReceiveServerRedirectForProvisionalNavigation": - if (webviewParams != null && - (webviewParams! - .onDidReceiveServerRedirectForProvisionalNavigation != - null || - params - .webviewParams! - // ignore: deprecated_member_use_from_same_package - .iosOnDidReceiveServerRedirectForProvisionalNavigation != - null)) { - if (webviewParams! - .onDidReceiveServerRedirectForProvisionalNavigation != - null) - webviewParams!.onDidReceiveServerRedirectForProvisionalNavigation!( - _controllerFromPlatform, - ); - else { - params - .webviewParams! - // ignore: deprecated_member_use_from_same_package - .iosOnDidReceiveServerRedirectForProvisionalNavigation!( - _controllerFromPlatform, - ); - } - } else if (_inAppBrowserEventHandler != null) { - _inAppBrowserEventHandler! - .onDidReceiveServerRedirectForProvisionalNavigation(); - _inAppBrowserEventHandler! - .iosOnDidReceiveServerRedirectForProvisionalNavigation(); - } - break; - case "onNavigationResponse": - if ((webviewParams != null && - (webviewParams!.onNavigationResponse != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.iosOnNavigationResponse != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - // ignore: deprecated_member_use_from_same_package - IOSWKNavigationResponse iosOnNavigationResponse = - // ignore: deprecated_member_use_from_same_package - IOSWKNavigationResponse.fromMap(arguments)!; - - NavigationResponse navigationResponse = NavigationResponse.fromMap( - arguments, - )!; - - if (webviewParams != null) { - if (webviewParams!.onNavigationResponse != null) - return (await webviewParams!.onNavigationResponse!( - _controllerFromPlatform, - navigationResponse, - ))?.toNativeValue(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.iosOnNavigationResponse!( - _controllerFromPlatform, - iosOnNavigationResponse, - ))?.toNativeValue(); - } - } else { - return (await _inAppBrowserEventHandler!.onNavigationResponse( - navigationResponse, - ))?.toNativeValue() ?? - (await _inAppBrowserEventHandler!.iosOnNavigationResponse( - iosOnNavigationResponse, - ))?.toNativeValue(); - } - } - break; - case "shouldAllowDeprecatedTLS": - if ((webviewParams != null && - (webviewParams!.shouldAllowDeprecatedTLS != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.iosShouldAllowDeprecatedTLS != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - URLAuthenticationChallenge challenge = - URLAuthenticationChallenge.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.shouldAllowDeprecatedTLS != null) - return (await webviewParams!.shouldAllowDeprecatedTLS!( - _controllerFromPlatform, - challenge, - ))?.toNativeValue(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.iosShouldAllowDeprecatedTLS!( - _controllerFromPlatform, - challenge, - ))?.toNativeValue(); - } - } else { - return (await _inAppBrowserEventHandler!.shouldAllowDeprecatedTLS( - challenge, - ))?.toNativeValue() ?? - // ignore: deprecated_member_use_from_same_package - (await _inAppBrowserEventHandler!.iosShouldAllowDeprecatedTLS( - challenge, - ))?.toNativeValue(); - } - } - break; - case "onLongPressHitTestResult": - if ((webviewParams != null && - webviewParams!.onLongPressHitTestResult != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - InAppWebViewHitTestResult hitTestResult = - InAppWebViewHitTestResult.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onLongPressHitTestResult != null) - webviewParams!.onLongPressHitTestResult!( - _controllerFromPlatform, - hitTestResult, - ); - else - _inAppBrowserEventHandler!.onLongPressHitTestResult(hitTestResult); - } - break; - case "onCreateContextMenu": - ContextMenu? contextMenu; - if (webviewParams != null && webviewParams!.contextMenu != null) { - contextMenu = webviewParams!.contextMenu; - } else if (_inAppBrowserEventHandler != null && - _inAppBrowser!.contextMenu != null) { - contextMenu = _inAppBrowser!.contextMenu; - } - - if (contextMenu != null && contextMenu.onCreateContextMenu != null) { - Map arguments = call.arguments - .cast(); - InAppWebViewHitTestResult hitTestResult = - InAppWebViewHitTestResult.fromMap(arguments)!; - - contextMenu.onCreateContextMenu!(hitTestResult); - } - break; - case "onHideContextMenu": - ContextMenu? contextMenu; - if (webviewParams != null && webviewParams!.contextMenu != null) { - contextMenu = webviewParams!.contextMenu; - } else if (_inAppBrowserEventHandler != null && - _inAppBrowser!.contextMenu != null) { - contextMenu = _inAppBrowser!.contextMenu; - } - - if (contextMenu != null && contextMenu.onHideContextMenu != null) { - contextMenu.onHideContextMenu!(); - } - break; - case "onContextMenuActionItemClicked": - ContextMenu? contextMenu; - if (webviewParams != null && webviewParams!.contextMenu != null) { - contextMenu = webviewParams!.contextMenu; - } else if (_inAppBrowserEventHandler != null && - _inAppBrowser!.contextMenu != null) { - contextMenu = _inAppBrowser!.contextMenu; - } - - if (contextMenu != null) { - int? androidId = call.arguments["androidId"]; - String? iosId = call.arguments["iosId"]; - dynamic id = call.arguments["id"]; - String title = call.arguments["title"]; - - ContextMenuItem menuItemClicked = ContextMenuItem( - id: id, - // ignore: deprecated_member_use_from_same_package - androidId: androidId, - // ignore: deprecated_member_use_from_same_package - iosId: iosId, - title: title, - action: null, - ); - - for (var menuItem in contextMenu.menuItems) { - if (menuItem.id == id) { - menuItemClicked = menuItem; - if (menuItem.action != null) { - menuItem.action!(); - } - break; - } - } - - if (contextMenu.onContextMenuActionItemClicked != null) { - contextMenu.onContextMenuActionItemClicked!(menuItemClicked); - } - } - break; - case "onEnterFullscreen": - if (webviewParams != null && webviewParams!.onEnterFullscreen != null) - webviewParams!.onEnterFullscreen!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onEnterFullscreen(); - break; - case "onExitFullscreen": - if (webviewParams != null && webviewParams!.onExitFullscreen != null) - webviewParams!.onExitFullscreen!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onExitFullscreen(); - break; - case "onOverScrolled": - if ((webviewParams != null && webviewParams!.onOverScrolled != null) || - _inAppBrowserEventHandler != null) { - int x = call.arguments["x"]; - int y = call.arguments["y"]; - bool clampedX = call.arguments["clampedX"]; - bool clampedY = call.arguments["clampedY"]; - - if (webviewParams != null && webviewParams!.onOverScrolled != null) - webviewParams!.onOverScrolled!( - _controllerFromPlatform, - x, - y, - clampedX, - clampedY, - ); - else - _inAppBrowserEventHandler!.onOverScrolled(x, y, clampedX, clampedY); - } - break; - case "onWindowFocus": - if (webviewParams != null && webviewParams!.onWindowFocus != null) - webviewParams!.onWindowFocus!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onWindowFocus(); - break; - case "onWindowBlur": - if (webviewParams != null && webviewParams!.onWindowBlur != null) - webviewParams!.onWindowBlur!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onWindowBlur(); - break; - case "onPrintRequest": - if ((webviewParams != null && - (webviewParams!.onPrintRequest != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onPrint != null)) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - String? printJobId = call.arguments["printJobId"]; - WebUri? uri = url != null ? WebUri(url) : null; - IOSPrintJobController? printJob = printJobId != null - ? IOSPrintJobController( - IOSPrintJobControllerCreationParams(id: printJobId), - ) - : null; - - if (webviewParams != null) { - if (webviewParams!.onPrintRequest != null) - return await webviewParams!.onPrintRequest!( - _controllerFromPlatform, - uri, - printJob, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.onPrint!(_controllerFromPlatform, uri); - return false; - } - } else { - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.onPrint(uri); - return await _inAppBrowserEventHandler!.onPrintRequest( - uri, - printJob, - ); - } - } - break; - case "onInjectedScriptLoaded": - String id = call.arguments[0]; - var onLoadCallback = _injectedScriptsFromURL[id]?.onLoad; - if ((webviewParams != null || _inAppBrowserEventHandler != null) && - onLoadCallback != null) { - onLoadCallback(); - } - break; - case "onInjectedScriptError": - String id = call.arguments[0]; - var onErrorCallback = _injectedScriptsFromURL[id]?.onError; - if ((webviewParams != null || _inAppBrowserEventHandler != null) && - onErrorCallback != null) { - onErrorCallback(); - } - break; - case "onCameraCaptureStateChanged": - if ((webviewParams != null && - webviewParams!.onCameraCaptureStateChanged != null) || - _inAppBrowserEventHandler != null) { - var oldState = MediaCaptureState.fromNativeValue( - call.arguments["oldState"], - ); - var newState = MediaCaptureState.fromNativeValue( - call.arguments["newState"], - ); - - if (webviewParams != null && - webviewParams!.onCameraCaptureStateChanged != null) - webviewParams!.onCameraCaptureStateChanged!( - _controllerFromPlatform, - oldState, - newState, - ); - else - _inAppBrowserEventHandler!.onCameraCaptureStateChanged( - oldState, - newState, - ); - } - break; - case "onMicrophoneCaptureStateChanged": - if ((webviewParams != null && - webviewParams!.onMicrophoneCaptureStateChanged != null) || - _inAppBrowserEventHandler != null) { - var oldState = MediaCaptureState.fromNativeValue( - call.arguments["oldState"], - ); - var newState = MediaCaptureState.fromNativeValue( - call.arguments["newState"], - ); - - if (webviewParams != null && - webviewParams!.onMicrophoneCaptureStateChanged != null) - webviewParams!.onMicrophoneCaptureStateChanged!( - _controllerFromPlatform, - oldState, - newState, - ); - else - _inAppBrowserEventHandler!.onMicrophoneCaptureStateChanged( - oldState, - newState, - ); - } - break; - case "onContentSizeChanged": - if ((webviewParams != null && - webviewParams!.onContentSizeChanged != null) || - _inAppBrowserEventHandler != null) { - var oldContentSize = MapSize.fromMap( - call.arguments["oldContentSize"]?.cast(), - )!; - var newContentSize = MapSize.fromMap( - call.arguments["newContentSize"]?.cast(), - )!; - - if (webviewParams != null && - webviewParams!.onContentSizeChanged != null) - webviewParams!.onContentSizeChanged!( - _controllerFromPlatform, - oldContentSize, - newContentSize, - ); - else - _inAppBrowserEventHandler!.onContentSizeChanged( - oldContentSize, - newContentSize, - ); - } - break; - case "onCallJsHandler": - String handlerName = call.arguments["handlerName"]; - Map handlerDataMap = call.arguments["data"] - .cast(); - // decode args to json - handlerDataMap["args"] = jsonDecode(handlerDataMap["args"]); - final handlerData = JavaScriptHandlerFunctionData.fromMap( - handlerDataMap, - )!; - - _debugLog(handlerName, handlerData); - - switch (handlerName) { - case "onLoadResource": - if ((webviewParams != null && - webviewParams!.onLoadResource != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - arguments["startTime"] = arguments["startTime"] is int - ? arguments["startTime"].toDouble() - : arguments["startTime"]; - arguments["duration"] = arguments["duration"] is int - ? arguments["duration"].toDouble() - : arguments["duration"]; - - var response = LoadedResource.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onLoadResource != null) - webviewParams!.onLoadResource!( - _controllerFromPlatform, - response, - ); - else - _inAppBrowserEventHandler!.onLoadResource(response); - } - return null; - case "shouldInterceptAjaxRequest": - if ((webviewParams != null && - webviewParams!.shouldInterceptAjaxRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - AjaxRequest request = AjaxRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.shouldInterceptAjaxRequest != null) - return jsonEncode( - await params.webviewParams!.shouldInterceptAjaxRequest!( - _controllerFromPlatform, - request, - ), - ); - else - return jsonEncode( - await _inAppBrowserEventHandler!.shouldInterceptAjaxRequest( - request, - ), - ); - } - return null; - case "onAjaxReadyStateChange": - if ((webviewParams != null && - webviewParams!.onAjaxReadyStateChange != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - AjaxRequest request = AjaxRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onAjaxReadyStateChange != null) - return jsonEncode( - (await webviewParams!.onAjaxReadyStateChange!( - _controllerFromPlatform, - request, - ))?.toNativeValue(), - ); - else - return jsonEncode( - (await _inAppBrowserEventHandler!.onAjaxReadyStateChange( - request, - ))?.toNativeValue(), - ); - } - return null; - case "onAjaxProgress": - if ((webviewParams != null && - webviewParams!.onAjaxProgress != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - AjaxRequest request = AjaxRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onAjaxProgress != null) - return jsonEncode( - (await webviewParams!.onAjaxProgress!( - _controllerFromPlatform, - request, - ))?.toNativeValue(), - ); - else - return jsonEncode( - (await _inAppBrowserEventHandler!.onAjaxProgress( - request, - ))?.toNativeValue(), - ); - } - return null; - case "shouldInterceptFetchRequest": - if ((webviewParams != null && - webviewParams!.shouldInterceptFetchRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - FetchRequest request = FetchRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.shouldInterceptFetchRequest != null) - return jsonEncode( - await webviewParams!.shouldInterceptFetchRequest!( - _controllerFromPlatform, - request, - ), - ); - else - return jsonEncode( - await _inAppBrowserEventHandler!.shouldInterceptFetchRequest( - request, - ), - ); - } - return null; - case "onWindowFocus": - if (webviewParams != null && webviewParams!.onWindowFocus != null) - webviewParams!.onWindowFocus!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onWindowFocus(); - return null; - case "onWindowBlur": - if (webviewParams != null && webviewParams!.onWindowBlur != null) - webviewParams!.onWindowBlur!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onWindowBlur(); - return null; - case "onInjectedScriptLoaded": - String id = handlerData.args[0]; - var onLoadCallback = _injectedScriptsFromURL[id]?.onLoad; - if ((webviewParams != null || _inAppBrowserEventHandler != null) && - onLoadCallback != null) { - onLoadCallback(); - } - return null; - case "onInjectedScriptError": - String id = handlerData.args[0]; - var onErrorCallback = _injectedScriptsFromURL[id]?.onError; - if ((webviewParams != null || _inAppBrowserEventHandler != null) && - onErrorCallback != null) { - onErrorCallback(); - } - return null; - } - - if (_javaScriptHandlersMap.containsKey(handlerName)) { - // convert result to json - try { - var jsHandlerResult = null; - if (_javaScriptHandlersMap[handlerName] - is JavaScriptHandlerCallback) { - jsHandlerResult = - await (_javaScriptHandlersMap[handlerName] - as JavaScriptHandlerCallback)(handlerData.args); - } else if (_javaScriptHandlersMap[handlerName] - is JavaScriptHandlerFunction) { - jsHandlerResult = - await (_javaScriptHandlersMap[handlerName] - as JavaScriptHandlerFunction)(handlerData); - } else { - jsHandlerResult = await _javaScriptHandlersMap[handlerName]!(); - } - return jsonEncode(jsHandlerResult); - } catch (error, stacktrace) { - developer.log( - error.toString() + '\n' + stacktrace.toString(), - name: 'JavaScript Handler "$handlerName"', - ); - throw Exception(error.toString().replaceFirst('Exception: ', '')); - } - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - Future getUrl() async { - Map args = {}; - String? url = await channel?.invokeMethod('getUrl', args); - return url != null ? WebUri(url) : null; - } - - @override - Future getTitle() async { - Map args = {}; - return await channel?.invokeMethod('getTitle', args); - } - - @override - Future getProgress() async { - Map args = {}; - return await channel?.invokeMethod('getProgress', args); - } - - @override - Future getHtml() async { - String? html; - - InAppWebViewSettings? settings = await getSettings(); - if (settings != null && settings.javaScriptEnabled == true) { - html = await evaluateJavascript( - source: "window.document.getElementsByTagName('html')[0].outerHTML;", - ); - if (html != null && html.isNotEmpty) return html; - } - - var webviewUrl = await getUrl(); - if (webviewUrl == null) { - return html; - } - - if (webviewUrl.isScheme("file")) { - var assetPathSplit = webviewUrl.toString().split("/flutter_assets/"); - var assetPath = assetPathSplit[assetPathSplit.length - 1]; - try { - var bytes = await rootBundle.load(assetPath); - html = utf8.decode(bytes.buffer.asUint8List()); - } catch (e) {} - } else { - try { - HttpClient client = HttpClient(); - var htmlRequest = await client.getUrl(webviewUrl); - html = await (await htmlRequest.close()) - .transform(Utf8Decoder()) - .join(); - } catch (e) { - developer.log(e.toString(), name: this.runtimeType.toString()); - } - } - - return html; - } - - @override - Future> getFavicons() async { - List favicons = []; - - var webviewUrl = await getUrl(); - - if (webviewUrl == null) { - return favicons; - } - - String? manifestUrl; - - var html = await getHtml(); - if (html == null || html.isEmpty) { - return favicons; - } - var assetPathBase; - - if (webviewUrl.isScheme("file")) { - var assetPathSplit = webviewUrl.toString().split("/flutter_assets/"); - assetPathBase = assetPathSplit[0] + "/flutter_assets/"; - } - - InAppWebViewSettings? settings = await getSettings(); - if (settings != null && settings.javaScriptEnabled == true) { - List> links = - (await evaluateJavascript( - source: """ -(function() { - var linkNodes = document.head.getElementsByTagName("link"); - var links = []; - for (var i = 0; i < linkNodes.length; i++) { - var linkNode = linkNodes[i]; - if (linkNode.rel === 'manifest') { - links.push( - { - rel: linkNode.rel, - href: linkNode.href, - sizes: null - } - ); - } else if (linkNode.rel != null && linkNode.rel.indexOf('icon') >= 0) { - links.push( - { - rel: linkNode.rel, - href: linkNode.href, - sizes: linkNode.sizes != null && linkNode.sizes.value != "" ? linkNode.sizes.value : null - } - ); - } - } - return links; -})(); -""", - ))?.cast>() ?? - []; - for (var link in links) { - if (link["rel"] == "manifest") { - manifestUrl = link["href"]; - if (!_isUrlAbsolute(manifestUrl!)) { - if (manifestUrl.startsWith("/")) { - manifestUrl = manifestUrl.substring(1); - } - manifestUrl = - ((assetPathBase == null) - ? webviewUrl.scheme + "://" + webviewUrl.host + "/" - : assetPathBase) + - manifestUrl; - } - continue; - } - favicons.addAll( - _createFavicons( - webviewUrl, - assetPathBase, - link["href"], - link["rel"], - link["sizes"], - false, - ), - ); - } - } - - // try to get /favicon.ico - try { - HttpClient client = HttpClient(); - var faviconUrl = - webviewUrl.scheme + "://" + webviewUrl.host + "/favicon.ico"; - var faviconUri = WebUri(faviconUrl); - var headRequest = await client.headUrl(faviconUri); - var headResponse = await headRequest.close(); - if (headResponse.statusCode == 200) { - favicons.add(Favicon(url: faviconUri, rel: "shortcut icon")); - } - } catch (e) { - developer.log( - "/favicon.ico file not found: " + e.toString(), - name: runtimeType.toString(), - ); - } - - // try to get the manifest file - HttpClientRequest? manifestRequest; - HttpClientResponse? manifestResponse; - bool manifestFound = false; - if (manifestUrl == null) { - manifestUrl = - webviewUrl.scheme + "://" + webviewUrl.host + "/manifest.json"; - } - try { - HttpClient client = HttpClient(); - manifestRequest = await client.getUrl(Uri.parse(manifestUrl)); - manifestResponse = await manifestRequest.close(); - manifestFound = - manifestResponse.statusCode == 200 && - manifestResponse.headers.contentType?.mimeType == "application/json"; - } catch (e) { - developer.log( - "Manifest file not found: " + e.toString(), - name: this.runtimeType.toString(), - ); - } - - if (manifestFound) { - try { - Map manifest = json.decode( - await manifestResponse!.transform(Utf8Decoder()).join(), - ); - if (manifest.containsKey("icons")) { - for (Map icon in manifest["icons"]) { - favicons.addAll( - _createFavicons( - webviewUrl, - assetPathBase, - icon["src"], - icon["rel"], - icon["sizes"], - true, - ), - ); - } - } - } catch (e) { - developer.log( - "Cannot get favicons from Manifest file. It might not have a valid format: " + - e.toString(), - error: e, - name: runtimeType.toString(), - ); - } - } - - return favicons; - } - - bool _isUrlAbsolute(String url) { - return url.startsWith("http://") || url.startsWith("https://"); - } - - List _createFavicons( - WebUri url, - String? assetPathBase, - String urlIcon, - String? rel, - String? sizes, - bool isManifest, - ) { - List favicons = []; - - List urlSplit = urlIcon.split("/"); - if (!_isUrlAbsolute(urlIcon)) { - if (urlIcon.startsWith("/")) { - urlIcon = urlIcon.substring(1); - } - urlIcon = - ((assetPathBase == null) - ? url.scheme + "://" + url.host + "/" - : assetPathBase) + - urlIcon; - } - if (isManifest) { - rel = (sizes != null) - ? urlSplit[urlSplit.length - 1] - .replaceFirst("-" + sizes, "") - .split(" ")[0] - .split(".")[0] - : null; - } - if (sizes != null && sizes.isNotEmpty && sizes != "any") { - List sizesSplit = sizes.split(" "); - for (String size in sizesSplit) { - int width = int.parse(size.split("x")[0]); - int height = int.parse(size.split("x")[1]); - favicons.add( - Favicon(url: WebUri(urlIcon), rel: rel, width: width, height: height), - ); - } - } else { - favicons.add( - Favicon(url: WebUri(urlIcon), rel: rel, width: null, height: null), - ); - } - - return favicons; - } - - @override - Future loadUrl({ - required URLRequest urlRequest, - @Deprecated('Use allowingReadAccessTo instead') - Uri? iosAllowingReadAccessTo, - WebUri? allowingReadAccessTo, - }) async { - assert(urlRequest.url != null && urlRequest.url.toString().isNotEmpty); - assert( - allowingReadAccessTo == null || allowingReadAccessTo.isScheme("file"), - ); - assert( - iosAllowingReadAccessTo == null || - iosAllowingReadAccessTo.isScheme("file"), - ); - - Map args = {}; - args.putIfAbsent('urlRequest', () => urlRequest.toMap()); - args.putIfAbsent( - 'allowingReadAccessTo', - () => - allowingReadAccessTo?.toString() ?? - iosAllowingReadAccessTo?.toString(), - ); - await channel?.invokeMethod('loadUrl', args); - } - - @override - Future postUrl({ - required WebUri url, - required Uint8List postData, - }) async { - assert(url.toString().isNotEmpty); - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - args.putIfAbsent('postData', () => postData); - await channel?.invokeMethod('postUrl', args); - } - - @override - Future loadData({ - required String data, - String mimeType = "text/html", - String encoding = "utf8", - WebUri? baseUrl, - @Deprecated('Use historyUrl instead') Uri? androidHistoryUrl, - WebUri? historyUrl, - @Deprecated('Use allowingReadAccessTo instead') - Uri? iosAllowingReadAccessTo, - WebUri? allowingReadAccessTo, - }) async { - assert( - allowingReadAccessTo == null || allowingReadAccessTo.isScheme("file"), - ); - assert( - iosAllowingReadAccessTo == null || - iosAllowingReadAccessTo.isScheme("file"), - ); - - Map args = {}; - args.putIfAbsent('data', () => data); - args.putIfAbsent('mimeType', () => mimeType); - args.putIfAbsent('encoding', () => encoding); - args.putIfAbsent('baseUrl', () => baseUrl?.toString() ?? "about:blank"); - args.putIfAbsent( - 'historyUrl', - () => - historyUrl?.toString() ?? - androidHistoryUrl?.toString() ?? - "about:blank", - ); - args.putIfAbsent( - 'allowingReadAccessTo', - () => - allowingReadAccessTo?.toString() ?? - iosAllowingReadAccessTo?.toString(), - ); - await channel?.invokeMethod('loadData', args); - } - - @override - Future loadFile({required String assetFilePath}) async { - assert(assetFilePath.isNotEmpty); - Map args = {}; - args.putIfAbsent('assetFilePath', () => assetFilePath); - await channel?.invokeMethod('loadFile', args); - } - - @override - Future reload() async { - Map args = {}; - await channel?.invokeMethod('reload', args); - } - - @override - Future goBack() async { - Map args = {}; - await channel?.invokeMethod('goBack', args); - } - - @override - Future canGoBack() async { - Map args = {}; - return await channel?.invokeMethod('canGoBack', args) ?? false; - } - - @override - Future goForward() async { - Map args = {}; - await channel?.invokeMethod('goForward', args); - } - - @override - Future canGoForward() async { - Map args = {}; - return await channel?.invokeMethod('canGoForward', args) ?? false; - } - - @override - Future goBackOrForward({required int steps}) async { - Map args = {}; - args.putIfAbsent('steps', () => steps); - await channel?.invokeMethod('goBackOrForward', args); - } - - @override - Future canGoBackOrForward({required int steps}) async { - Map args = {}; - args.putIfAbsent('steps', () => steps); - return await channel?.invokeMethod('canGoBackOrForward', args) ?? - false; - } - - @override - Future goTo({required WebHistoryItem historyItem}) async { - var steps = historyItem.offset; - if (steps != null) { - await goBackOrForward(steps: steps); - } - } - - @override - Future isLoading() async { - Map args = {}; - return await channel?.invokeMethod('isLoading', args) ?? false; - } - - @override - Future stopLoading() async { - Map args = {}; - await channel?.invokeMethod('stopLoading', args); - } - - @override - Future evaluateJavascript({ - required String source, - ContentWorld? contentWorld, - }) async { - Map args = {}; - args.putIfAbsent('source', () => source); - args.putIfAbsent('contentWorld', () => contentWorld?.toMap()); - var data = await channel?.invokeMethod('evaluateJavascript', args); - return data; - } - - @override - Future injectJavascriptFileFromUrl({ - required WebUri urlFile, - ScriptHtmlTagAttributes? scriptHtmlTagAttributes, - }) async { - assert(urlFile.toString().isNotEmpty); - var id = scriptHtmlTagAttributes?.id; - if (scriptHtmlTagAttributes != null && id != null) { - _injectedScriptsFromURL[id] = scriptHtmlTagAttributes; - } - Map args = {}; - args.putIfAbsent('urlFile', () => urlFile.toString()); - args.putIfAbsent( - 'scriptHtmlTagAttributes', - () => scriptHtmlTagAttributes?.toMap(), - ); - await channel?.invokeMethod('injectJavascriptFileFromUrl', args); - } - - @override - Future injectJavascriptFileFromAsset({ - required String assetFilePath, - }) async { - String source = await rootBundle.loadString(assetFilePath); - return await evaluateJavascript(source: source); - } - - @override - Future injectCSSCode({required String source}) async { - Map args = {}; - args.putIfAbsent('source', () => source); - await channel?.invokeMethod('injectCSSCode', args); - } - - @override - Future injectCSSFileFromUrl({ - required WebUri urlFile, - CSSLinkHtmlTagAttributes? cssLinkHtmlTagAttributes, - }) async { - assert(urlFile.toString().isNotEmpty); - Map args = {}; - args.putIfAbsent('urlFile', () => urlFile.toString()); - args.putIfAbsent( - 'cssLinkHtmlTagAttributes', - () => cssLinkHtmlTagAttributes?.toMap(), - ); - await channel?.invokeMethod('injectCSSFileFromUrl', args); - } - - @override - Future injectCSSFileFromAsset({required String assetFilePath}) async { - String source = await rootBundle.loadString(assetFilePath); - await injectCSSCode(source: source); - } - - @override - void addJavaScriptHandler({ - required String handlerName, - required Function callback, - }) { - assert( - !kJavaScriptHandlerForbiddenNames.contains(handlerName), - '"$handlerName" is a forbidden name!', - ); - this._javaScriptHandlersMap[handlerName] = (callback); - } - - @override - Function? removeJavaScriptHandler({required String handlerName}) { - return this._javaScriptHandlersMap.remove(handlerName); - } - - @override - bool hasJavaScriptHandler({required String handlerName}) { - return this._javaScriptHandlersMap.containsKey(handlerName); - } - - @override - Future takeScreenshot({ - ScreenshotConfiguration? screenshotConfiguration, - }) async { - Map args = {}; - args.putIfAbsent( - 'screenshotConfiguration', - () => screenshotConfiguration?.toMap(), - ); - return await channel?.invokeMethod('takeScreenshot', args); - } - - @override - @Deprecated('Use setSettings instead') - Future setOptions({required InAppWebViewGroupOptions options}) async { - InAppWebViewSettings settings = - InAppWebViewSettings.fromMap(options.toMap()) ?? InAppWebViewSettings(); - await setSettings(settings: settings); - } - - @override - @Deprecated('Use getSettings instead') - Future getOptions() async { - InAppWebViewSettings? settings = await getSettings(); - - Map? options = settings?.toMap(); - if (options != null) { - options = options.cast(); - return InAppWebViewGroupOptions.fromMap(options as Map); - } - - return null; - } - - @override - Future setSettings({required InAppWebViewSettings settings}) async { - Map args = {}; - - args.putIfAbsent('settings', () => settings.toMap()); - await channel?.invokeMethod('setSettings', args); - } - - @override - Future getSettings() async { - Map args = {}; - - Map? settings = await channel?.invokeMethod( - 'getSettings', - args, - ); - if (settings != null) { - settings = settings.cast(); - return InAppWebViewSettings.fromMap(settings as Map); - } - - return null; - } - - @override - Future getCopyBackForwardList() async { - Map args = {}; - Map? result = (await channel?.invokeMethod( - 'getCopyBackForwardList', - args, - ))?.cast(); - return WebHistory.fromMap(result); - } - - @override - @Deprecated("Use InAppWebViewController.clearAllCache instead") - Future clearCache() async { - Map args = {}; - await channel?.invokeMethod('clearCache', args); - } - - @override - @Deprecated("Use FindInteractionController.findAll instead") - Future findAllAsync({required String find}) async { - Map args = {}; - args.putIfAbsent('find', () => find); - await channel?.invokeMethod('findAll', args); - } - - @override - @Deprecated("Use FindInteractionController.findNext instead") - Future findNext({required bool forward}) async { - Map args = {}; - args.putIfAbsent('forward', () => forward); - await channel?.invokeMethod('findNext', args); - } - - @override - @Deprecated("Use FindInteractionController.clearMatches instead") - Future clearMatches() async { - Map args = {}; - await channel?.invokeMethod('clearMatches', args); - } - - @override - @Deprecated("Use tRexRunnerHtml instead") - Future getTRexRunnerHtml() async { - return await tRexRunnerHtml; - } - - @override - @Deprecated("Use tRexRunnerCss instead") - Future getTRexRunnerCss() async { - return await tRexRunnerCss; - } - - @override - Future scrollTo({ - required int x, - required int y, - bool animated = false, - }) async { - Map args = {}; - args.putIfAbsent('x', () => x); - args.putIfAbsent('y', () => y); - args.putIfAbsent('animated', () => animated); - await channel?.invokeMethod('scrollTo', args); - } - - @override - Future scrollBy({ - required int x, - required int y, - bool animated = false, - }) async { - Map args = {}; - args.putIfAbsent('x', () => x); - args.putIfAbsent('y', () => y); - args.putIfAbsent('animated', () => animated); - await channel?.invokeMethod('scrollBy', args); - } - - @override - Future pauseTimers() async { - Map args = {}; - await channel?.invokeMethod('pauseTimers', args); - } - - @override - Future resumeTimers() async { - Map args = {}; - await channel?.invokeMethod('resumeTimers', args); - } - - @override - Future printCurrentPage({ - PrintJobSettings? settings, - }) async { - Map args = {}; - args.putIfAbsent("settings", () => settings?.toMap()); - String? jobId = await channel?.invokeMethod( - 'printCurrentPage', - args, - ); - if (jobId != null) { - return IOSPrintJobController( - PlatformPrintJobControllerCreationParams(id: jobId), - ); - } - return null; - } - - @override - Future getContentHeight() async { - Map args = {}; - var height = await channel?.invokeMethod('getContentHeight', args); - if (height == null || height == 0) { - // try to use javascript - var scrollHeight = await evaluateJavascript( - source: "document.documentElement.scrollHeight;", - ); - if (scrollHeight != null && scrollHeight is num) { - height = scrollHeight.toInt(); - } - } - return height; - } - - @override - Future getContentWidth() async { - Map args = {}; - var height = await channel?.invokeMethod('getContentWidth', args); - if (height == null || height == 0) { - // try to use javascript - var scrollHeight = await evaluateJavascript( - source: "document.documentElement.scrollWidth;", - ); - if (scrollHeight != null && scrollHeight is num) { - height = scrollHeight.toInt(); - } - } - return height; - } - - @override - Future zoomBy({ - required double zoomFactor, - @Deprecated('Use animated instead') bool? iosAnimated, - bool animated = false, - }) async { - Map args = {}; - args.putIfAbsent('zoomFactor', () => zoomFactor); - args.putIfAbsent('animated', () => iosAnimated ?? animated); - return await channel?.invokeMethod('zoomBy', args); - } - - @override - Future getOriginalUrl() async { - Map args = {}; - String? url = await channel?.invokeMethod('getOriginalUrl', args); - return url != null ? WebUri(url) : null; - } - - @override - Future getZoomScale() async { - Map args = {}; - return await channel?.invokeMethod('getZoomScale', args); - } - - @override - @Deprecated('Use getZoomScale instead') - Future getScale() async { - return await getZoomScale(); - } - - @override - Future getSelectedText() async { - Map args = {}; - return await channel?.invokeMethod('getSelectedText', args); - } - - @override - Future getHitTestResult() async { - Map args = {}; - Map? hitTestResultMap = await channel?.invokeMethod( - 'getHitTestResult', - args, - ); - - if (hitTestResultMap == null) { - return null; - } - - hitTestResultMap = hitTestResultMap.cast(); - - InAppWebViewHitTestResultType? type = - InAppWebViewHitTestResultType.fromNativeValue( - hitTestResultMap["type"]?.toInt(), - ); - String? extra = hitTestResultMap["extra"]; - return InAppWebViewHitTestResult(type: type, extra: extra); - } - - @override - Future clearFocus() async { - Map args = {}; - return await channel?.invokeMethod('clearFocus', args); - } - - @override - Future setInputMethodEnabled(bool enabled) async { - Map args = {}; - args.putIfAbsent("enabled", () => enabled); - return await channel?.invokeMethod('setInputMethodEnabled', args); - } - - @override - Future hideInputMethod() async { - Map args = {}; - return await channel?.invokeMethod('hideInputMethod', args); - } - - @override - Future requestFocus({ - FocusDirection? direction, - InAppWebViewRect? previouslyFocusedRect, - }) async { - Map args = {}; - args.putIfAbsent("direction", () => direction?.toNativeValue()); - args.putIfAbsent( - "previouslyFocusedRect", - () => previouslyFocusedRect?.toMap(), - ); - return await channel?.invokeMethod('requestFocus', args); - } - - @override - Future setContextMenu(ContextMenu? contextMenu) async { - Map args = {}; - args.putIfAbsent("contextMenu", () => contextMenu?.toMap()); - await channel?.invokeMethod('setContextMenu', args); - _inAppBrowser?.setContextMenu(contextMenu); - } - - @override - Future requestFocusNodeHref() async { - Map args = {}; - Map? result = await channel?.invokeMethod( - 'requestFocusNodeHref', - args, - ); - return result != null - ? RequestFocusNodeHrefResult( - url: result['url'] != null ? WebUri(result['url']) : null, - title: result['title'], - src: result['src'], - ) - : null; - } - - @override - Future requestImageRef() async { - Map args = {}; - Map? result = await channel?.invokeMethod( - 'requestImageRef', - args, - ); - return result != null - ? RequestImageRefResult( - url: result['url'] != null ? WebUri(result['url']) : null, - ) - : null; - } - - @override - Future> getMetaTags() async { - List metaTags = []; - - List>? metaTagList = (await evaluateJavascript( - source: """ -(function() { - var metaTags = []; - var metaTagNodes = document.head.getElementsByTagName('meta'); - for (var i = 0; i < metaTagNodes.length; i++) { - var metaTagNode = metaTagNodes[i]; - - var otherAttributes = metaTagNode.getAttributeNames(); - var nameIndex = otherAttributes.indexOf("name"); - if (nameIndex !== -1) otherAttributes.splice(nameIndex, 1); - var contentIndex = otherAttributes.indexOf("content"); - if (contentIndex !== -1) otherAttributes.splice(contentIndex, 1); - - var attrs = []; - for (var j = 0; j < otherAttributes.length; j++) { - var otherAttribute = otherAttributes[j]; - attrs.push( - { - name: otherAttribute, - value: metaTagNode.getAttribute(otherAttribute) - } - ); - } - - metaTags.push( - { - name: metaTagNode.name, - content: metaTagNode.content, - attrs: attrs - } - ); - } - return metaTags; -})(); - """, - ))?.cast>(); - - if (metaTagList == null) { - return metaTags; - } - - for (var metaTag in metaTagList) { - var attrs = []; - - for (var metaTagAttr in metaTag["attrs"]) { - attrs.add( - MetaTagAttribute( - name: metaTagAttr["name"], - value: metaTagAttr["value"], - ), - ); - } - - metaTags.add( - MetaTag( - name: metaTag["name"], - content: metaTag["content"], - attrs: attrs, - ), - ); - } - - return metaTags; - } - - @override - Future getMetaThemeColor() async { - Color? themeColor; - - try { - Map args = {}; - themeColor = UtilColor.fromStringRepresentation( - await channel?.invokeMethod('getMetaThemeColor', args), - ); - return themeColor; - } catch (e) { - // not implemented - } - - // try using javascript - var metaTags = await getMetaTags(); - MetaTag? metaTagThemeColor; - - for (var metaTag in metaTags) { - if (metaTag.name == "theme-color") { - metaTagThemeColor = metaTag; - break; - } - } - - if (metaTagThemeColor == null) { - return null; - } - - var colorValue = metaTagThemeColor.content; - - themeColor = colorValue != null - ? UtilColor.fromStringRepresentation(colorValue) - : null; - - return themeColor; - } - - @override - Future getScrollX() async { - Map args = {}; - return await channel?.invokeMethod('getScrollX', args); - } - - @override - Future getScrollY() async { - Map args = {}; - return await channel?.invokeMethod('getScrollY', args); - } - - @override - Future getCertificate() async { - Map args = {}; - Map? sslCertificateMap = (await channel?.invokeMethod( - 'getCertificate', - args, - ))?.cast(); - return SslCertificate.fromMap(sslCertificateMap); - } - - @override - Future addUserScript({required UserScript userScript}) async { - assert(webviewParams?.windowId == null); - - Map args = {}; - args.putIfAbsent('userScript', () => userScript.toMap()); - if (!(_userScripts[userScript.injectionTime]?.contains(userScript) ?? - false)) { - _userScripts[userScript.injectionTime]?.add(userScript); - await channel?.invokeMethod('addUserScript', args); - } - } - - @override - Future addUserScripts({required List userScripts}) async { - assert(webviewParams?.windowId == null); - - for (var i = 0; i < userScripts.length; i++) { - await addUserScript(userScript: userScripts[i]); - } - } - - @override - Future removeUserScript({required UserScript userScript}) async { - assert(webviewParams?.windowId == null); - - var index = _userScripts[userScript.injectionTime]?.indexOf(userScript); - if (index == null || index == -1) { - return false; - } - - _userScripts[userScript.injectionTime]?.remove(userScript); - Map args = {}; - args.putIfAbsent('userScript', () => userScript.toMap()); - args.putIfAbsent('index', () => index); - await channel?.invokeMethod('removeUserScript', args); - - return true; - } - - @override - Future removeUserScriptsByGroupName({required String groupName}) async { - assert(webviewParams?.windowId == null); - - final List userScriptsAtDocumentStart = List.from( - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_START] ?? [], - ); - for (final userScript in userScriptsAtDocumentStart) { - if (userScript.groupName == groupName) { - _userScripts[userScript.injectionTime]?.remove(userScript); - } - } - - final List userScriptsAtDocumentEnd = List.from( - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_END] ?? [], - ); - for (final userScript in userScriptsAtDocumentEnd) { - if (userScript.groupName == groupName) { - _userScripts[userScript.injectionTime]?.remove(userScript); - } - } - - Map args = {}; - args.putIfAbsent('groupName', () => groupName); - await channel?.invokeMethod('removeUserScriptsByGroupName', args); - } - - @override - Future removeUserScripts({ - required List userScripts, - }) async { - assert(webviewParams?.windowId == null); - - for (final userScript in userScripts) { - await removeUserScript(userScript: userScript); - } - } - - @override - Future removeAllUserScripts() async { - assert(webviewParams?.windowId == null); - - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.clear(); - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.clear(); - - Map args = {}; - await channel?.invokeMethod('removeAllUserScripts', args); - } - - @override - bool hasUserScript({required UserScript userScript}) { - return _userScripts[userScript.injectionTime]?.contains(userScript) ?? - false; - } - - @override - Future callAsyncJavaScript({ - required String functionBody, - Map arguments = const {}, - ContentWorld? contentWorld, - }) async { - Map args = {}; - args.putIfAbsent('functionBody', () => functionBody); - args.putIfAbsent('arguments', () => arguments); - args.putIfAbsent('contentWorld', () => contentWorld?.toMap()); - var data = await channel?.invokeMethod('callAsyncJavaScript', args); - if (data == null) { - return null; - } - return CallAsyncJavaScriptResult( - value: data["value"], - error: data["error"], - ); - } - - @override - Future saveWebArchive({ - required String filePath, - bool autoname = false, - }) async { - if (!autoname) { - assert( - WebArchiveFormat.WEBARCHIVE.isSupported() && - filePath.endsWith( - "." + WebArchiveFormat.WEBARCHIVE.toNativeValue()!, - ), - ); - } - - Map args = {}; - args.putIfAbsent("filePath", () => filePath); - args.putIfAbsent("autoname", () => autoname); - return await channel?.invokeMethod('saveWebArchive', args); - } - - @override - Future isSecureContext() async { - Map args = {}; - return await channel?.invokeMethod('isSecureContext', args) ?? false; - } - - @override - Future createWebMessageChannel() async { - Map args = {}; - Map? result = (await channel?.invokeMethod( - 'createWebMessageChannel', - args, - ))?.cast(); - final webMessageChannel = IOSWebMessageChannel.static().fromMap(result); - if (webMessageChannel != null) { - _webMessageChannels.add(webMessageChannel); - } - return webMessageChannel; - } - - @override - Future postWebMessage({ - required WebMessage message, - WebUri? targetOrigin, - }) async { - if (targetOrigin == null) { - targetOrigin = WebUri(''); - } - Map args = {}; - args.putIfAbsent('message', () => message.toMap()); - args.putIfAbsent('targetOrigin', () => targetOrigin.toString()); - await channel?.invokeMethod('postWebMessage', args); - } - - @override - Future addWebMessageListener( - PlatformWebMessageListener webMessageListener, - ) async { - assert( - !_webMessageListeners.contains(webMessageListener), - "${webMessageListener} was already added.", - ); - assert( - !_webMessageListenerObjNames.contains( - webMessageListener.params.jsObjectName, - ), - "jsObjectName ${webMessageListener.params.jsObjectName} was already added.", - ); - _webMessageListeners.add(webMessageListener as IOSWebMessageListener); - _webMessageListenerObjNames.add(webMessageListener.params.jsObjectName); - - Map args = {}; - args.putIfAbsent('webMessageListener', () => webMessageListener.toMap()); - await channel?.invokeMethod('addWebMessageListener', args); - } - - @override - bool hasWebMessageListener(PlatformWebMessageListener webMessageListener) { - return _webMessageListeners.contains(webMessageListener) || - _webMessageListenerObjNames.contains( - webMessageListener.params.jsObjectName, - ); - } - - @override - Future canScrollVertically() async { - Map args = {}; - return await channel?.invokeMethod('canScrollVertically', args) ?? - false; - } - - @override - Future canScrollHorizontally() async { - Map args = {}; - return await channel?.invokeMethod('canScrollHorizontally', args) ?? - false; - } - - @override - Future reloadFromOrigin() async { - Map args = {}; - await channel?.invokeMethod('reloadFromOrigin', args); - } - - @override - Future createPdf({ - @Deprecated("Use pdfConfiguration instead") - // ignore: deprecated_member_use_from_same_package - IOSWKPDFConfiguration? iosWKPdfConfiguration, - PDFConfiguration? pdfConfiguration, - }) async { - Map args = {}; - args.putIfAbsent( - 'pdfConfiguration', - () => pdfConfiguration?.toMap() ?? iosWKPdfConfiguration?.toMap(), - ); - return await channel?.invokeMethod('createPdf', args); - } - - @override - Future createWebArchiveData() async { - Map args = {}; - return await channel?.invokeMethod('createWebArchiveData', args); - } - - @override - Future hasOnlySecureContent() async { - Map args = {}; - return await channel?.invokeMethod('hasOnlySecureContent', args) ?? - false; - } - - @override - Future pauseAllMediaPlayback() async { - Map args = {}; - return await channel?.invokeMethod('pauseAllMediaPlayback', args); - } - - @override - Future setAllMediaPlaybackSuspended({required bool suspended}) async { - Map args = {}; - args.putIfAbsent("suspended", () => suspended); - return await channel?.invokeMethod('setAllMediaPlaybackSuspended', args); - } - - @override - Future closeAllMediaPresentations() async { - Map args = {}; - return await channel?.invokeMethod('closeAllMediaPresentations', args); - } - - @override - Future requestMediaPlaybackState() async { - Map args = {}; - return MediaPlaybackState.fromNativeValue( - await channel?.invokeMethod('requestMediaPlaybackState', args), - ); - } - - @override - Future isInFullscreen() async { - Map args = {}; - return await channel?.invokeMethod('isInFullscreen', args) ?? false; - } - - @override - Future getCameraCaptureState() async { - Map args = {}; - return MediaCaptureState.fromNativeValue( - await channel?.invokeMethod('getCameraCaptureState', args), - ); - } - - @override - Future setCameraCaptureState({required MediaCaptureState state}) async { - Map args = {}; - args.putIfAbsent('state', () => state.toNativeValue()); - await channel?.invokeMethod('setCameraCaptureState', args); - } - - @override - Future getMicrophoneCaptureState() async { - Map args = {}; - return MediaCaptureState.fromNativeValue( - await channel?.invokeMethod('getMicrophoneCaptureState', args), - ); - } - - @override - Future setMicrophoneCaptureState({ - required MediaCaptureState state, - }) async { - Map args = {}; - args.putIfAbsent('state', () => state.toNativeValue()); - await channel?.invokeMethod('setMicrophoneCaptureState', args); - } - - @override - Future loadSimulatedRequest({ - required URLRequest urlRequest, - required Uint8List data, - URLResponse? urlResponse, - }) async { - Map args = {}; - args.putIfAbsent('urlRequest', () => urlRequest.toMap()); - args.putIfAbsent('data', () => data); - args.putIfAbsent('urlResponse', () => urlResponse?.toMap()); - await channel?.invokeMethod('loadSimulatedRequest', args); - } - - @override - Future saveState() async { - Map args = {}; - return await channel?.invokeMethod('saveState', args); - } - - @override - Future restoreState(Uint8List? state) async { - Map args = {}; - args.putIfAbsent('state', () => state); - return await channel?.invokeMethod('restoreState', args) ?? false; - } - - @override - Future getDefaultUserAgent() async { - Map args = {}; - return await _staticChannel.invokeMethod( - 'getDefaultUserAgent', - args, - ) ?? - ''; - } - - @override - Future handlesURLScheme(String urlScheme) async { - Map args = {}; - args.putIfAbsent('urlScheme', () => urlScheme); - return await _staticChannel.invokeMethod('handlesURLScheme', args); - } - - @override - Future disposeKeepAlive(InAppWebViewKeepAlive keepAlive) async { - Map args = {}; - args.putIfAbsent('keepAliveId', () => keepAlive.id); - await _staticChannel.invokeMethod('disposeKeepAlive', args); - _keepAliveMap[keepAlive] = null; - } - - @override - Future clearAllCache({bool includeDiskFiles = true}) async { - Map args = {}; - args.putIfAbsent('includeDiskFiles', () => includeDiskFiles); - await _staticChannel.invokeMethod('clearAllCache', args); - } - - @override - Future setJavaScriptBridgeName(String bridgeName) async { - assert( - RegExp(r'^[a-zA-Z_]\w*$').hasMatch(bridgeName), - 'bridgeName must be a non-empty string with only alphanumeric and underscore characters. It can\'t start with a number.', - ); - Map args = {}; - args.putIfAbsent('bridgeName', () => bridgeName); - await _staticChannel.invokeMethod('setJavaScriptBridgeName', args); - } - - @override - Future getJavaScriptBridgeName() async { - Map args = {}; - return await _staticChannel.invokeMethod( - 'getJavaScriptBridgeName', - args, - ) ?? - ''; - } - - @override - Future get tRexRunnerHtml async => await rootBundle.loadString( - 'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html', - ); - - @override - Future get tRexRunnerCss async => await rootBundle.loadString( - 'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.css', - ); - - @override - dynamic getViewId() { - return id; - } - - @override - void dispose({bool isKeepAlive = false}) { - disposeChannel(removeMethodCallHandler: !isKeepAlive); - _inAppBrowser = null; - webStorage.dispose(); - if (!isKeepAlive) { - _controllerFromPlatform = null; - _javaScriptHandlersMap.clear(); - _userScripts.clear(); - _webMessageListenerObjNames.clear(); - _injectedScriptsFromURL.clear(); - for (final webMessageChannel in _webMessageChannels) { - webMessageChannel.dispose(); - } - _webMessageChannels.clear(); - for (final webMessageListener in _webMessageListeners) { - webMessageListener.dispose(); - } - _webMessageListeners.clear(); - } - } -} - -extension InternalInAppWebViewController on IOSInAppWebViewController { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_ios/lib/src/in_app_webview/main.dart b/flutter_inappwebview_ios/lib/src/in_app_webview/main.dart deleted file mode 100644 index b83b0611e7..0000000000 --- a/flutter_inappwebview_ios/lib/src/in_app_webview/main.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'in_app_webview_controller.dart' hide InternalInAppWebViewController; -export 'in_app_webview.dart'; -export 'headless_in_app_webview.dart' hide InternalHeadlessInAppWebView; diff --git a/flutter_inappwebview_ios/lib/src/inappwebview_platform.dart b/flutter_inappwebview_ios/lib/src/inappwebview_platform.dart deleted file mode 100644 index 9467277bbe..0000000000 --- a/flutter_inappwebview_ios/lib/src/inappwebview_platform.dart +++ /dev/null @@ -1,713 +0,0 @@ -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import 'chrome_safari_browser/chrome_safari_browser.dart'; -import 'cookie_manager.dart'; -import 'find_interaction/main.dart'; -import 'http_auth_credentials_database.dart'; -import 'in_app_browser/in_app_browser.dart'; -import 'in_app_webview/main.dart'; -import 'print_job/main.dart'; -import 'proxy_controller.dart'; -import 'pull_to_refresh/main.dart'; -import 'web_authentication_session/main.dart'; -import 'web_message/main.dart'; -import 'web_storage/main.dart'; - -/// Implementation of [InAppWebViewPlatform] using the WebKit API. -class IOSInAppWebViewPlatform extends InAppWebViewPlatform { - /// Registers this class as the default instance of [InAppWebViewPlatform]. - static void registerWith() { - InAppWebViewPlatform.instance = IOSInAppWebViewPlatform(); - } - - /// Creates a new [IOSCookieManager]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [CookieManager] in `flutter_inappwebview` instead. - @override - IOSCookieManager createPlatformCookieManager( - PlatformCookieManagerCreationParams params, - ) { - return IOSCookieManager(params); - } - - /// Creates a new empty [IOSCookieManager] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [CookieManager] in `flutter_inappwebview` instead. - @override - IOSCookieManager createPlatformCookieManagerStatic() { - return IOSCookieManager.static(); - } - - /// Creates a new [IOSInAppWebViewController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebViewController] in `flutter_inappwebview` instead. - @override - IOSInAppWebViewController createPlatformInAppWebViewController( - PlatformInAppWebViewControllerCreationParams params, - ) { - return IOSInAppWebViewController(params); - } - - /// Creates a new empty [IOSInAppWebViewController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebViewController] in `flutter_inappwebview` instead. - @override - IOSInAppWebViewController createPlatformInAppWebViewControllerStatic() { - return IOSInAppWebViewController.static(); - } - - /// Creates a new [IOSInAppWebViewWidget]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebView] in `flutter_inappwebview` instead. - @override - IOSInAppWebViewWidget createPlatformInAppWebViewWidget( - PlatformInAppWebViewWidgetCreationParams params, - ) { - return IOSInAppWebViewWidget(params); - } - - /// Creates a new empty [IOSInAppWebViewWidget] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebView] in `flutter_inappwebview` instead. - @override - IOSInAppWebViewWidget createPlatformInAppWebViewWidgetStatic() { - return IOSInAppWebViewWidget.static(); - } - - /// Creates a new [IOSFindInteractionController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [FindInteractionController] in `flutter_inappwebview` instead. - @override - IOSFindInteractionController createPlatformFindInteractionController( - PlatformFindInteractionControllerCreationParams params, - ) { - return IOSFindInteractionController(params); - } - - /// Creates a new empty [IOSFindInteractionController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [FindInteractionController] in `flutter_inappwebview` instead. - @override - IOSFindInteractionController createPlatformFindInteractionControllerStatic() { - return IOSFindInteractionController.static(); - } - - /// Creates a new [IOSPrintJobController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [PrintJobController] in `flutter_inappwebview` instead. - @override - IOSPrintJobController createPlatformPrintJobController( - PlatformPrintJobControllerCreationParams params, - ) { - return IOSPrintJobController(params); - } - - /// Creates a new empty [PlatformPrintJobController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [PrintJobController] in `flutter_inappwebview` instead. - @override - IOSPrintJobController createPlatformPrintJobControllerStatic() { - return IOSPrintJobController.static(); - } - - /// Creates a new [IOSPullToRefreshController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [PullToRefreshController] in `flutter_inappwebview` instead. - @override - IOSPullToRefreshController createPlatformPullToRefreshController( - PlatformPullToRefreshControllerCreationParams params, - ) { - return IOSPullToRefreshController(params); - } - - /// Creates a new empty [IOSPullToRefreshController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [PullToRefreshController] in `flutter_inappwebview` instead. - @override - IOSPullToRefreshController createPlatformPullToRefreshControllerStatic() { - return IOSPullToRefreshController.static(); - } - - /// Creates a new [IOSWebMessageChannel]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebMessageChannel] in `flutter_inappwebview` instead. - @override - IOSWebMessageChannel createPlatformWebMessageChannel( - PlatformWebMessageChannelCreationParams params, - ) { - return IOSWebMessageChannel(params); - } - - /// Creates a new empty [IOSWebMessageChannel] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebMessageChannel] in `flutter_inappwebview` instead. - @override - IOSWebMessageChannel createPlatformWebMessageChannelStatic() { - return IOSWebMessageChannel.static(); - } - - /// Creates a new [IOSWebMessageListener]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebMessageListener] in `flutter_inappwebview` instead. - @override - IOSWebMessageListener createPlatformWebMessageListener( - PlatformWebMessageListenerCreationParams params, - ) { - return IOSWebMessageListener(params); - } - - /// Creates a new empty [IOSWebMessageListener] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebMessageListener] in `flutter_inappwebview` instead. - @override - IOSWebMessageListener createPlatformWebMessageListenerStatic() { - return IOSWebMessageListener.static(); - } - - /// Creates a new [IOSJavaScriptReplyProxy]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [JavaScriptReplyProxy] in `flutter_inappwebview` instead. - @override - IOSJavaScriptReplyProxy createPlatformJavaScriptReplyProxy( - PlatformJavaScriptReplyProxyCreationParams params, - ) { - return IOSJavaScriptReplyProxy(params); - } - - /// Creates a new [IOSWebMessagePort]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebMessagePort] in `flutter_inappwebview` instead. - @override - IOSWebMessagePort createPlatformWebMessagePort( - PlatformWebMessagePortCreationParams params, - ) { - return IOSWebMessagePort(params); - } - - /// Creates a new [IOSWebStorage]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebStorage] in `flutter_inappwebview` instead. - @override - IOSWebStorage createPlatformWebStorage( - PlatformWebStorageCreationParams params, - ) { - return IOSWebStorage(params); - } - - /// Creates a new empty [IOSWebStorage] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebStorage] in `flutter_inappwebview` instead. - @override - IOSWebStorage createPlatformWebStorageStatic() { - return IOSWebStorage( - IOSWebStorageCreationParams( - localStorage: createPlatformLocalStorageStatic(), - sessionStorage: createPlatformSessionStorageStatic(), - ), - ); - } - - /// Creates a new [IOSLocalStorage]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [LocalStorage] in `flutter_inappwebview` instead. - @override - IOSLocalStorage createPlatformLocalStorage( - PlatformLocalStorageCreationParams params, - ) { - return IOSLocalStorage(params); - } - - /// Creates a new empty [IOSLocalStorage] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [LocalStorage] in `flutter_inappwebview` instead. - @override - IOSLocalStorage createPlatformLocalStorageStatic() { - return IOSLocalStorage.defaultStorage(controller: null); - } - - /// Creates a new [IOSSessionStorage]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [SessionStorage] in `flutter_inappwebview` instead. - @override - IOSSessionStorage createPlatformSessionStorage( - PlatformSessionStorageCreationParams params, - ) { - return IOSSessionStorage(params); - } - - /// Creates a new empty [IOSSessionStorage] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [SessionStorage] in `flutter_inappwebview` instead. - @override - IOSSessionStorage createPlatformSessionStorageStatic() { - return IOSSessionStorage.defaultStorage(controller: null); - } - - /// Creates a new [IOSHeadlessInAppWebView]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [HeadlessInAppWebView] in `flutter_inappwebview` instead. - @override - IOSHeadlessInAppWebView createPlatformHeadlessInAppWebView( - PlatformHeadlessInAppWebViewCreationParams params, - ) { - return IOSHeadlessInAppWebView(params); - } - - /// Creates a new empty [IOSHeadlessInAppWebView] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [HeadlessInAppWebView] in `flutter_inappwebview` instead. - @override - IOSHeadlessInAppWebView createPlatformHeadlessInAppWebViewStatic() { - return IOSHeadlessInAppWebView.static(); - } - - /// Creates a new [IOSHttpAuthCredentialDatabase]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [HttpAuthCredentialDatabase] in `flutter_inappwebview` instead. - @override - IOSHttpAuthCredentialDatabase createPlatformHttpAuthCredentialDatabase( - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) { - return IOSHttpAuthCredentialDatabase(params); - } - - /// Creates a new empty [IOSHttpAuthCredentialDatabase] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [HttpAuthCredentialDatabase] in `flutter_inappwebview` instead. - @override - IOSHttpAuthCredentialDatabase - createPlatformHttpAuthCredentialDatabaseStatic() { - return IOSHttpAuthCredentialDatabase.static(); - } - - /// Creates a new [IOSInAppBrowser]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppBrowser] in `flutter_inappwebview` instead. - @override - IOSInAppBrowser createPlatformInAppBrowser( - PlatformInAppBrowserCreationParams params, - ) { - return IOSInAppBrowser(params); - } - - /// Creates a new empty [IOSInAppBrowser] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppBrowser] in `flutter_inappwebview` instead. - @override - IOSInAppBrowser createPlatformInAppBrowserStatic() { - return IOSInAppBrowser.static(); - } - - /// Creates a new [IOSChromeSafariBrowser]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ChromeSafariBrowser] in `flutter_inappwebview` instead. - @override - IOSChromeSafariBrowser createPlatformChromeSafariBrowser( - PlatformChromeSafariBrowserCreationParams params, - ) { - return IOSChromeSafariBrowser(params); - } - - /// Creates a new empty [IOSChromeSafariBrowser] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ChromeSafariBrowser] in `flutter_inappwebview` instead. - @override - IOSChromeSafariBrowser createPlatformChromeSafariBrowserStatic() { - return IOSChromeSafariBrowser.static(); - } - - /// Creates a new empty [IOSWebStorageManager] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebStorageManager] in `flutter_inappwebview` instead. - @override - IOSWebStorageManager createPlatformWebStorageManager( - PlatformWebStorageManagerCreationParams params, - ) { - return IOSWebStorageManager(params); - } - - /// Creates a new empty [IOSWebStorageManager] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebStorageManager] in `flutter_inappwebview` instead. - @override - IOSWebStorageManager createPlatformWebStorageManagerStatic() { - return IOSWebStorageManager.static(); - } - - /// Creates a new [IOSWebAuthenticationSession]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebAuthenticationSession] in `flutter_inappwebview` instead. - @override - IOSWebAuthenticationSession createPlatformWebAuthenticationSession( - PlatformWebAuthenticationSessionCreationParams params, - ) { - return IOSWebAuthenticationSession(params); - } - - /// Creates a new empty [IOSWebAuthenticationSession] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebAuthenticationSession] in `flutter_inappwebview` instead. - @override - IOSWebAuthenticationSession createPlatformWebAuthenticationSessionStatic() { - return IOSWebAuthenticationSession.static(); - } - - /// Creates a new [IOSProxyController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ProxyController] in `flutter_inappwebview` instead. - @override - PlatformProxyController createPlatformProxyController( - PlatformProxyControllerCreationParams params, - ) { - return IOSProxyController(params); - } - - /// Creates a new empty [IOSProxyController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ProxyController] in `flutter_inappwebview` instead. - @override - IOSProxyController createPlatformProxyControllerStatic() { - return IOSProxyController.static(); - } - - // ************************************************************************ // - // Create static instances of unsupported classes to be able to call // - // isClassSupported, isMethodSupported, isPropertySupported, etc. // - // static methods without throwing a missing platform implementation // - // exception. // - // ************************************************************************ // - - /// Creates a new empty [PlatformWebViewEnvironment] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebViewEnvironment] in `flutter_inappwebview` instead. - @override - PlatformWebViewEnvironment createPlatformWebViewEnvironmentStatic() { - return _PlatformWebViewEnvironment.static(); - } - - /// Creates a new empty [PlatformProcessGlobalConfig] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ProcessGlobalConfig] in `flutter_inappwebview` instead. - @override - PlatformProcessGlobalConfig createPlatformProcessGlobalConfigStatic() { - return _PlatformProcessGlobalConfig.static(); - } - - /// Creates a new empty [PlatformServiceWorkerController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ServiceWorkerController] in `flutter_inappwebview` instead. - @override - PlatformServiceWorkerController - createPlatformServiceWorkerControllerStatic() { - return _PlatformServiceWorkerController.static(); - } - - /// Creates a new empty [PlatformTracingController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [TracingController] in `flutter_inappwebview` instead. - @override - PlatformTracingController createPlatformTracingControllerStatic() { - return _PlatformTracingController.static(); - } - - /// Creates a new empty [PlatformWebNotificationController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebNotificationController] in `flutter_inappwebview` instead. - @override - PlatformWebNotificationController - createPlatformWebNotificationControllerStatic() { - return _PlatformWebNotificationController.static(); - } - - /// Creates a new empty [PlatformAssetsPathHandler] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [AssetsPathHandler] in `flutter_inappwebview` instead. - @override - PlatformAssetsPathHandler createPlatformAssetsPathHandlerStatic() { - return _PlatformAssetsPathHandler.static(); - } - - /// Creates a new empty [PlatformResourcesPathHandler] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ResourcesPathHandler] in `flutter_inappwebview` instead. - @override - PlatformResourcesPathHandler createPlatformResourcesPathHandlerStatic() { - return _PlatformResourcesPathHandler.static(); - } - - /// Creates a new empty [PlatformInternalStoragePathHandler] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InternalStoragePathHandler] in `flutter_inappwebview` instead. - @override - PlatformInternalStoragePathHandler - createPlatformInternalStoragePathHandlerStatic() { - return _PlatformInternalStoragePathHandler.static(); - } - - /// Creates a new empty [PlatformCustomPathHandler] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [CustomPathHandler] in `flutter_inappwebview` instead. - @override - PlatformCustomPathHandler createPlatformCustomPathHandlerStatic() { - return _PlatformCustomPathHandler.static(); - } - - /// Creates a new [DefaultInAppLocalhostServer]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppLocalhostServer] in `flutter_inappwebview` instead. - @override - DefaultInAppLocalhostServer createPlatformInAppLocalhostServer( - PlatformInAppLocalhostServerCreationParams params, - ) { - return DefaultInAppLocalhostServer(params); - } - - /// Creates a new empty [DefaultInAppLocalhostServer] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppLocalhostServer] in `flutter_inappwebview` instead. - @override - DefaultInAppLocalhostServer createPlatformInAppLocalhostServerStatic() { - return DefaultInAppLocalhostServer.static(); - } - - /// Creates a new empty [PlatformWebViewFeature] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebViewFeature] in `flutter_inappwebview` instead - @override - PlatformWebViewFeature createPlatformWebViewFeatureStatic() { - return _PlatformWebViewFeature.static(); - } -} - -class _PlatformProcessGlobalConfig extends PlatformProcessGlobalConfig { - _PlatformProcessGlobalConfig(PlatformProcessGlobalConfigCreationParams params) - : super.implementation(params); - static final _PlatformProcessGlobalConfig _staticValue = - _PlatformProcessGlobalConfig( - const PlatformProcessGlobalConfigCreationParams(), - ); - - factory _PlatformProcessGlobalConfig.static() => _staticValue; -} - -class _PlatformServiceWorkerController extends PlatformServiceWorkerController { - _PlatformServiceWorkerController( - PlatformServiceWorkerControllerCreationParams params, - ) : super.implementation(params); - static final _PlatformServiceWorkerController _staticValue = - _PlatformServiceWorkerController( - const PlatformServiceWorkerControllerCreationParams(), - ); - - factory _PlatformServiceWorkerController.static() => _staticValue; - - @override - ServiceWorkerClient? get serviceWorkerClient => throw UnimplementedError(); -} - -class _PlatformTracingController extends PlatformTracingController { - _PlatformTracingController(PlatformTracingControllerCreationParams params) - : super.implementation(params); - static final _PlatformTracingController _staticValue = - _PlatformTracingController( - const PlatformTracingControllerCreationParams(), - ); - - factory _PlatformTracingController.static() => _staticValue; -} - -class _PlatformWebViewEnvironment extends PlatformWebViewEnvironment { - _PlatformWebViewEnvironment(PlatformWebViewEnvironmentCreationParams params) - : super.implementation(params); - static final _PlatformWebViewEnvironment _staticValue = - _PlatformWebViewEnvironment( - const PlatformWebViewEnvironmentCreationParams(), - ); - - factory _PlatformWebViewEnvironment.static() => _staticValue; -} - -class _PlatformWebNotificationController - extends PlatformWebNotificationController { - _PlatformWebNotificationController( - PlatformWebNotificationControllerCreationParams params, - ) : super.implementation(params); - - static final _PlatformWebNotificationController _staticValue = - _PlatformWebNotificationController( - PlatformWebNotificationControllerCreationParams( - id: '', - notification: WebNotification(), - ), - ); - - factory _PlatformWebNotificationController.static() => _staticValue; -} - -class _PlatformWebViewFeature extends PlatformWebViewFeature { - _PlatformWebViewFeature(PlatformWebViewFeatureCreationParams params) - : super.implementation(params); - - static final _PlatformWebViewFeature _staticValue = _PlatformWebViewFeature( - PlatformWebViewFeatureCreationParams(), - ); - factory _PlatformWebViewFeature.static() => _staticValue; -} - -class _PlatformAssetsPathHandler extends PlatformAssetsPathHandler { - _PlatformAssetsPathHandler(PlatformAssetsPathHandlerCreationParams params) - : super.implementation(params); - - static final _PlatformAssetsPathHandler _staticValue = - _PlatformAssetsPathHandler( - PlatformAssetsPathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - ), - ); - - factory _PlatformAssetsPathHandler.static() => _staticValue; - - @override - PlatformPathHandlerEvents? eventHandler; - - @override - Map toMap({EnumMethod? enumMethod}) => { - "path": path, - "type": type, - }; - - @override - Map toJson() => toMap(); -} - -class _PlatformResourcesPathHandler extends PlatformResourcesPathHandler { - _PlatformResourcesPathHandler( - PlatformResourcesPathHandlerCreationParams params, - ) : super.implementation(params); - - static final _PlatformResourcesPathHandler _staticValue = - _PlatformResourcesPathHandler( - PlatformResourcesPathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - ), - ); - - factory _PlatformResourcesPathHandler.static() => _staticValue; - - @override - PlatformPathHandlerEvents? eventHandler; - - @override - Map toMap({EnumMethod? enumMethod}) => { - "path": path, - "type": type, - }; - - @override - Map toJson() => toMap(); -} - -class _PlatformInternalStoragePathHandler - extends PlatformInternalStoragePathHandler { - _PlatformInternalStoragePathHandler( - PlatformInternalStoragePathHandlerCreationParams params, - ) : super.implementation(params); - - static final _PlatformInternalStoragePathHandler _staticValue = - _PlatformInternalStoragePathHandler( - PlatformInternalStoragePathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - directory: '', - ), - ); - - factory _PlatformInternalStoragePathHandler.static() => _staticValue; - - @override - PlatformPathHandlerEvents? eventHandler; - - @override - Map toMap({EnumMethod? enumMethod}) => { - "path": path, - "type": type, - }; - - @override - Map toJson() => toMap(); -} - -class _PlatformCustomPathHandler extends PlatformCustomPathHandler { - _PlatformCustomPathHandler(PlatformCustomPathHandlerCreationParams params) - : super.implementation(params); - - static final _PlatformCustomPathHandler _staticValue = - _PlatformCustomPathHandler( - PlatformCustomPathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - ), - ); - - factory _PlatformCustomPathHandler.static() => _staticValue; - - @override - PlatformPathHandlerEvents? eventHandler; - - @override - Map toMap({EnumMethod? enumMethod}) => { - "path": path, - "type": type, - }; - - @override - Map toJson() => toMap(); -} diff --git a/flutter_inappwebview_ios/lib/src/main.dart b/flutter_inappwebview_ios/lib/src/main.dart deleted file mode 100644 index 17f32781bf..0000000000 --- a/flutter_inappwebview_ios/lib/src/main.dart +++ /dev/null @@ -1,13 +0,0 @@ -export 'inappwebview_platform.dart'; -export 'in_app_webview/main.dart'; -export 'in_app_browser/main.dart'; -export 'chrome_safari_browser/main.dart'; -export 'web_storage/main.dart'; -export 'cookie_manager.dart' hide InternalCookieManager; -export 'http_auth_credentials_database.dart' - hide InternalHttpAuthCredentialDatabase; -export 'pull_to_refresh/main.dart'; -export 'web_message/main.dart'; -export 'print_job/main.dart'; -export 'find_interaction/main.dart'; -export 'web_authentication_session/main.dart'; diff --git a/flutter_inappwebview_ios/lib/src/platform_util.dart b/flutter_inappwebview_ios/lib/src/platform_util.dart deleted file mode 100644 index e52ccbd8cc..0000000000 --- a/flutter_inappwebview_ios/lib/src/platform_util.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'package:flutter/services.dart'; - -///Platform native utilities -class PlatformUtil { - static PlatformUtil? _instance; - static const MethodChannel _channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_platformutil', - ); - - PlatformUtil._(); - - ///Get [PlatformUtil] instance. - static PlatformUtil instance() { - return (_instance != null) ? _instance! : _init(); - } - - static PlatformUtil _init() { - _channel.setMethodCallHandler((call) async { - try { - return await _handleMethod(call); - } on Error catch (e) { - print(e); - print(e.stackTrace); - } - }); - _instance = PlatformUtil._(); - return _instance!; - } - - static Future _handleMethod(MethodCall call) async {} - - String? _cachedSystemVersion; - - ///Get current platform system version. - Future getSystemVersion() async { - if (_cachedSystemVersion != null) { - return _cachedSystemVersion!; - } - Map args = {}; - _cachedSystemVersion = await _channel.invokeMethod( - 'getSystemVersion', - args, - ); - return _cachedSystemVersion!; - } - - ///Format date. - Future formatDate({ - required DateTime date, - required String format, - String locale = "en_US", - String timezone = "UTC", - }) async { - Map args = {}; - args.putIfAbsent('date', () => date.millisecondsSinceEpoch); - args.putIfAbsent('format', () => format); - args.putIfAbsent('locale', () => locale); - args.putIfAbsent('timezone', () => timezone); - return await _channel.invokeMethod('formatDate', args); - } - - ///Get cookie expiration date used by Web platform. - Future getWebCookieExpirationDate({required DateTime date}) async { - Map args = {}; - args.putIfAbsent('date', () => date.millisecondsSinceEpoch); - return await _channel.invokeMethod('getWebCookieExpirationDate', args); - } -} diff --git a/flutter_inappwebview_ios/lib/src/print_job/main.dart b/flutter_inappwebview_ios/lib/src/print_job/main.dart deleted file mode 100644 index 4e70ad9405..0000000000 --- a/flutter_inappwebview_ios/lib/src/print_job/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'print_job_controller.dart'; diff --git a/flutter_inappwebview_ios/lib/src/print_job/print_job_controller.dart b/flutter_inappwebview_ios/lib/src/print_job/print_job_controller.dart deleted file mode 100644 index 708a7d387e..0000000000 --- a/flutter_inappwebview_ios/lib/src/print_job/print_job_controller.dart +++ /dev/null @@ -1,91 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [IOSPrintJobController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformPrintJobControllerCreationParams] for -/// more information. -@immutable -class IOSPrintJobControllerCreationParams - extends PlatformPrintJobControllerCreationParams { - /// Creates a new [IOSPrintJobControllerCreationParams] instance. - const IOSPrintJobControllerCreationParams({required super.id}); - - /// Creates a [IOSPrintJobControllerCreationParams] instance based on [PlatformPrintJobControllerCreationParams]. - factory IOSPrintJobControllerCreationParams.fromPlatformPrintJobControllerCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformPrintJobControllerCreationParams params, - ) { - return IOSPrintJobControllerCreationParams(id: params.id); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController} -class IOSPrintJobController extends PlatformPrintJobController - with ChannelController { - /// Constructs a [IOSPrintJobController]. - IOSPrintJobController(PlatformPrintJobControllerCreationParams params) - : super.implementation( - params is IOSPrintJobControllerCreationParams - ? params - : IOSPrintJobControllerCreationParams.fromPlatformPrintJobControllerCreationParams( - params, - ), - ) { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_printjobcontroller_${params.id}', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - static final IOSPrintJobController _staticValue = IOSPrintJobController( - IOSPrintJobControllerCreationParams(id: ''), - ); - - /// Provide static access. - factory IOSPrintJobController.static() { - return _staticValue; - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onComplete": - bool completed = call.arguments["completed"]; - String? error = call.arguments["error"]; - if (onComplete != null) { - onComplete!(completed, error); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - } - - @override - Future dismiss({bool animated = true}) async { - Map args = {}; - args.putIfAbsent("animated", () => animated); - await channel?.invokeMethod('dismiss', args); - } - - @override - Future getInfo() async { - Map args = {}; - Map? infoMap = (await channel?.invokeMethod( - 'getInfo', - args, - ))?.cast(); - return PrintJobInfo.fromMap(infoMap); - } - - @override - Future dispose() async { - Map args = {}; - await channel?.invokeMethod('dispose', args); - disposeChannel(); - } -} diff --git a/flutter_inappwebview_ios/lib/src/proxy_controller.dart b/flutter_inappwebview_ios/lib/src/proxy_controller.dart deleted file mode 100644 index 1e68f1f1f1..0000000000 --- a/flutter_inappwebview_ios/lib/src/proxy_controller.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [IOSProxyController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformProxyControllerCreationParams] for -/// more information. -@immutable -class IOSProxyControllerCreationParams - extends PlatformProxyControllerCreationParams { - /// Creates a new [IOSProxyControllerCreationParams] instance. - const IOSProxyControllerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformProxyControllerCreationParams params, - ) : super(); - - /// Creates a [IOSProxyControllerCreationParams] instance based on [PlatformProxyControllerCreationParams]. - factory IOSProxyControllerCreationParams.fromPlatformProxyControllerCreationParams( - PlatformProxyControllerCreationParams params, - ) { - return IOSProxyControllerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformProxyController} -class IOSProxyController extends PlatformProxyController - with ChannelController { - /// Creates a new [IOSProxyController]. - IOSProxyController(PlatformProxyControllerCreationParams params) - : super.implementation( - params is IOSProxyControllerCreationParams - ? params - : IOSProxyControllerCreationParams.fromPlatformProxyControllerCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_proxycontroller', - ); - handler = handleMethod; - initMethodCallHandler(); - } - - static IOSProxyController? _instance; - - ///Gets the [IOSProxyController] shared instance. - static IOSProxyController instance() { - return (_instance != null) ? _instance! : _init(); - } - - static IOSProxyController _init() { - _instance = IOSProxyController( - IOSProxyControllerCreationParams( - const PlatformProxyControllerCreationParams(), - ), - ); - return _instance!; - } - - static final IOSProxyController _staticValue = IOSProxyController( - IOSProxyControllerCreationParams( - const PlatformProxyControllerCreationParams(), - ), - ); - - /// Provide static access. - factory IOSProxyController.static() { - return _staticValue; - } - - Future _handleMethod(MethodCall call) async {} - - @override - Future setProxyOverride({required ProxySettings settings}) async { - Map args = {}; - args.putIfAbsent("settings", () => settings.toMap()); - await channel?.invokeMethod('setProxyOverride', args); - } - - @override - Future clearProxyOverride() async { - Map args = {}; - await channel?.invokeMethod('clearProxyOverride', args); - } - - @override - void dispose() { - // empty - } -} - -extension InternalProxyController on IOSProxyController { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_ios/lib/src/pull_to_refresh/main.dart b/flutter_inappwebview_ios/lib/src/pull_to_refresh/main.dart deleted file mode 100644 index 586af9d873..0000000000 --- a/flutter_inappwebview_ios/lib/src/pull_to_refresh/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'pull_to_refresh_controller.dart' hide InternalPullToRefreshController; diff --git a/flutter_inappwebview_ios/lib/src/pull_to_refresh/pull_to_refresh_controller.dart b/flutter_inappwebview_ios/lib/src/pull_to_refresh/pull_to_refresh_controller.dart deleted file mode 100644 index 603c635048..0000000000 --- a/flutter_inappwebview_ios/lib/src/pull_to_refresh/pull_to_refresh_controller.dart +++ /dev/null @@ -1,157 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [IOSPullToRefreshController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformPullToRefreshControllerCreationParams] for -/// more information. -class IOSPullToRefreshControllerCreationParams - extends PlatformPullToRefreshControllerCreationParams { - /// Creates a new [IOSPullToRefreshControllerCreationParams] instance. - IOSPullToRefreshControllerCreationParams({ - super.onRefresh, - super.options, - super.settings, - }); - - /// Creates a [IOSPullToRefreshControllerCreationParams] instance based on [PlatformPullToRefreshControllerCreationParams]. - factory IOSPullToRefreshControllerCreationParams.fromPlatformPullToRefreshControllerCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformPullToRefreshControllerCreationParams params, - ) { - return IOSPullToRefreshControllerCreationParams( - onRefresh: params.onRefresh, - options: params.options, - settings: params.settings, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformPullToRefreshController} -class IOSPullToRefreshController extends PlatformPullToRefreshController - with ChannelController { - /// Constructs a [IOSPullToRefreshController]. - IOSPullToRefreshController( - PlatformPullToRefreshControllerCreationParams params, - ) : super.implementation( - params is IOSPullToRefreshControllerCreationParams - ? params - : IOSPullToRefreshControllerCreationParams.fromPlatformPullToRefreshControllerCreationParams( - params, - ), - ); - - static final IOSPullToRefreshController _staticValue = - IOSPullToRefreshController(IOSPullToRefreshControllerCreationParams()); - - /// Provide static access. - factory IOSPullToRefreshController.static() { - return _staticValue; - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - debugLoggingSettings: - PlatformPullToRefreshController.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - _debugLog(call.method, call.arguments); - - switch (call.method) { - case "onRefresh": - if (params.onRefresh != null) params.onRefresh!(); - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - Future setEnabled(bool enabled) async { - Map args = {}; - args.putIfAbsent('enabled', () => enabled); - await channel?.invokeMethod('setEnabled', args); - } - - @override - Future isEnabled() async { - Map args = {}; - return await channel?.invokeMethod('isEnabled', args) ?? false; - } - - Future _setRefreshing(bool refreshing) async { - Map args = {}; - args.putIfAbsent('refreshing', () => refreshing); - await channel?.invokeMethod('setRefreshing', args); - } - - @override - Future beginRefreshing() async { - return await _setRefreshing(true); - } - - @override - Future endRefreshing() async { - await _setRefreshing(false); - } - - @override - Future isRefreshing() async { - Map args = {}; - return await channel?.invokeMethod('isRefreshing', args) ?? false; - } - - @override - Future setColor(Color color) async { - Map args = {}; - args.putIfAbsent('color', () => color.toHex()); - await channel?.invokeMethod('setColor', args); - } - - @override - Future setBackgroundColor(Color color) async { - Map args = {}; - args.putIfAbsent('color', () => color.toHex()); - await channel?.invokeMethod('setBackgroundColor', args); - } - - @Deprecated("Use setStyledTitle instead") - @override - Future setAttributedTitle(IOSNSAttributedString attributedTitle) async { - Map args = {}; - args.putIfAbsent('attributedTitle', () => attributedTitle.toMap()); - await channel?.invokeMethod('setStyledTitle', args); - } - - @override - Future setStyledTitle(AttributedString attributedTitle) async { - Map args = {}; - args.putIfAbsent('attributedTitle', () => attributedTitle.toMap()); - await channel?.invokeMethod('setStyledTitle', args); - } - - @override - void dispose({bool isKeepAlive = false}) { - disposeChannel(removeMethodCallHandler: !isKeepAlive); - } -} - -extension InternalPullToRefreshController on IOSPullToRefreshController { - void init(dynamic id) { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_$id', - ); - handler = _handleMethod; - initMethodCallHandler(); - } -} diff --git a/flutter_inappwebview_ios/lib/src/web_authentication_session/main.dart b/flutter_inappwebview_ios/lib/src/web_authentication_session/main.dart deleted file mode 100644 index 37ca0c240c..0000000000 --- a/flutter_inappwebview_ios/lib/src/web_authentication_session/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'web_authenticate_session.dart'; diff --git a/flutter_inappwebview_ios/lib/src/web_authentication_session/web_authenticate_session.dart b/flutter_inappwebview_ios/lib/src/web_authentication_session/web_authenticate_session.dart deleted file mode 100755 index 56656c97db..0000000000 --- a/flutter_inappwebview_ios/lib/src/web_authentication_session/web_authenticate_session.dart +++ /dev/null @@ -1,173 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [IOSWebAuthenticationSession]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebAuthenticationSessionCreationParams] for -/// more information. -class IOSWebAuthenticationSessionCreationParams - extends PlatformWebAuthenticationSessionCreationParams { - /// Creates a new [IOSWebAuthenticationSessionCreationParams] instance. - const IOSWebAuthenticationSessionCreationParams(); - - /// Creates a [IOSWebAuthenticationSessionCreationParams] instance based on [PlatformWebAuthenticationSessionCreationParams]. - factory IOSWebAuthenticationSessionCreationParams.fromPlatformWebAuthenticationSessionCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebAuthenticationSessionCreationParams params, - ) { - return IOSWebAuthenticationSessionCreationParams(); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession} -class IOSWebAuthenticationSession extends PlatformWebAuthenticationSession - with ChannelController { - /// Constructs a [IOSWebAuthenticationSession]. - IOSWebAuthenticationSession( - PlatformWebAuthenticationSessionCreationParams params, - ) : super.implementation( - params is IOSWebAuthenticationSessionCreationParams - ? params - : IOSWebAuthenticationSessionCreationParams.fromPlatformWebAuthenticationSessionCreationParams( - params, - ), - ); - - static final IOSWebAuthenticationSession _staticValue = - IOSWebAuthenticationSession(IOSWebAuthenticationSessionCreationParams()); - - /// Provide static access. - factory IOSWebAuthenticationSession.static() { - return _staticValue; - } - - @override - final String id = IdGenerator.generate(); - - @override - late final WebUri url; - - @override - late final String? callbackURLScheme; - - @override - late final WebAuthenticationSessionSettings? initialSettings; - - @override - late final WebAuthenticationSessionCompletionHandler onComplete; - - static const MethodChannel _staticChannel = const MethodChannel( - 'com.pichillilorenzo/flutter_webauthenticationsession', - ); - - @override - Future create({ - required WebUri url, - String? callbackURLScheme, - WebAuthenticationSessionCompletionHandler onComplete, - WebAuthenticationSessionSettings? initialSettings, - }) async { - var session = IOSWebAuthenticationSession._create( - url: url, - callbackURLScheme: callbackURLScheme, - onComplete: onComplete, - initialSettings: initialSettings, - ); - initialSettings = - session.initialSettings ?? WebAuthenticationSessionSettings(); - Map args = {}; - args.putIfAbsent("id", () => session.id); - args.putIfAbsent("url", () => session.url.toString()); - args.putIfAbsent("callbackURLScheme", () => session.callbackURLScheme); - args.putIfAbsent("initialSettings", () => initialSettings?.toMap()); - await _staticChannel.invokeMethod('create', args); - return session; - } - - IOSWebAuthenticationSession._create({ - required this.url, - this.callbackURLScheme, - this.onComplete, - WebAuthenticationSessionSettings? initialSettings, - }) : super.implementation(IOSWebAuthenticationSessionCreationParams()) { - assert(url.toString().isNotEmpty); - assert( - ['http', 'https'].contains(url.scheme), - 'The specified URL has an unsupported scheme. Only HTTP and HTTPS URLs are supported on iOS.', - ); - - this.initialSettings = - initialSettings ?? WebAuthenticationSessionSettings(); - channel = MethodChannel( - 'com.pichillilorenzo/flutter_webauthenticationsession_$id', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - debugLoggingSettings: - PlatformWebAuthenticationSession.debugLoggingSettings, - id: id, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - _debugLog(call.method, call.arguments); - - switch (call.method) { - case "onComplete": - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - var error = WebAuthenticationSessionError.fromNativeValue( - call.arguments["errorCode"], - ); - if (onComplete != null) { - onComplete!(uri, error); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - } - - @override - Future canStart() async { - Map args = {}; - return await channel?.invokeMethod('canStart', args) ?? false; - } - - @override - Future start() async { - Map args = {}; - return await channel?.invokeMethod('start', args) ?? false; - } - - @override - Future cancel() async { - Map args = {}; - await channel?.invokeMethod("cancel", args); - } - - @override - Future dispose() async { - Map args = {}; - await channel?.invokeMethod("dispose", args); - disposeChannel(); - } - - @override - Future isAvailable() async { - Map args = {}; - return await _staticChannel.invokeMethod("isAvailable", args) ?? - false; - } -} diff --git a/flutter_inappwebview_ios/lib/src/web_message/main.dart b/flutter_inappwebview_ios/lib/src/web_message/main.dart deleted file mode 100644 index d41e30c755..0000000000 --- a/flutter_inappwebview_ios/lib/src/web_message/main.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'web_message_port.dart' hide InternalWebMessagePort; -export 'web_message_channel.dart' hide InternalWebMessageChannel; -export 'web_message_listener.dart'; diff --git a/flutter_inappwebview_ios/lib/src/web_message/web_message_channel.dart b/flutter_inappwebview_ios/lib/src/web_message/web_message_channel.dart deleted file mode 100644 index 6364c68304..0000000000 --- a/flutter_inappwebview_ios/lib/src/web_message/web_message_channel.dart +++ /dev/null @@ -1,130 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import 'web_message_port.dart'; - -/// Object specifying creation parameters for creating a [IOSWebMessageChannel]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebMessageChannelCreationParams] for -/// more information. -@immutable -class IOSWebMessageChannelCreationParams - extends PlatformWebMessageChannelCreationParams { - /// Creates a new [IOSWebMessageChannelCreationParams] instance. - const IOSWebMessageChannelCreationParams({ - required super.id, - required super.port1, - required super.port2, - }); - - /// Creates a [IOSWebMessageChannelCreationParams] instance based on [PlatformWebMessageChannelCreationParams]. - factory IOSWebMessageChannelCreationParams.fromPlatformWebMessageChannelCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebMessageChannelCreationParams params, - ) { - return IOSWebMessageChannelCreationParams( - id: params.id, - port1: params.port1, - port2: params.port2, - ); - } - - @override - String toString() { - return 'IOSWebMessageChannelCreationParams{id: $id, port1: $port1, port2: $port2}'; - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel} -class IOSWebMessageChannel extends PlatformWebMessageChannel - with ChannelController { - /// Constructs a [IOSWebMessageChannel]. - IOSWebMessageChannel(PlatformWebMessageChannelCreationParams params) - : super.implementation( - params is IOSWebMessageChannelCreationParams - ? params - : IOSWebMessageChannelCreationParams.fromPlatformWebMessageChannelCreationParams( - params, - ), - ) { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_web_message_channel_${params.id}', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - static final IOSWebMessageChannel _staticValue = IOSWebMessageChannel( - IOSWebMessageChannelCreationParams( - id: '', - port1: IOSWebMessagePort(IOSWebMessagePortCreationParams(index: 0)), - port2: IOSWebMessagePort(IOSWebMessagePortCreationParams(index: 1)), - ), - ); - - /// Provide static access. - factory IOSWebMessageChannel.static() { - return _staticValue; - } - - IOSWebMessagePort get _iosPort1 => port1 as IOSWebMessagePort; - - IOSWebMessagePort get _iosPort2 => port2 as IOSWebMessagePort; - - static IOSWebMessageChannel? _fromMap(Map? map) { - if (map == null) { - return null; - } - var webMessageChannel = IOSWebMessageChannel( - IOSWebMessageChannelCreationParams( - id: map["id"], - port1: IOSWebMessagePort(IOSWebMessagePortCreationParams(index: 0)), - port2: IOSWebMessagePort(IOSWebMessagePortCreationParams(index: 1)), - ), - ); - webMessageChannel._iosPort1.webMessageChannel = webMessageChannel; - webMessageChannel._iosPort2.webMessageChannel = webMessageChannel; - return webMessageChannel; - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onMessage": - int index = call.arguments["index"]; - var port = index == 0 ? _iosPort1 : _iosPort2; - if (port.onMessage != null) { - WebMessage? message = call.arguments["message"] != null - ? WebMessage.fromMap( - call.arguments["message"].cast(), - ) - : null; - port.onMessage!(message); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - IOSWebMessageChannel? fromMap(Map? map) { - return _fromMap(map); - } - - @override - void dispose() { - disposeChannel(); - } - - @override - String toString() { - return 'IOSWebMessageChannel{id: $id, port1: $port1, port2: $port2}'; - } -} - -extension InternalWebMessageChannel on IOSWebMessageChannel { - MethodChannel? get internalChannel => channel; -} diff --git a/flutter_inappwebview_ios/lib/src/web_message/web_message_listener.dart b/flutter_inappwebview_ios/lib/src/web_message/web_message_listener.dart deleted file mode 100644 index 64a4ba54bd..0000000000 --- a/flutter_inappwebview_ios/lib/src/web_message/web_message_listener.dart +++ /dev/null @@ -1,190 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [IOSWebMessageListener]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebMessageListenerCreationParams] for -/// more information. -@immutable -class IOSWebMessageListenerCreationParams - extends PlatformWebMessageListenerCreationParams { - /// Creates a new [IOSWebMessageListenerCreationParams] instance. - const IOSWebMessageListenerCreationParams({ - required this.allowedOriginRules, - required super.jsObjectName, - super.onPostMessage, - }); - - /// Creates a [IOSWebMessageListenerCreationParams] instance based on [PlatformWebMessageListenerCreationParams]. - factory IOSWebMessageListenerCreationParams.fromPlatformWebMessageListenerCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebMessageListenerCreationParams params, - ) { - return IOSWebMessageListenerCreationParams( - allowedOriginRules: params.allowedOriginRules ?? Set.from(["*"]), - jsObjectName: params.jsObjectName, - onPostMessage: params.onPostMessage, - ); - } - - @override - final Set allowedOriginRules; - - @override - String toString() { - return 'IOSWebMessageListenerCreationParams{jsObjectName: $jsObjectName, allowedOriginRules: $allowedOriginRules, onPostMessage: $onPostMessage}'; - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener} -class IOSWebMessageListener extends PlatformWebMessageListener - with ChannelController { - /// Constructs a [IOSWebMessageListener]. - IOSWebMessageListener(PlatformWebMessageListenerCreationParams params) - : super.implementation( - params is IOSWebMessageListenerCreationParams - ? params - : IOSWebMessageListenerCreationParams.fromPlatformWebMessageListenerCreationParams( - params, - ), - ) { - assert( - !this._iosParams.allowedOriginRules.contains(""), - "allowedOriginRules cannot contain empty strings", - ); - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_web_message_listener_${_id}_${params.jsObjectName}', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - static final IOSWebMessageListener _staticValue = IOSWebMessageListener( - IOSWebMessageListenerCreationParams( - jsObjectName: '', - allowedOriginRules: Set.from(["*"]), - ), - ); - - /// Provide static access. - factory IOSWebMessageListener.static() { - return _staticValue; - } - - ///Message Listener ID used internally. - final String _id = IdGenerator.generate(); - - IOSJavaScriptReplyProxy? _replyProxy; - - IOSWebMessageListenerCreationParams get _iosParams => - params as IOSWebMessageListenerCreationParams; - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onPostMessage": - if (_replyProxy == null) { - _replyProxy = IOSJavaScriptReplyProxy( - PlatformJavaScriptReplyProxyCreationParams( - webMessageListener: this, - ), - ); - } - if (onPostMessage != null) { - WebMessage? message = call.arguments["message"] != null - ? WebMessage.fromMap( - call.arguments["message"].cast(), - ) - : null; - WebUri? sourceOrigin = call.arguments["sourceOrigin"] != null - ? WebUri(call.arguments["sourceOrigin"]) - : null; - bool isMainFrame = call.arguments["isMainFrame"]; - onPostMessage!(message, sourceOrigin, isMainFrame, _replyProxy!); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - void dispose() { - disposeChannel(); - } - - @override - Map toMap() { - return { - "id": _id, - "jsObjectName": params.jsObjectName, - "allowedOriginRules": _iosParams.allowedOriginRules.toList(), - }; - } - - @override - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return 'IOSWebMessageListener{id: ${_id}, jsObjectName: ${params.jsObjectName}, allowedOriginRules: ${params.allowedOriginRules}, replyProxy: $_replyProxy}'; - } -} - -/// Object specifying creation parameters for creating a [IOSJavaScriptReplyProxy]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformJavaScriptReplyProxyCreationParams] for -/// more information. -@immutable -class IOSJavaScriptReplyProxyCreationParams - extends PlatformJavaScriptReplyProxyCreationParams { - /// Creates a new [IOSJavaScriptReplyProxyCreationParams] instance. - const IOSJavaScriptReplyProxyCreationParams({ - required super.webMessageListener, - }); - - /// Creates a [IOSJavaScriptReplyProxyCreationParams] instance based on [PlatformJavaScriptReplyProxyCreationParams]. - factory IOSJavaScriptReplyProxyCreationParams.fromPlatformJavaScriptReplyProxyCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformJavaScriptReplyProxyCreationParams params, - ) { - return IOSJavaScriptReplyProxyCreationParams( - webMessageListener: params.webMessageListener, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.JavaScriptReplyProxy} -class IOSJavaScriptReplyProxy extends PlatformJavaScriptReplyProxy { - /// Constructs a [IOSWebMessageListener]. - IOSJavaScriptReplyProxy(PlatformJavaScriptReplyProxyCreationParams params) - : super.implementation( - params is IOSJavaScriptReplyProxyCreationParams - ? params - : IOSJavaScriptReplyProxyCreationParams.fromPlatformJavaScriptReplyProxyCreationParams( - params, - ), - ); - - IOSWebMessageListener get _iosWebMessageListener => - params.webMessageListener as IOSWebMessageListener; - - @override - Future postMessage(WebMessage message) async { - Map args = {}; - args.putIfAbsent('message', () => message.toMap()); - await _iosWebMessageListener.channel?.invokeMethod('postMessage', args); - } - - @override - String toString() { - return 'IOSJavaScriptReplyProxy{}'; - } -} diff --git a/flutter_inappwebview_ios/lib/src/web_message/web_message_port.dart b/flutter_inappwebview_ios/lib/src/web_message/web_message_port.dart deleted file mode 100644 index 6f9bc84ccc..0000000000 --- a/flutter_inappwebview_ios/lib/src/web_message/web_message_port.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import 'web_message_channel.dart'; - -/// Object specifying creation parameters for creating a [IOSWebMessagePort]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebMessagePortCreationParams] for -/// more information. -@immutable -class IOSWebMessagePortCreationParams - extends PlatformWebMessagePortCreationParams { - /// Creates a new [IOSWebMessagePortCreationParams] instance. - const IOSWebMessagePortCreationParams({required super.index}); - - /// Creates a [IOSWebMessagePortCreationParams] instance based on [PlatformWebMessagePortCreationParams]. - factory IOSWebMessagePortCreationParams.fromPlatformWebMessagePortCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebMessagePortCreationParams params, - ) { - return IOSWebMessagePortCreationParams(index: params.index); - } - - @override - String toString() { - return 'IOSWebMessagePortCreationParams{index: $index}'; - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessagePort} -class IOSWebMessagePort extends PlatformWebMessagePort { - WebMessageCallback? _onMessage; - late IOSWebMessageChannel _webMessageChannel; - - /// Constructs a [IOSWebMessagePort]. - IOSWebMessagePort(PlatformWebMessagePortCreationParams params) - : super.implementation( - params is IOSWebMessagePortCreationParams - ? params - : IOSWebMessagePortCreationParams.fromPlatformWebMessagePortCreationParams( - params, - ), - ); - - @override - Future setWebMessageCallback(WebMessageCallback? onMessage) async { - Map args = {}; - args.putIfAbsent('index', () => params.index); - await _webMessageChannel.internalChannel?.invokeMethod( - 'setWebMessageCallback', - args, - ); - this._onMessage = onMessage; - } - - @override - Future postMessage(WebMessage message) async { - Map args = {}; - args.putIfAbsent('index', () => params.index); - args.putIfAbsent('message', () => message.toMap()); - await _webMessageChannel.internalChannel?.invokeMethod('postMessage', args); - } - - @override - Future close() async { - Map args = {}; - args.putIfAbsent('index', () => params.index); - await _webMessageChannel.internalChannel?.invokeMethod('close', args); - } - - @override - Map toMap({EnumMethod? enumMethod}) { - return { - "index": params.index, - "webMessageChannelId": this._webMessageChannel.params.id, - }; - } - - @override - Map toJson() { - return toMap(); - } - - @override - String toString() { - return 'IOSWebMessagePort{index: ${params.index}}'; - } -} - -extension InternalWebMessagePort on IOSWebMessagePort { - WebMessageCallback? get onMessage => _onMessage; - void set onMessage(WebMessageCallback? value) => _onMessage = value; - - IOSWebMessageChannel get webMessageChannel => _webMessageChannel; - void set webMessageChannel(IOSWebMessageChannel value) => - _webMessageChannel = value; -} diff --git a/flutter_inappwebview_ios/lib/src/web_storage/main.dart b/flutter_inappwebview_ios/lib/src/web_storage/main.dart deleted file mode 100644 index dab327ba6d..0000000000 --- a/flutter_inappwebview_ios/lib/src/web_storage/main.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'web_storage.dart'; -export 'web_storage_manager.dart'; diff --git a/flutter_inappwebview_ios/lib/src/web_storage/web_storage.dart b/flutter_inappwebview_ios/lib/src/web_storage/web_storage.dart deleted file mode 100644 index 0b99997666..0000000000 --- a/flutter_inappwebview_ios/lib/src/web_storage/web_storage.dart +++ /dev/null @@ -1,305 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../in_app_webview/in_app_webview_controller.dart'; - -/// Object specifying creation parameters for creating a [IOSWebStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebStorageCreationParams] for -/// more information. -class IOSWebStorageCreationParams extends PlatformWebStorageCreationParams { - /// Creates a new [IOSWebStorageCreationParams] instance. - IOSWebStorageCreationParams({ - required super.localStorage, - required super.sessionStorage, - }); - - /// Creates a [IOSWebStorageCreationParams] instance based on [PlatformWebStorageCreationParams]. - factory IOSWebStorageCreationParams.fromPlatformWebStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebStorageCreationParams params, - ) { - return IOSWebStorageCreationParams( - localStorage: params.localStorage, - sessionStorage: params.sessionStorage, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage} -class IOSWebStorage extends PlatformWebStorage { - /// Constructs a [IOSWebStorage]. - IOSWebStorage(PlatformWebStorageCreationParams params) - : super.implementation( - params is IOSWebStorageCreationParams - ? params - : IOSWebStorageCreationParams.fromPlatformWebStorageCreationParams( - params, - ), - ); - - @override - PlatformLocalStorage get localStorage => params.localStorage; - - @override - PlatformSessionStorage get sessionStorage => params.sessionStorage; - - @override - void dispose() { - localStorage.dispose(); - sessionStorage.dispose(); - } -} - -/// Object specifying creation parameters for creating a [IOSStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformStorageCreationParams] for -/// more information. -class IOSStorageCreationParams extends PlatformStorageCreationParams { - /// Creates a new [IOSStorageCreationParams] instance. - IOSStorageCreationParams({ - required super.controller, - required super.webStorageType, - }); - - /// Creates a [IOSStorageCreationParams] instance based on [PlatformStorageCreationParams]. - factory IOSStorageCreationParams.fromPlatformStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformStorageCreationParams params, - ) { - return IOSStorageCreationParams( - controller: params.controller, - webStorageType: params.webStorageType, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformStorage} -abstract mixin class IOSStorage implements PlatformStorage { - @override - IOSInAppWebViewController? controller; - - @override - Future length() async { - var result = await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.length; - """, - ); - return result != null ? int.parse(json.decode(result)) : null; - } - - @override - Future setItem({required String key, required dynamic value}) async { - var encodedValue = json.encode(value); - await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.setItem("$key", ${value is String ? encodedValue : "JSON.stringify($encodedValue)"}); - """, - ); - } - - @override - Future getItem({required String key}) async { - var itemValue = await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.getItem("$key"); - """, - ); - - if (itemValue == null) { - return null; - } - - try { - return json.decode(itemValue); - } catch (e) {} - - return itemValue; - } - - @override - Future removeItem({required String key}) async { - await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.removeItem("$key"); - """, - ); - } - - @override - Future> getItems() async { - var webStorageItems = []; - - List>? items = (await controller?.evaluateJavascript( - source: - """ -(function() { - var webStorageItems = []; - for(var i = 0; i < window.$webStorageType.length; i++){ - var key = window.$webStorageType.key(i); - webStorageItems.push( - { - key: key, - value: window.$webStorageType.getItem(key) - } - ); - } - return webStorageItems; -})(); - """, - ))?.cast>(); - - if (items == null) { - return webStorageItems; - } - - for (var item in items) { - webStorageItems.add( - WebStorageItem(key: item["key"], value: item["value"]), - ); - } - - return webStorageItems; - } - - @override - Future clear() async { - await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.clear(); - """, - ); - } - - @override - Future key({required int index}) async { - var result = await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.key($index); - """, - ); - return result != null ? json.decode(result) : null; - } - - @override - void dispose() { - controller = null; - } -} - -/// Object specifying creation parameters for creating a [IOSLocalStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformLocalStorageCreationParams] for -/// more information. -class IOSLocalStorageCreationParams extends PlatformLocalStorageCreationParams { - /// Creates a new [IOSLocalStorageCreationParams] instance. - IOSLocalStorageCreationParams(super.params); - - /// Creates a [IOSLocalStorageCreationParams] instance based on [PlatformLocalStorageCreationParams]. - factory IOSLocalStorageCreationParams.fromPlatformLocalStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformLocalStorageCreationParams params, - ) { - return IOSLocalStorageCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformLocalStorage} -class IOSLocalStorage extends PlatformLocalStorage with IOSStorage { - /// Constructs a [IOSLocalStorage]. - IOSLocalStorage(PlatformLocalStorageCreationParams params) - : super.implementation( - params is IOSLocalStorageCreationParams - ? params - : IOSLocalStorageCreationParams.fromPlatformLocalStorageCreationParams( - params, - ), - ); - - /// Default storage - factory IOSLocalStorage.defaultStorage({ - required PlatformInAppWebViewController? controller, - }) { - return IOSLocalStorage( - IOSLocalStorageCreationParams( - PlatformLocalStorageCreationParams( - PlatformStorageCreationParams( - controller: controller, - webStorageType: WebStorageType.LOCAL_STORAGE, - ), - ), - ), - ); - } - - @override - IOSInAppWebViewController? get controller => - params.controller as IOSInAppWebViewController?; -} - -/// Object specifying creation parameters for creating a [IOSSessionStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformSessionStorageCreationParams] for -/// more information. -class IOSSessionStorageCreationParams - extends PlatformSessionStorageCreationParams { - /// Creates a new [IOSSessionStorageCreationParams] instance. - IOSSessionStorageCreationParams(super.params); - - /// Creates a [IOSSessionStorageCreationParams] instance based on [PlatformSessionStorageCreationParams]. - factory IOSSessionStorageCreationParams.fromPlatformSessionStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformSessionStorageCreationParams params, - ) { - return IOSSessionStorageCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformSessionStorage} -class IOSSessionStorage extends PlatformSessionStorage with IOSStorage { - /// Constructs a [IOSSessionStorage]. - IOSSessionStorage(PlatformSessionStorageCreationParams params) - : super.implementation( - params is IOSSessionStorageCreationParams - ? params - : IOSSessionStorageCreationParams.fromPlatformSessionStorageCreationParams( - params, - ), - ); - - /// Default storage - factory IOSSessionStorage.defaultStorage({ - required PlatformInAppWebViewController? controller, - }) { - return IOSSessionStorage( - IOSSessionStorageCreationParams( - PlatformSessionStorageCreationParams( - PlatformStorageCreationParams( - controller: controller, - webStorageType: WebStorageType.SESSION_STORAGE, - ), - ), - ), - ); - } - - @override - IOSInAppWebViewController? get controller => - params.controller as IOSInAppWebViewController?; -} diff --git a/flutter_inappwebview_ios/lib/src/web_storage/web_storage_manager.dart b/flutter_inappwebview_ios/lib/src/web_storage/web_storage_manager.dart deleted file mode 100755 index 4bff887edc..0000000000 --- a/flutter_inappwebview_ios/lib/src/web_storage/web_storage_manager.dart +++ /dev/null @@ -1,164 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [IOSWebStorageManager]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebStorageManagerCreationParams] for -/// more information. -@immutable -class IOSWebStorageManagerCreationParams - extends PlatformWebStorageManagerCreationParams { - /// Creates a new [IOSWebStorageManagerCreationParams] instance. - const IOSWebStorageManagerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformWebStorageManagerCreationParams params, - ) : super(); - - /// Creates a [IOSWebStorageManagerCreationParams] instance based on [PlatformWebStorageManagerCreationParams]. - factory IOSWebStorageManagerCreationParams.fromPlatformWebStorageManagerCreationParams( - PlatformWebStorageManagerCreationParams params, - ) { - return IOSWebStorageManagerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager} -class IOSWebStorageManager extends PlatformWebStorageManager - with ChannelController { - /// Creates a new [IOSWebStorageManager]. - IOSWebStorageManager(PlatformWebStorageManagerCreationParams params) - : super.implementation( - params is IOSWebStorageManagerCreationParams - ? params - : IOSWebStorageManagerCreationParams.fromPlatformWebStorageManagerCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_webstoragemanager', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - static IOSWebStorageManager? _instance; - - ///Gets the WebStorage manager shared instance. - static IOSWebStorageManager instance() { - return (_instance != null) ? _instance! : _init(); - } - - static IOSWebStorageManager _init() { - _instance = IOSWebStorageManager( - IOSWebStorageManagerCreationParams( - const PlatformWebStorageManagerCreationParams(), - ), - ); - return _instance!; - } - - static IOSWebStorageManager? _static; - - /// Provide static access. - factory IOSWebStorageManager.static() { - _static ??= IOSWebStorageManager( - IOSWebStorageManagerCreationParams( - const PlatformWebStorageManagerCreationParams(), - ), - ); - return _static!; - } - - Future _handleMethod(MethodCall call) async {} - - @override - Future> fetchDataRecords({ - required Set dataTypes, - }) async { - List recordList = []; - List dataTypesList = []; - for (var dataType in dataTypes) { - if (dataType.isSupported()) { - dataTypesList.add(dataType.toNativeValue()!); - } - } - Map args = {}; - args.putIfAbsent("dataTypes", () => dataTypesList); - List> records = - (await channel?.invokeMethod( - 'fetchDataRecords', - args, - ))?.cast>() ?? - []; - for (var record in records) { - List dataTypesString = record["dataTypes"].cast(); - Set dataTypes = Set(); - for (var dataTypeValue in dataTypesString) { - var dataType = WebsiteDataType.fromNativeValue(dataTypeValue); - if (dataType != null) { - dataTypes.add(dataType); - } - } - recordList.add( - WebsiteDataRecord( - displayName: record["displayName"], - dataTypes: dataTypes, - ), - ); - } - return recordList; - } - - @override - Future removeDataFor({ - required Set dataTypes, - required List dataRecords, - }) async { - List dataTypesList = []; - for (var dataType in dataTypes) { - if (dataType.isSupported()) { - dataTypesList.add(dataType.toNativeValue()!); - } - } - - List> recordList = []; - for (var record in dataRecords) { - recordList.add(record.toMap()); - } - - Map args = {}; - args.putIfAbsent("dataTypes", () => dataTypesList); - args.putIfAbsent("recordList", () => recordList); - await channel?.invokeMethod('removeDataFor', args); - } - - @override - Future removeDataModifiedSince({ - required Set dataTypes, - required DateTime date, - }) async { - List dataTypesList = []; - for (var dataType in dataTypes) { - if (dataType.isSupported()) { - dataTypesList.add(dataType.toNativeValue()!); - } - } - - var timestamp = date.millisecondsSinceEpoch; - - Map args = {}; - args.putIfAbsent("dataTypes", () => dataTypesList); - args.putIfAbsent("timestamp", () => timestamp); - await channel?.invokeMethod('removeDataModifiedSince', args); - } - - @override - void dispose() { - // empty - } -} diff --git a/flutter_inappwebview_ios/pubspec.yaml b/flutter_inappwebview_ios/pubspec.yaml deleted file mode 100644 index 186b85bcdd..0000000000 --- a/flutter_inappwebview_ios/pubspec.yaml +++ /dev/null @@ -1,83 +0,0 @@ -name: flutter_inappwebview_ios -description: iOS implementation of the flutter_inappwebview plugin. -version: 1.2.0-beta.3 -homepage: https://inappwebview.dev/ -repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_ios -issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues -funding: - - https://inappwebview.dev/donate/ -topics: - - html - - webview - - webview-flutter - - inappwebview - - browser - -environment: - sdk: ^3.8.0 - flutter: ">=3.32.0" - -dependencies: - flutter: - sdk: flutter - flutter_inappwebview_platform_interface: ^1.4.0-beta.3 - # path: ../flutter_inappwebview_platform_interface - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^6.0.0 - plugin_platform_interface: ^2.1.8 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - # This section identifies this Flutter project as a plugin project. - # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) - # which should be registered in the plugin registry. This is required for - # using method channels. - # The Android 'package' specifies package in which the registered class is. - # This is required for using method channels on Android. - # The 'ffiPlugin' specifies that native code should be built and bundled. - # This is required for using `dart:ffi`. - # All these are used by the tooling to maintain consistency when - # adding or updating assets for this project. - plugin: - implements: flutter_inappwebview - platforms: - ios: - pluginClass: InAppWebViewFlutterPlugin - dartPluginClass: IOSInAppWebViewPlatform - - # To add assets to your plugin package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # To add custom fonts to your plugin package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages diff --git a/flutter_inappwebview_ios/test/flutter_inappwebview_ios_test.dart b/flutter_inappwebview_ios/test/flutter_inappwebview_ios_test.dart deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/flutter_inappwebview_linux/.gitignore b/flutter_inappwebview_linux/.gitignore deleted file mode 100644 index b9d7f25b91..0000000000 --- a/flutter_inappwebview_linux/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.build/ -.buildlog/ -.history -.svn/ -.swiftpm/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock -**/doc/api/ -.dart_tool/ -.flutter-plugins-dependencies -/build/ -/coverage/ diff --git a/flutter_inappwebview_linux/.metadata b/flutter_inappwebview_linux/.metadata deleted file mode 100644 index c1dd3d0884..0000000000 --- a/flutter_inappwebview_linux/.metadata +++ /dev/null @@ -1,30 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "f6ff1529fd6d8af5f706051d9251ac9231c83407" - channel: "stable" - -project_type: plugin - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: f6ff1529fd6d8af5f706051d9251ac9231c83407 - base_revision: f6ff1529fd6d8af5f706051d9251ac9231c83407 - - platform: linux - create_revision: f6ff1529fd6d8af5f706051d9251ac9231c83407 - base_revision: f6ff1529fd6d8af5f706051d9251ac9231c83407 - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/flutter_inappwebview_linux/CHANGELOG.md b/flutter_inappwebview_linux/CHANGELOG.md deleted file mode 100644 index e57de0b6f8..0000000000 --- a/flutter_inappwebview_linux/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## 0.1.0-beta.1 - -- Initial release. diff --git a/flutter_inappwebview_linux/LICENSE b/flutter_inappwebview_linux/LICENSE deleted file mode 100644 index 6ccd8da42c..0000000000 --- a/flutter_inappwebview_linux/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2023 Lorenzo Pichilli - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/flutter_inappwebview_linux/README.md b/flutter_inappwebview_linux/README.md deleted file mode 100644 index be3c486dcc..0000000000 --- a/flutter_inappwebview_linux/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# flutter\_inappwebview\_linux - -The Linux WPE WebKit implementation of [`flutter_inappwebview`](https://pub.dev/packages/flutter_inappwebview). - -## Usage - -This package is [endorsed](https://flutter.dev/docs/development/packages-and-plugins/developing-packages#endorsed-federated-plugin), -which means you can simply use `flutter_inappwebview` -normally. This package will be automatically included in your app when you do, -so you do not need to add it to your `pubspec.yaml`. - -However, if you `import` this package to use any of its APIs directly, you -should add it to your `pubspec.yaml` as usual. \ No newline at end of file diff --git a/flutter_inappwebview_linux/WPE_BACKEND.md b/flutter_inappwebview_linux/WPE_BACKEND.md deleted file mode 100644 index 1c0b07bd8f..0000000000 --- a/flutter_inappwebview_linux/WPE_BACKEND.md +++ /dev/null @@ -1,594 +0,0 @@ -# WPE WebKit Backend for flutter_inappwebview_linux - -This document describes how to install and configure WPE WebKit for the flutter_inappwebview Linux plugin. - -## Overview - -This plugin uses WPE WebKit for offscreen web rendering. WPE WebKit is the official WebKit port for embedded systems: - -1. **Designed for headless/offscreen rendering** - No GTK widget hierarchy required -2. **Excellent GPU integration** - Uses DMA-BUF for zero-copy texture sharing with Flutter -3. **Lower memory footprint** - No widget hierarchy overhead -4. **Perfect for embedded systems** - Raspberry Pi, set-top boxes, kiosks, etc. - -The WPE backend exports frames directly as GPU textures via DMA-BUF or SHM buffers. - -## Backend Selection - -The plugin supports two backend APIs, with automatic selection at compile time: - -| Backend | Package | Status | Description | -|---------|---------|--------|-------------| -| **WPEPlatform** | `wpe-platform-2.0` + `wpe-platform-headless-2.0` | **DEFAULT** | Modern API for WPE WebKit 2.40+. Recommended for new installations. | -| **WPEBackend-FDO** | `wpebackend-fdo-1.0` | Legacy Fallback | Used only when WPEPlatform is not available. For older systems. | - -### Backend Detection Logic - -The build system automatically selects the backend: - -1. **If WPEPlatform is found** (`wpe-platform-2.0` and `wpe-platform-headless-2.0`): - - WPEPlatform is used as the default backend - - `HAVE_WPE_PLATFORM=1` is defined - - WPEBackend-FDO is ignored even if available - -2. **If WPEPlatform is NOT found** but WPEBackend-FDO is available: - - WPEBackend-FDO is used as legacy fallback - - `HAVE_WPE_BACKEND_LEGACY=1` is defined - -3. **If neither is found**: Build fails with an error message. - -> **Note:** WPEPlatform and WPEBackend-FDO are **mutually exclusive** at compile time. You cannot use both simultaneously. - -## Installation Options - -You can either: -1. **Use pre-built packages** from your distribution (if available): https://wpewebkit.org/about/get-wpe.html -2. **Build from source** using official tarball releases (recommended for latest features): https://wpewebkit.org/release/ - -### Option 2: Build from Source - -#### Prerequisites - -Install the **required** build dependencies (optional features are listed separately below): - -```bash -# Core build tools -sudo apt-get install -y \ - build-essential cmake ninja-build meson pkg-config \ - ruby ruby-dev python3 python3-pip \ - gperf unifdef - -# GLib (required) -sudo apt-get install -y libglib2.0-dev - -# Networking and security (required) -sudo apt-get install -y \ - libsoup-3.0-dev \ - libssl-dev libgnutls28-dev \ - libsecret-1-dev \ - libgcrypt20-dev libtasn1-dev - -# Graphics and rendering (required) -sudo apt-get install -y \ - libepoxy-dev \ - libegl1-mesa-dev libgles2-mesa-dev \ - libxkbcommon-dev - -# Image and font processing (required) -sudo apt-get install -y \ - libjpeg-dev libpng-dev libwebp-dev \ - libharfbuzz-dev libharfbuzz-icu0 libfreetype6-dev libfontconfig1-dev - -# Text and internationalization (required) -sudo apt-get install -y \ - libicu-dev libxml2-dev \ - libhyphen-dev libenchant-2-dev - -# Media and audio (required for ENABLE_VIDEO and ENABLE_WEB_AUDIO) -sudo apt-get install -y \ - libgstreamer1.0-dev \ - libgstreamer-plugins-base1.0-dev \ - libgstreamer-plugins-bad1.0-dev \ - gstreamer1.0-plugins-base gstreamer1.0-plugins-good - -# Database and storage (required) -sudo apt-get install -y libsqlite3-dev - -# WPE libraries (required) -sudo apt-get install -y libwpe-1.0-dev -``` - -> **Note:** Optional dependencies (libjxl, libavif, flite, libdrm, etc.) are listed in the "Installing All Optional Dependencies" section below. Install them for full feature support, or disable the corresponding CMake flags. - -#### Optional Features and Dependencies - -WPE WebKit has many optional features that are **enabled by default**. If you don't have the required dependencies installed, you must either install them or disable the feature via CMake flags. - -##### Features Enabled by Default - -| CMake Flag | Default | Min Version | Dependencies (Debian/Ubuntu) | Description | -|------------|---------|-------------|------------------------------|-------------| -| `USE_JPEGXL` | ON | 0.7.0 | `libjxl-dev` | JPEG XL image format support | -| `USE_AVIF` | ON | 0.9.0 | `libavif-dev` | AVIF image format support | -| `USE_WOFF2` | ON | 1.0.2 | `libwoff-dev` | WOFF2 web font support | -| `USE_LCMS` | ON | — | `liblcms2-dev` | Color management (Little CMS) | -| `USE_ATK` | ON | 2.16.0 | `libatk1.0-dev libatk-bridge2.0-dev` | Accessibility toolkit | -| `USE_GBM` | ON | — | `libgbm-dev` | Generic Buffer Management (GPU) | -| `USE_LIBDRM` | ON | — | `libdrm-dev` | Direct Rendering Manager | -| `USE_LIBBACKTRACE` | ON | — | `libbacktrace-dev` | Stack trace support | -| `USE_SKIA_OPENTYPE_SVG` | ON | — | — | Skia OpenType SVG font support | -| `ENABLE_SPEECH_SYNTHESIS` | ON | — | See speech options below | Text-to-speech support | -| `USE_FLITE` | ON | 2.2 | `flite1-dev` | Flite speech engine (used when speech enabled) | -| `USE_SPIEL` | OFF | — | `libspiel-dev` | Alternative speech engine (LibSpiel) | -| `ENABLE_XSLT` | ON | 1.1.13 | `libxslt1-dev` | XSLT transformation support | -| `ENABLE_INTROSPECTION` | ON | — | `gobject-introspection libgirepository1.0-dev` | GObject introspection | -| `ENABLE_DOCUMENTATION` | ON | — | `pip3 install gi-docgen` | API documentation generation | -| `ENABLE_JOURNALD_LOG` | ON | — | `libsystemd-dev` or `libelogind-dev` | Systemd journal logging | -| `ENABLE_BUBBLEWRAP_SANDBOX` | ON | — | `bubblewrap xdg-dbus-proxy libseccomp-dev` | Process sandboxing (Linux only) | -| `ENABLE_WEBDRIVER` | ON | — | — | WebDriver automation support | -| `ENABLE_PDFJS` | ON | — | — | PDF.js viewer | -| `ENABLE_VIDEO` | ON | — | GStreamer (see prerequisites) | HTML5 video support | -| `ENABLE_WEB_AUDIO` | ON | — | GStreamer (see prerequisites) | Web Audio API support | -| `ENABLE_GAMEPAD` | ON | 0.2.4 | `libmanette-0.2-dev` | Gamepad/controller support | -| `ENABLE_MEDIA_STREAM` | ON | — | GStreamer plugins | Camera/microphone access | -| `USE_GSTREAMER_WEBRTC` | OFF | — | `gstreamer1.0-plugins-bad` | GStreamer-based WebRTC | - -##### Features Disabled by Default (Experimental/Advanced) - -| CMake Flag | Default | Dependencies (Debian/Ubuntu) | Description | -|------------|---------|------------------------------|-------------| -| `ENABLE_WPE_PLATFORM` | OFF | See platform flags below | WPE 2.0 platform abstraction (**required for this plugin**, ⚠️ see note) | -| `ENABLE_WPE_PLATFORM_HEADLESS` | OFF | See platform flags below | Headless platform (**required for this plugin**, ⚠️ see note) | -| `ENABLE_ENCRYPTED_MEDIA` | OFF | Thunder/OCDM | Encrypted Media Extensions (EME/DRM) | -| `ENABLE_WPE_PLATFORM_DRM` | OFF | `libinput-dev libudev-dev libdrm-dev libgbm-dev` | DRM/KMS platform (requires `USE_GBM`) | -| `ENABLE_WPE_PLATFORM_WAYLAND` | OFF | `libwayland-dev wayland-protocols` | Wayland platform | -| `ENABLE_WPE_QT_API` | OFF | Qt5/Qt6 development packages | Qt/QML API bindings | -| `USE_QT6` | OFF | `qt6-base-dev qt6-declarative-dev` | Use Qt6 instead of Qt5 (requires `ENABLE_WPE_PLATFORM`) | -| `ENABLE_WPE_1_1_API` | OFF | — | Build WPE 1.1 API instead of 2.0 | - -> **⚠️ WPEPlatform for this Plugin:** The `ENABLE_WPE_PLATFORM` flags above are for **building WPE WebKit from source**. To use the modern WPEPlatform backend with this Flutter plugin (the default), you must enable `ENABLE_WPE_PLATFORM=ON` and `ENABLE_WPE_PLATFORM_HEADLESS=ON` when building WPE WebKit. If these are disabled, the plugin will fall back to WPEBackend-FDO. - -##### Disabling Optional Features - -To disable a feature, pass `-D=OFF` to cmake. Example: - -```bash -cmake -B build -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=$WPE_PREFIX \ - -DPORT=WPE \ - -DUSE_JPEGXL=OFF \ - -DUSE_AVIF=OFF \ - -DENABLE_SPEECH_SYNTHESIS=OFF \ - -DENABLE_DOCUMENTATION=OFF \ - -DENABLE_INTROSPECTION=OFF \ - -DENABLE_WPE_PLATFORM=ON \ - -DENABLE_WPE_PLATFORM_HEADLESS=ON \ - # ... other options -``` - -##### Minimal Build (Disable Most Optional Features) - -For a minimal build without optional dependencies: - -```bash -cmake -B build -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=$WPE_PREFIX \ - -DPORT=WPE \ - -DUSE_JPEGXL=OFF \ - -DUSE_AVIF=OFF \ - -DUSE_WOFF2=OFF \ - -DUSE_LCMS=OFF \ - -DUSE_ATK=OFF \ - -DUSE_LIBBACKTRACE=OFF \ - -DENABLE_SPEECH_SYNTHESIS=OFF \ - -DENABLE_DOCUMENTATION=OFF \ - -DENABLE_INTROSPECTION=OFF \ - -DENABLE_JOURNALD_LOG=OFF \ - -DENABLE_BUBBLEWRAP_SANDBOX=OFF \ - -DENABLE_WEBDRIVER=OFF \ - -DENABLE_GAMEPAD=OFF \ - -DUSE_GSTREAMER_WEBRTC=OFF \ - -DENABLE_MINIBROWSER=OFF \ - -DENABLE_WPE_PLATFORM=ON \ - -DENABLE_WPE_PLATFORM_HEADLESS=ON -``` - -##### Feature-Complete Build (WPE 2.0 with All Features) - -For a full-featured WPE 2.0 build with all optional features enabled: - -```bash -cmake -B build -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=$WPE_PREFIX \ - -DPORT=WPE \ - -DENABLE_DOCUMENTATION=OFF \ - -DENABLE_INTROSPECTION=ON \ - -DENABLE_BUBBLEWRAP_SANDBOX=ON \ - -DENABLE_WEBDRIVER=ON \ - -DENABLE_MINIBROWSER=OFF \ - -DENABLE_PDFJS=ON \ - -DENABLE_VIDEO=ON \ - -DENABLE_WEB_AUDIO=ON \ - -DENABLE_SPEECH_SYNTHESIS=ON \ - -DENABLE_XSLT=ON \ - -DENABLE_GAMEPAD=ON \ - -DENABLE_JOURNALD_LOG=ON \ - -DUSE_AVIF=ON \ - -DUSE_WOFF2=ON \ - -DUSE_JPEGXL=ON \ - -DUSE_LCMS=ON \ - -DUSE_ATK=ON \ - -DUSE_GBM=ON \ - -DUSE_LIBDRM=ON \ - -DUSE_LIBBACKTRACE=ON \ - -DUSE_FLITE=ON \ - -DUSE_GSTREAMER_WEBRTC=ON \ - -DENABLE_WPE_PLATFORM=ON \ - -DENABLE_WPE_PLATFORM_HEADLESS=ON -``` - -> **Note:** This requires all optional dependencies to be installed (see "Installing All Optional Dependencies" above). - -##### Installing All Optional Dependencies - -To install **all** optional dependencies for a full-featured build: - -```bash -# Image format support -sudo apt-get install -y \ - libjxl-dev \ - libavif-dev \ - libwoff-dev \ - libopenjp2-7-dev - -# Color management -sudo apt-get install -y liblcms2-dev - -# Accessibility -sudo apt-get install -y libatk1.0-dev libatk-bridge2.0-dev - -# Graphics/GPU (required for USE_GBM and USE_LIBDRM) -sudo apt-get install -y libdrm-dev libgbm-dev - -# Debugging -sudo apt-get install -y libbacktrace-dev - -# Speech synthesis (choose one) -sudo apt-get install -y flite1-dev # Flite (default) -# OR: sudo apt-get install -y libspiel-dev # LibSpiel (alternative) - -# XSLT -sudo apt-get install -y libxslt1-dev - -# GObject introspection & documentation -sudo apt-get install -y gobject-introspection libgirepository1.0-dev -pip3 install gi-docgen - -# Systemd logging -sudo apt-get install -y libsystemd-dev - -# Sandboxing -sudo apt-get install -y bubblewrap xdg-dbus-proxy libseccomp-dev - -# Gamepad support -sudo apt-get install -y libmanette-0.2-dev libevdev-dev - -# WebRTC with GStreamer -sudo apt-get install -y gstreamer1.0-plugins-bad - -# WPE Platform DRM (for ENABLE_WPE_PLATFORM_DRM) -sudo apt-get install -y libinput-dev libudev-dev - -# WPE Platform Wayland (for ENABLE_WPE_PLATFORM_WAYLAND) -sudo apt-get install -y libwayland-dev wayland-protocols - -# Qt6 support (for ENABLE_WPE_QT_API with USE_QT6) -# sudo apt-get install -y qt6-base-dev qt6-declarative-dev -``` - -##### Common Build Errors and Fixes - -| Error Message | Solution | -|---------------|----------| -| `libjxl is required for USE_JPEGXL` | Install `libjxl-dev` OR add `-DUSE_JPEGXL=OFF` | -| `libavif 0.9.0 is required for USE_AVIF` | Install `libavif-dev` OR add `-DUSE_AVIF=OFF` | -| `libwoff2dec is required for USE_WOFF2` | Install `libwoff-dev` OR add `-DUSE_WOFF2=OFF` | -| `libcms2 is required for USE_LCMS` | Install `liblcms2-dev` OR add `-DUSE_LCMS=OFF` | -| `atk is required for USE_ATK` | Install `libatk1.0-dev libatk-bridge2.0-dev` OR add `-DUSE_ATK=OFF` | -| `libbacktrace is required for USE_LIBBACKTRACE` | Install `libbacktrace-dev` OR add `-DUSE_LIBBACKTRACE=OFF` | -| `Flite is needed for ENABLE_SPEECH_SYNTHESIS` | Install `flite1-dev` OR add `-DENABLE_SPEECH_SYNTHESIS=OFF` | -| `LibSpiel is needed for ENABLE_SPEECH_SYNTHESIS` | Install `libspiel-dev` OR use Flite instead | -| `libxslt is required for ENABLE_XSLT` | Install `libxslt1-dev` OR add `-DENABLE_XSLT=OFF` | -| `GObjectIntrospection is needed for ENABLE_INTROSPECTION` | Install `gobject-introspection libgirepository1.0-dev` OR add `-DENABLE_INTROSPECTION=OFF` | -| `gi-docgen is needed for ENABLE_DOCUMENTATION` | Run `pip3 install gi-docgen` OR add `-DENABLE_DOCUMENTATION=OFF` | -| `libsystemd or libelogind are needed for ENABLE_JOURNALD_LOG` | Install `libsystemd-dev` OR add `-DENABLE_JOURNALD_LOG=OFF` | -| `GBM is required for USE_GBM` | Install `libgbm-dev` OR add `-DUSE_GBM=OFF` (disables GPU process) | -| `libdrm is required for USE_LIBDRM` | Install `libdrm-dev` OR add `-DUSE_LIBDRM=OFF` | - -#### Build Instructions - -```bash -# Create a working directory -mkdir -p ~/wpe-build && cd ~/wpe-build - -# Set installation prefix (use /usr/local or a custom path) -export WPE_PREFIX=/usr/local - -# === 1. Build libwpe === -wget https://wpewebkit.org/releases/libwpe-1.16.3.tar.xz -tar xf libwpe-1.16.3.tar.xz -cd libwpe-1.16.3 -cmake -B build -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=$WPE_PREFIX -ninja -C build -sudo ninja -C build install -cd .. - -# === 2. Build WPEBackend-fdo (OPTIONAL - only for legacy fallback) === -# Skip this step if you enable ENABLE_WPE_PLATFORM in step 3. -# Only needed for older WPE WebKit builds or as a fallback. -wget https://wpewebkit.org/releases/wpebackend-fdo-1.16.1.tar.xz -tar xf wpebackend-fdo-1.16.1.tar.xz -cd wpebackend-fdo-1.16.1 -meson setup build \ - --prefix=$WPE_PREFIX \ - --buildtype=release -ninja -C build -sudo ninja -C build install -cd .. - -# === 3. Build WPE WebKit === -# This is the largest component and takes significant time/resources -wget https://wpewebkit.org/releases/wpewebkit-2.50.4.tar.xz -tar xf wpewebkit-2.50.4.tar.xz -cd wpewebkit-2.50.4 - -# Configure with recommended options for flutter_inappwebview -# See "Optional Features and Dependencies" section above for all flags -cmake -B build -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=$WPE_PREFIX \ - -DPORT=WPE \ - -DENABLE_DOCUMENTATION=OFF \ - -DENABLE_INTROSPECTION=OFF \ - -DENABLE_BUBBLEWRAP_SANDBOX=ON \ - -DENABLE_WEBDRIVER=OFF \ - -DENABLE_MINIBROWSER=OFF \ - -DUSE_AVIF=ON \ - -DUSE_WOFF2=ON \ - -DUSE_JPEGXL=ON \ - -DENABLE_WPE_PLATFORM=ON \ - -DENABLE_WPE_PLATFORM_HEADLESS=ON - -# The last two flags enable the modern WPEPlatform backend (recommended). -# If omitted, the plugin will fall back to legacy WPEBackend-FDO. - -# If you're missing optional dependencies, disable them: -# -DUSE_JPEGXL=OFF # if libjxl-dev not installed -# -DUSE_AVIF=OFF # if libavif-dev not installed -# -DUSE_WOFF2=OFF # if libwoff-dev not installed -# -DUSE_LCMS=OFF # if liblcms2-dev not installed -# -DENABLE_SPEECH_SYNTHESIS=OFF # if flite1-dev not installed -# -DUSE_ATK=OFF # if libatk1.0-dev not installed -# -DUSE_LIBBACKTRACE=OFF # if libbacktrace-dev not installed -# -DENABLE_JOURNALD_LOG=OFF # if libsystemd-dev not installed - -# Build (use -j to limit parallelism if you have limited RAM) -# Each WebKit build process uses ~1.5GB RAM -ninja -C build -j$(nproc) - -# Install -sudo ninja -C build install -cd .. - -# === 4. Update library cache === -sudo ldconfig - -# === 5. Create the default backend symlink (OPTIONAL - only for legacy fallback) === -# WPE looks for libWPEBackend-default.so -ARCH=$(uname -m) -if [ -f "$WPE_PREFIX/lib/${ARCH}-linux-gnu/libWPEBackend-fdo-1.0.so.1" ]; then - sudo ln -sf "$WPE_PREFIX/lib/${ARCH}-linux-gnu/libWPEBackend-fdo-1.0.so.1" \ - "$WPE_PREFIX/lib/libWPEBackend-default.so" -elif [ -f "$WPE_PREFIX/lib/aarch64-linux-gnu/libWPEBackend-fdo-1.0.so.1" ]; then - sudo ln -sf "$WPE_PREFIX/lib/aarch64-linux-gnu/libWPEBackend-fdo-1.0.so.1" \ - "$WPE_PREFIX/lib/libWPEBackend-default.so" -elif [ -f "$WPE_PREFIX/lib/x86_64-linux-gnu/libWPEBackend-fdo-1.0.so.1" ]; then - sudo ln -sf "$WPE_PREFIX/lib/x86_64-linux-gnu/libWPEBackend-fdo-1.0.so.1" \ - "$WPE_PREFIX/lib/libWPEBackend-default.so" -elif [ -f "$WPE_PREFIX/lib/libWPEBackend-fdo-1.0.so.1" ]; then - sudo ln -sf "$WPE_PREFIX/lib/libWPEBackend-fdo-1.0.so.1" \ - "$WPE_PREFIX/lib/libWPEBackend-default.so" -fi -``` - -#### Verify Installation - -```bash -# Check pkg-config can find the libraries -pkg-config --modversion wpe-webkit-2.0 -# (OPTIONAL - only for legacy fallback) -pkg-config --modversion wpebackend-fdo-1.0 -pkg-config --modversion wpe-1.0 -``` - -If pkg-config doesn't find the libraries, add the installation path: - -```bash -export PKG_CONFIG_PATH=$WPE_PREFIX/lib/pkgconfig:$WPE_PREFIX/lib/$(uname -m)-linux-gnu/pkgconfig:$PKG_CONFIG_PATH -``` - -## Building the Flutter Plugin - -The plugin automatically detects WPE libraries via pkg-config. When WPE is found, it: - -1. **Compiles with the WPE backend** -2. **Bundles WPE libraries** into the Flutter app's `lib/` directory -3. **Creates necessary symlinks** so the app runs without `LD_LIBRARY_PATH` - -### Build Your App - -```bash -cd your_flutter_app -flutter build linux --release -``` - -During build, you should see messages indicating which backend is being used: - -**With WPEPlatform (default):** -``` --- flutter_inappwebview_linux: Using WPE WebKit backend --- flutter_inappwebview_linux: Found wpe-webkit-2.0 (2.50.4) --- flutter_inappwebview_linux: Found wpe-platform-2.0 (WPEPlatform API - DEFAULT) --- flutter_inappwebview_linux: Found wpe-platform-headless-2.0 --- flutter_inappwebview_linux: Will bundle /usr/local/lib/libWPEWebKit-2.0.so.1.6.9 --- flutter_inappwebview_linux: Will bundle /usr/local/lib/libwpe-1.0.so.1.10.0 -``` - -**With WPEBackend-FDO (legacy fallback):** -``` --- flutter_inappwebview_linux: Using WPE WebKit backend --- flutter_inappwebview_linux: Found wpe-webkit-2.0 (2.50.4) --- flutter_inappwebview_linux: Found wpebackend-fdo-1.0 (Legacy FDO API) --- flutter_inappwebview_linux: Will bundle /usr/local/lib/libWPEWebKit-2.0.so.1.6.9 --- flutter_inappwebview_linux: Will bundle /usr/local/lib/libwpe-1.0.so.1.10.0 --- flutter_inappwebview_linux: Will bundle /usr/local/lib/.../libWPEBackend-fdo-1.0.so.1.11.0 -``` - -### Run Your App - -The built app includes all WPE libraries bundled in the `lib/` directory and can be run directly: - -```bash -# x64 architecture -./build/linux/x64/release/bundle/your_app - -# ARM64 architecture -./build/linux/arm64/release/bundle/your_app -``` - -### What Gets Bundled - -The following files are automatically copied to your app's `lib/` directory: - -**Always bundled:** -- `libWPEWebKit-2.0.so.*` - WPE WebKit library (~160MB) -- `libwpe-1.0.so.*` - libwpe library - -**With WPEPlatform (default):** -- WPEPlatform is built into `libWPEWebKit-2.0.so`, so no additional libraries are needed. - -**With WPEBackend-FDO (legacy):** -- `libWPEBackend-fdo-1.0.so.*` - FDO backend library -- `libWPEBackend-default.so` - Symlink to FDO backend - -## Architecture - -``` -Flutter App - │ - ▼ -flutter_inappwebview Dart layer - │ - ▼ -Method Channel - │ - ▼ -InAppWebView (C++) - │ - ├──► WebKitWebView (WPE WebKit) - │ │ - │ ▼ - │ ┌─────────────────────────────────────┐ - │ │ WPE Backend (compile-time choice) │ - │ ├─────────────────────────────────────┤ - │ │ WPEPlatform (DEFAULT) │ - │ │ - wpe-platform-2.0 │ - │ │ - wpe-platform-headless-2.0 │ - │ │ - Modern API (WPE WebKit 2.40+) │ - │ ├─────────────────────────────────────┤ - │ │ WPEBackend-FDO (LEGACY FALLBACK) │ - │ │ - wpebackend-fdo-1.0 │ - │ │ - For older systems │ - │ └─────────────────────────────────────┘ - │ │ - │ ▼ - └──► Flutter Texture ◄──── SHM Buffer / DMA-BUF -``` - -## Troubleshooting - -### "WPE WebKit not found" - -Ensure pkg-config can find the libraries: - -```bash -# Core WPE WebKit library (required) -pkg-config --cflags --libs wpe-webkit-2.0 -pkg-config --cflags --libs wpe-1.0 - -# WPEPlatform (default backend) - check if available -pkg-config --cflags --libs wpe-platform-2.0 -pkg-config --cflags --libs wpe-platform-headless-2.0 - -# WPEBackend-FDO (legacy fallback) - check if available -pkg-config --cflags --libs wpebackend-fdo-1.0 -``` - -If not found, add the installation prefix: - -```bash -export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/lib/$(uname -m)-linux-gnu/pkgconfig:$PKG_CONFIG_PATH -``` - -### "Failed to load WPEBackend-default.so" - -This error only applies to the **WPEBackend-FDO (legacy)** backend. If you're using WPEPlatform, you won't see this error. - -Create the default backend symlink: - -```bash -sudo ln -sf /usr/local/lib/$(uname -m)-linux-gnu/libWPEBackend-fdo-1.0.so.1 \ - /usr/local/lib/libWPEBackend-default.so -``` - -Or for the bundled app, ensure the symlink exists in the `lib/` directory. - -### Build errors for WPE WebKit - -If you encounter missing dependency errors during `cmake`: - -```bash -# If you see "gi-docgen not found" -pip3 install gi-docgen - -# If you see "unifdef not found" -sudo apt-get install unifdef - -# If you see "gperf not found" -sudo apt-get install gperf - -# If you see "ruby not found" -sudo apt-get install ruby ruby-dev - -# If you see GObject introspection errors -sudo apt-get install gobject-introspection libgirepository1.0-dev -``` - -### Libraries not bundled - -If libraries aren't being bundled, check: - -1. CMake output for "Will bundle" messages -2. Library paths are correct in pkg-config - -## Resources - -- [WPE WebKit Official Site](https://wpewebkit.org/) -- [WPE WebKit API Reference](https://webkitgtk.org/reference/wpe-webkit-2.0/stable/) -- [Release Downloads](https://wpewebkit.org/release/) -- [Release Schedule](https://wpewebkit.org/release/schedule/) diff --git a/flutter_inappwebview_linux/analysis_options.yaml b/flutter_inappwebview_linux/analysis_options.yaml deleted file mode 100644 index e2d13ab58a..0000000000 --- a/flutter_inappwebview_linux/analysis_options.yaml +++ /dev/null @@ -1,16 +0,0 @@ -include: package:flutter_lints/flutter.yaml - -linter: - rules: - constant_identifier_names: ignore - deprecated_member_use_from_same_package: ignore - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options -analyzer: - errors: - constant_identifier_names: ignore - deprecated_member_use: ignore - deprecated_member_use_from_same_package: ignore - unnecessary_cast: ignore - unnecessary_import: ignore diff --git a/flutter_inappwebview_linux/example/.gitignore b/flutter_inappwebview_linux/example/.gitignore deleted file mode 100644 index 3820a95c65..0000000000 --- a/flutter_inappwebview_linux/example/.gitignore +++ /dev/null @@ -1,45 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.build/ -.buildlog/ -.history -.svn/ -.swiftpm/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins-dependencies -.pub-cache/ -.pub/ -/build/ -/coverage/ - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/flutter_inappwebview_linux/example/README.md b/flutter_inappwebview_linux/example/README.md deleted file mode 100644 index aed2067a22..0000000000 --- a/flutter_inappwebview_linux/example/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# flutter_inappwebview_linux_example - -Demonstrates how to use the flutter_inappwebview_linux plugin. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/flutter_inappwebview_linux/example/analysis_options.yaml b/flutter_inappwebview_linux/example/analysis_options.yaml deleted file mode 100644 index 0d2902135c..0000000000 --- a/flutter_inappwebview_linux/example/analysis_options.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at https://dart.dev/lints. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/flutter_inappwebview_linux/example/assets/date_input_test.html b/flutter_inappwebview_linux/example/assets/date_input_test.html deleted file mode 100644 index abc925a9e8..0000000000 --- a/flutter_inappwebview_linux/example/assets/date_input_test.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - Date/Time Input Test - - - -

Choose your colors:

- -
- - -
- -
- - -
- - -

📅 Date/Time Input Test

- -
-

How to use

-
    -
  • Click the calendar icon (📅) to open the date picker
  • -
  • You can also type directly in the input field
  • -
  • The picker dialog is movable and non-modal
  • -
  • Double-click a date to quickly confirm
  • -
-
- -
Standard Inputs
- -
- - -
Value: 2024-03-15
-
- -
- - -
Value: 2024-03-15T14:30
-
- -
- - -
Value: 14:30
-
- -
- - -
Value: 2024-03
-
- -
- - -
Value: 2024-W11
-
- -
With Constraints
- -
- - -
Value: (empty)
-
- -
Disabled / Readonly (should NOT open picker)
- -
- - -
Disabled - should not open picker
-
- -
- - -
Readonly - should not open picker
-
- - - - diff --git a/flutter_inappwebview_linux/example/assets/test_page.html b/flutter_inappwebview_linux/example/assets/test_page.html deleted file mode 100644 index 2384cef72a..0000000000 --- a/flutter_inappwebview_linux/example/assets/test_page.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - Local File Test Page - - -

Local File Loaded!

-

This page was loaded via loadFile() from Flutter assets.

- - diff --git a/flutter_inappwebview_linux/example/integration_test/plugin_integration_test.dart b/flutter_inappwebview_linux/example/integration_test/plugin_integration_test.dart deleted file mode 100644 index c5269d9508..0000000000 --- a/flutter_inappwebview_linux/example/integration_test/plugin_integration_test.dart +++ /dev/null @@ -1,43 +0,0 @@ -// This is a basic Flutter integration test. -// -// Since integration tests run in a full Flutter application, they can interact -// with the host side of a plugin implementation, unlike Dart unit tests. -// -// For more information about Flutter integration tests, please see -// https://flutter.dev/to/integration-testing - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:integration_test/integration_test.dart'; - -import 'package:flutter_inappwebview_linux/flutter_inappwebview_linux.dart'; -import 'package:flutter_inappwebview_linux/src/in_app_webview/custom_platform_view.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -void main() { - IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - - testWidgets('LinuxInAppWebViewWidget can be created', (WidgetTester tester) async { - LinuxInAppWebViewPlatform.registerWith(); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Builder( - builder: (context) => LinuxInAppWebViewWidget( - LinuxInAppWebViewWidgetCreationParams( - initialUrlRequest: URLRequest(url: WebUri('https://flutter.dev')), - ), - ).build(context), - ), - ), - ), - ); - - // Wait for the widget to be created - await tester.pump(); - - // Verify that the custom platform view was created - expect(find.byType(CustomPlatformView), findsOneWidget); - }); -} diff --git a/flutter_inappwebview_linux/example/lib/main.dart b/flutter_inappwebview_linux/example/lib/main.dart deleted file mode 100644 index 0b677f49b6..0000000000 --- a/flutter_inappwebview_linux/example/lib/main.dart +++ /dev/null @@ -1,387 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview_linux/flutter_inappwebview_linux.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - - LinuxInAppWebViewPlatform.registerWith(); - - runApp(const MaterialApp(home: MyApp())); -} - -/// Event handler for InAppBrowser tests -class TestInAppBrowserEventHandler extends PlatformInAppBrowserEvents { - bool browserCreated = false; - bool browserExited = false; - Completer browserCreatedCompleter = Completer(); - Completer browserExitedCompleter = Completer(); - - @override - void onBrowserCreated() { - debugPrint('[TEST] InAppBrowser: onBrowserCreated fired'); - browserCreated = true; - if (!browserCreatedCompleter.isCompleted) { - browserCreatedCompleter.complete(); - } - } - - @override - void onExit() { - debugPrint('[TEST] InAppBrowser: onExit fired'); - browserExited = true; - if (!browserExitedCompleter.isCompleted) { - browserExitedCompleter.complete(); - } - } - - @override - void onLoadStart(WebUri? url) { - debugPrint('[TEST] InAppBrowser: onLoadStart - $url'); - } - - @override - void onLoadStop(WebUri? url) { - debugPrint('[TEST] InAppBrowser: onLoadStop - $url'); - } - - @override - FutureOr shouldOverrideUrlLoading(navigationAction) { - debugPrint("\n\nOverride ${navigationAction.request.url}\n\n"); - return NavigationActionPolicy.ALLOW; - } -} - -/// Test InAppBrowser implementation -Future testInAppBrowser() async { - debugPrint('[TEST] InAppBrowser: Starting test...'); - - final browser = LinuxInAppBrowser(LinuxInAppBrowserCreationParams()); - final eventHandler = TestInAppBrowserEventHandler(); - browser.eventHandler = eventHandler; - - // Open URL - try { - await browser.openUrlRequest( - urlRequest: URLRequest(url: WebUri('https://flutter.dev')), - settings: InAppBrowserClassSettings( - browserSettings: InAppBrowserSettings( - toolbarTopBackgroundColor: Colors.blue, - presentationStyle: ModalPresentationStyle.POPOVER, - ), - webViewSettings: InAppWebViewSettings( - isInspectable: kDebugMode, - useShouldOverrideUrlLoading: true, - useOnLoadResource: true, - ), - ), - ); - debugPrint('[TEST] InAppBrowser: openUrlRequest completed'); - } catch (e) { - debugPrint('[TEST] ❌ InAppBrowser: openUrlRequest failed - $e'); - return; - } - - // Wait for browser to be created (with timeout) - try { - await eventHandler.browserCreatedCompleter.future.timeout( - const Duration(seconds: 5), - onTimeout: () { - debugPrint( - '[TEST] ❌ InAppBrowser: Timeout waiting for onBrowserCreated', - ); - }, - ); - } catch (e) { - debugPrint('[TEST] ❌ InAppBrowser: Error waiting for browser - $e'); - } - - if (!eventHandler.browserCreated) { - debugPrint('[TEST] ❌ InAppBrowser: onBrowserCreated not fired'); - return; - } - - debugPrint('[TEST] ✅ InAppBrowser: Browser created successfully'); - - // Test isHidden - try { - final isHidden = await browser.isHidden(); - debugPrint('[TEST] InAppBrowser: isHidden = $isHidden'); - if (isHidden == false) { - debugPrint( - '[TEST] ✅ InAppBrowser: isHidden returned correct value (false)', - ); - } - } catch (e) { - debugPrint('[TEST] ❌ InAppBrowser: isHidden failed - $e'); - } - - // Test hide - try { - await browser.hide(); - debugPrint('[TEST] ✅ InAppBrowser: hide() called successfully'); - await Future.delayed(const Duration(milliseconds: 500)); - - final isHiddenAfterHide = await browser.isHidden(); - debugPrint('[TEST] InAppBrowser: isHidden after hide = $isHiddenAfterHide'); - if (isHiddenAfterHide == true) { - debugPrint('[TEST] ✅ InAppBrowser: hide() worked correctly'); - } - } catch (e) { - debugPrint('[TEST] ❌ InAppBrowser: hide failed - $e'); - } - - // Test show - try { - await browser.show(); - debugPrint('[TEST] ✅ InAppBrowser: show() called successfully'); - await Future.delayed(const Duration(milliseconds: 500)); - - final isHiddenAfterShow = await browser.isHidden(); - debugPrint('[TEST] InAppBrowser: isHidden after show = $isHiddenAfterShow'); - if (isHiddenAfterShow == false) { - debugPrint('[TEST] ✅ InAppBrowser: show() worked correctly'); - } - } catch (e) { - debugPrint('[TEST] ❌ InAppBrowser: show failed - $e'); - } - - // Test setSettings - try { - await browser.setSettings( - settings: InAppBrowserClassSettings( - browserSettings: InAppBrowserSettings( - toolbarTopBackgroundColor: const Color.fromARGB(255, 100, 100, 100), - ), - ), - ); - debugPrint('[TEST] ✅ InAppBrowser: setSettings() called successfully'); - } catch (e) { - debugPrint('[TEST] ❌ InAppBrowser: setSettings failed - $e'); - } - - // Test getSettings - try { - final settings = await browser.getSettings(); - debugPrint('[TEST] InAppBrowser: getSettings() = $settings'); - debugPrint('[TEST] ✅ InAppBrowser: getSettings() called successfully'); - } catch (e) { - debugPrint('[TEST] ❌ InAppBrowser: getSettings failed - $e'); - } - - // Wait for browser exit (with timeout) - try { - await eventHandler.browserExitedCompleter.future.timeout( - const Duration(seconds: 3), - onTimeout: () { - debugPrint('[TEST] ⚠️ InAppBrowser: Timeout waiting for onExit'); - }, - ); - } catch (e) { - debugPrint('[TEST] ⚠️ InAppBrowser: Error waiting for exit - $e'); - } - - if (eventHandler.browserExited) { - debugPrint('[TEST] ✅ InAppBrowser: All tests passed!'); - } else { - debugPrint('[TEST] ⚠️ InAppBrowser: Tests completed but onExit not fired'); - } -} - -/// Test openWithSystemBrowser -Future testOpenWithSystemBrowser() async { - debugPrint('[TEST] openWithSystemBrowser: Starting test...'); - try { - final browser = LinuxInAppBrowser(LinuxInAppBrowserCreationParams()); - await browser.openWithSystemBrowser(url: WebUri('https://flutter.dev')); - debugPrint('[TEST] ✅ openWithSystemBrowser: Command executed successfully'); - } catch (e) { - debugPrint('[TEST] ❌ openWithSystemBrowser: $e'); - } -} - -/// Run all InAppBrowser tests -Future runAllInAppBrowserTests() async { - debugPrint(''); - debugPrint('========================================'); - debugPrint('[TEST] Starting InAppBrowser Test Suite'); - debugPrint('========================================'); - debugPrint(''); - - // Test 1: InAppBrowser - await testInAppBrowser(); - - debugPrint(''); - debugPrint('----------------------------------------'); - debugPrint(''); - - debugPrint(''); - debugPrint('========================================'); - debugPrint('[TEST] InAppBrowser Test Suite Complete'); - debugPrint('========================================'); - debugPrint(''); -} - -class MyApp extends StatefulWidget { - const MyApp({super.key}); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - final GlobalKey webViewKey = GlobalKey(); - - LinuxInAppWebViewController? webViewController; - late LinuxFindInteractionController findInteractionController; - InAppWebViewSettings settings = InAppWebViewSettings( - isInspectable: kDebugMode, - mediaPlaybackRequiresUserGesture: false, - allowsInlineMediaPlayback: true, - iframeAllow: "camera; microphone", - iframeAllowFullscreen: true, - javaScriptCanOpenWindowsAutomatically: true, - // Register custom scheme for onLoadResourceWithCustomScheme testing - // Note: http/https cannot be overridden - WPE WebKit explicitly prohibits it - resourceCustomSchemes: ['myapp'], - // Enable Intelligent Tracking Prevention (ITP) - itpEnabled: true, - ); - - String url = ""; - double progress = 0; - final urlController = TextEditingController(); - - @override - void initState() { - super.initState(); - findInteractionController = LinuxFindInteractionController( - LinuxFindInteractionControllerCreationParams( - onFindResultReceived: - ( - controller, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ) {}, - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text("Linux InAppWebView Tests")), - body: SafeArea( - child: Column( - children: [ - TextField( - decoration: const InputDecoration(prefixIcon: Icon(Icons.search)), - controller: urlController, - keyboardType: TextInputType.url, - onSubmitted: (value) { - var url = WebUri(value); - if (url.scheme.isEmpty) { - url = WebUri("https://www.google.com/search?q=$value"); - } - webViewController?.loadUrl(urlRequest: URLRequest(url: url)); - }, - ), - Expanded( - child: Stack( - children: [ - Padding( - padding: const EdgeInsets.all(50.0), - child: LinuxInAppWebViewWidget( - LinuxInAppWebViewWidgetCreationParams( - key: webViewKey, - initialUrlRequest: URLRequest( - url: WebUri( - "https://www.youtube.com/watch?v=d7j6vZHskNY&themeRefresh=1", - ), - ), - // initialFile: "assets/date_input_test.html", - initialSettings: settings, - onWebViewCreated: (controller) async { - webViewController = controller; - - await Future.delayed(Duration(seconds: 2)); - controller.loadUrl( - urlRequest: URLRequest( - url: WebUri('https://flutter.dev'), - ), - ); - debugPrint('[TEST] Loaded flutter.dev'); - - await Future.delayed(Duration(seconds: 2)); - controller.reload(); - debugPrint('[TEST] Reloaded flutter.dev'); - - await Future.delayed(Duration(seconds: 2)); - controller.loadUrl( - urlRequest: URLRequest( - url: WebUri('https://google.com'), - ), - ); - debugPrint('[TEST] Loaded google.com'); - - await Future.delayed(Duration(seconds: 2)); - controller.reload(); - debugPrint('[TEST] Reloaded google.com'); - - await Future.delayed(Duration(seconds: 2)); - controller.goBack(); - debugPrint('[TEST] Should go back to flutter.dev'); - - await Future.delayed(Duration(seconds: 2)); - controller.goBack(); - debugPrint('[TEST] Should go back to YouTube'); - }, - ), - ).build(context), - ), - progress < 1.0 - ? LinearProgressIndicator(value: progress) - : Container(), - ], - ), - ), - OverflowBar( - alignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - child: const Icon(Icons.arrow_back), - onPressed: () { - webViewController?.goBack(); - }, - ), - ElevatedButton( - child: const Icon(Icons.arrow_forward), - onPressed: () { - webViewController?.goForward(); - }, - ), - ElevatedButton( - child: const Icon(Icons.refresh), - onPressed: () { - webViewController?.reload(); - }, - ), - ElevatedButton.icon( - icon: const Icon(Icons.open_in_browser), - label: const Text('Test InAppBrowser'), - onPressed: () { - runAllInAppBrowserTests(); - }, - ), - ], - ), - ], - ), - ), - ); - } -} diff --git a/flutter_inappwebview_linux/example/linux/.gitignore b/flutter_inappwebview_linux/example/linux/.gitignore deleted file mode 100644 index d3896c9844..0000000000 --- a/flutter_inappwebview_linux/example/linux/.gitignore +++ /dev/null @@ -1 +0,0 @@ -flutter/ephemeral diff --git a/flutter_inappwebview_linux/example/linux/CMakeLists.txt b/flutter_inappwebview_linux/example/linux/CMakeLists.txt deleted file mode 100644 index 76fc27a514..0000000000 --- a/flutter_inappwebview_linux/example/linux/CMakeLists.txt +++ /dev/null @@ -1,175 +0,0 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.13) -project(runner LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "flutter_inappwebview_linux_example") -# The unique GTK application identifier for this application. See: -# https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.pichillilorenzo.flutter_inappwebview_linux") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(SET CMP0063 NEW) - -# Load bundled libraries from the lib/ directory relative to the binary. -set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") - -# Root filesystem for cross-building. -if(FLUTTER_TARGET_PLATFORM_SYSROOT) - set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endif() - -# Define build configuration options. -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") -endif() - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_14) - target_compile_options(${TARGET} PRIVATE -Wall -Werror) - target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") - target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) - -# Application build; see runner/CMakeLists.txt. -add_subdirectory("runner") - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) - -# Only the install-generated bundle's copy of the executable will launch -# correctly, since the resources must in the right relative locations. To avoid -# people trying to run the unbundled copy, put it in a subdirectory instead of -# the default top-level location. -set_target_properties(${BINARY_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" -) - -# Enable the test target. -set(include_flutter_inappwebview_linux_tests TRUE) - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# By default, "installing" just makes a relocatable bundle in the build -# directory. -set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -# Start with a clean build bundle directory every time. -install(CODE " - file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") - " COMPONENT Runtime) - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) - install(FILES "${bundled_library}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endforeach(bundled_library) - -# === WPE Library Symlink Creation === -# Create the necessary soname symlinks so the WPE libraries can find each other at runtime -install(CODE " - # Create symlinks for WPE libraries in the lib directory - set(LIB_DIR \"${INSTALL_BUNDLE_LIB_DIR}\") - - # Function to create soname symlinks for a library - macro(create_lib_symlinks LIB_PATTERN SONAME_BASE) - file(GLOB LIB_FILES \"\${LIB_DIR}/\${LIB_PATTERN}\") - if(LIB_FILES) - list(GET LIB_FILES 0 REAL_LIB) - get_filename_component(REAL_LIB_NAME \"\${REAL_LIB}\" NAME) - - # Create .so.X symlink (e.g., libwpe-1.0.so.1 -> libwpe-1.0.so.1.10.0) - set(SONAME_LINK \"\${LIB_DIR}/\${SONAME_BASE}.so.1\") - if(NOT EXISTS \"\${SONAME_LINK}\") - execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink - \"\${REAL_LIB_NAME}\" \"\${SONAME_LINK}\") - message(STATUS \"Created symlink: \${SONAME_LINK} -> \${REAL_LIB_NAME}\") - endif() - - # Create .so symlink (e.g., libwpe-1.0.so -> libwpe-1.0.so.1) - set(SO_LINK \"\${LIB_DIR}/\${SONAME_BASE}.so\") - if(NOT EXISTS \"\${SO_LINK}\") - execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink - \"\${SONAME_BASE}.so.1\" \"\${SO_LINK}\") - message(STATUS \"Created symlink: \${SO_LINK} -> \${SONAME_BASE}.so.1\") - endif() - endif() - endmacro() - - # Create symlinks for each WPE library - create_lib_symlinks(\"libWPEWebKit-2.0.so.*.*.*\" \"libWPEWebKit-2.0\") - create_lib_symlinks(\"libwpe-1.0.so.*.*.*\" \"libwpe-1.0\") - create_lib_symlinks(\"libWPEBackend-fdo-1.0.so.*.*.*\" \"libWPEBackend-fdo-1.0\") - - # Create the default backend symlink that WPE expects - set(DEFAULT_BACKEND_LINK \"\${LIB_DIR}/libWPEBackend-default.so\") - if(NOT EXISTS \"\${DEFAULT_BACKEND_LINK}\") - execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink - \"libWPEBackend-fdo-1.0.so.1\" \"\${DEFAULT_BACKEND_LINK}\") - message(STATUS \"Created symlink: \${DEFAULT_BACKEND_LINK} -> libWPEBackend-fdo-1.0.so.1\") - endif() - " COMPONENT Runtime) - -# Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") -install(DIRECTORY "${NATIVE_ASSETS_DIR}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") - install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() diff --git a/flutter_inappwebview_linux/example/linux/flutter/CMakeLists.txt b/flutter_inappwebview_linux/example/linux/flutter/CMakeLists.txt deleted file mode 100644 index d5bd01648a..0000000000 --- a/flutter_inappwebview_linux/example/linux/flutter/CMakeLists.txt +++ /dev/null @@ -1,88 +0,0 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.10) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. - -# Serves the same purpose as list(TRANSFORM ... PREPEND ...), -# which isn't available in 3.10. -function(list_prepend LIST_NAME PREFIX) - set(NEW_LIST "") - foreach(element ${${LIST_NAME}}) - list(APPEND NEW_LIST "${PREFIX}${element}") - endforeach(element) - set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) -endfunction() - -# === Flutter Library === -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) -pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) - -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "fl_basic_message_channel.h" - "fl_binary_codec.h" - "fl_binary_messenger.h" - "fl_dart_project.h" - "fl_engine.h" - "fl_json_message_codec.h" - "fl_json_method_codec.h" - "fl_message_codec.h" - "fl_method_call.h" - "fl_method_channel.h" - "fl_method_codec.h" - "fl_method_response.h" - "fl_plugin_registrar.h" - "fl_plugin_registry.h" - "fl_standard_message_codec.h" - "fl_standard_method_codec.h" - "fl_string_codec.h" - "fl_value.h" - "fl_view.h" - "flutter_linux.h" -) -list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") -target_link_libraries(flutter INTERFACE - PkgConfig::GTK - PkgConfig::GLIB - PkgConfig::GIO -) -add_dependencies(flutter flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CMAKE_CURRENT_BINARY_DIR}/_phony_ - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" - ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} -) diff --git a/flutter_inappwebview_linux/example/linux/flutter/generated_plugin_registrant.cc b/flutter_inappwebview_linux/example/linux/flutter/generated_plugin_registrant.cc deleted file mode 100644 index 5a06516deb..0000000000 --- a/flutter_inappwebview_linux/example/linux/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - -#include - -void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) flutter_inappwebview_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterInappwebviewLinuxPlugin"); - flutter_inappwebview_linux_plugin_register_with_registrar(flutter_inappwebview_linux_registrar); -} diff --git a/flutter_inappwebview_linux/example/linux/flutter/generated_plugin_registrant.h b/flutter_inappwebview_linux/example/linux/flutter/generated_plugin_registrant.h deleted file mode 100644 index e0f0a47bc0..0000000000 --- a/flutter_inappwebview_linux/example/linux/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void fl_register_plugins(FlPluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/flutter_inappwebview_linux/example/linux/flutter/generated_plugins.cmake b/flutter_inappwebview_linux/example/linux/flutter/generated_plugins.cmake deleted file mode 100644 index e6d369b08a..0000000000 --- a/flutter_inappwebview_linux/example/linux/flutter/generated_plugins.cmake +++ /dev/null @@ -1,24 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST - flutter_inappwebview_linux -) - -list(APPEND FLUTTER_FFI_PLUGIN_LIST -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) - -foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) -endforeach(ffi_plugin) diff --git a/flutter_inappwebview_linux/example/linux/runner/CMakeLists.txt b/flutter_inappwebview_linux/example/linux/runner/CMakeLists.txt deleted file mode 100644 index e97dabc702..0000000000 --- a/flutter_inappwebview_linux/example/linux/runner/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -cmake_minimum_required(VERSION 3.13) -project(runner LANGUAGES CXX) - -# Define the application target. To change its name, change BINARY_NAME in the -# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer -# work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add preprocessor definitions for the application ID. -add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") - -# Add dependency libraries. Add any application-specific dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter) -target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) - -target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/flutter_inappwebview_linux/example/linux/runner/main.cc b/flutter_inappwebview_linux/example/linux/runner/main.cc deleted file mode 100644 index e7c5c54370..0000000000 --- a/flutter_inappwebview_linux/example/linux/runner/main.cc +++ /dev/null @@ -1,6 +0,0 @@ -#include "my_application.h" - -int main(int argc, char** argv) { - g_autoptr(MyApplication) app = my_application_new(); - return g_application_run(G_APPLICATION(app), argc, argv); -} diff --git a/flutter_inappwebview_linux/example/linux/runner/my_application.cc b/flutter_inappwebview_linux/example/linux/runner/my_application.cc deleted file mode 100644 index 997ca776a2..0000000000 --- a/flutter_inappwebview_linux/example/linux/runner/my_application.cc +++ /dev/null @@ -1,148 +0,0 @@ -#include "my_application.h" - -#include -#ifdef GDK_WINDOWING_X11 -#include -#endif - -#include "flutter/generated_plugin_registrant.h" - -struct _MyApplication { - GtkApplication parent_instance; - char** dart_entrypoint_arguments; -}; - -G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) - -// Called when first Flutter frame received. -static void first_frame_cb(MyApplication* self, FlView* view) { - gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); -} - -// Implements GApplication::activate. -static void my_application_activate(GApplication* application) { - MyApplication* self = MY_APPLICATION(application); - GtkWindow* window = - GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); - - // Use a header bar when running in GNOME as this is the common style used - // by applications and is the setup most users will be using (e.g. Ubuntu - // desktop). - // If running on X and not using GNOME then just use a traditional title bar - // in case the window manager does more exotic layout, e.g. tiling. - // If running on Wayland assume the header bar will work (may need changing - // if future cases occur). - gboolean use_header_bar = TRUE; -#ifdef GDK_WINDOWING_X11 - GdkScreen* screen = gtk_window_get_screen(window); - if (GDK_IS_X11_SCREEN(screen)) { - const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); - if (g_strcmp0(wm_name, "GNOME Shell") != 0) { - use_header_bar = FALSE; - } - } -#endif - if (use_header_bar) { - GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); - gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "flutter_inappwebview_linux_example"); - gtk_header_bar_set_show_close_button(header_bar, TRUE); - gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); - } else { - gtk_window_set_title(window, "flutter_inappwebview_linux_example"); - } - - gtk_window_set_default_size(window, 1280, 720); - - g_autoptr(FlDartProject) project = fl_dart_project_new(); - fl_dart_project_set_dart_entrypoint_arguments( - project, self->dart_entrypoint_arguments); - - FlView* view = fl_view_new(project); - GdkRGBA background_color; - // Background defaults to black, override it here if necessary, e.g. #00000000 - // for transparent. - gdk_rgba_parse(&background_color, "#000000"); - fl_view_set_background_color(view, &background_color); - gtk_widget_show(GTK_WIDGET(view)); - gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); - - // Show the window when Flutter renders. - // Requires the view to be realized so we can start rendering. - g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), - self); - gtk_widget_realize(GTK_WIDGET(view)); - - fl_register_plugins(FL_PLUGIN_REGISTRY(view)); - - gtk_widget_grab_focus(GTK_WIDGET(view)); -} - -// Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, - gchar*** arguments, - int* exit_status) { - MyApplication* self = MY_APPLICATION(application); - // Strip out the first argument as it is the binary name. - self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); - - g_autoptr(GError) error = nullptr; - if (!g_application_register(application, nullptr, &error)) { - g_warning("Failed to register: %s", error->message); - *exit_status = 1; - return TRUE; - } - - g_application_activate(application); - *exit_status = 0; - - return TRUE; -} - -// Implements GApplication::startup. -static void my_application_startup(GApplication* application) { - // MyApplication* self = MY_APPLICATION(object); - - // Perform any actions required at application startup. - - G_APPLICATION_CLASS(my_application_parent_class)->startup(application); -} - -// Implements GApplication::shutdown. -static void my_application_shutdown(GApplication* application) { - // MyApplication* self = MY_APPLICATION(object); - - // Perform any actions required at application shutdown. - - G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); -} - -// Implements GObject::dispose. -static void my_application_dispose(GObject* object) { - MyApplication* self = MY_APPLICATION(object); - g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); - G_OBJECT_CLASS(my_application_parent_class)->dispose(object); -} - -static void my_application_class_init(MyApplicationClass* klass) { - G_APPLICATION_CLASS(klass)->activate = my_application_activate; - G_APPLICATION_CLASS(klass)->local_command_line = - my_application_local_command_line; - G_APPLICATION_CLASS(klass)->startup = my_application_startup; - G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; - G_OBJECT_CLASS(klass)->dispose = my_application_dispose; -} - -static void my_application_init(MyApplication* self) {} - -MyApplication* my_application_new() { - // Set the program name to the application ID, which helps various systems - // like GTK and desktop environments map this running application to its - // corresponding .desktop file. This ensures better integration by allowing - // the application to be recognized beyond its binary name. - g_set_prgname(APPLICATION_ID); - - return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, "flags", - G_APPLICATION_NON_UNIQUE, nullptr)); -} diff --git a/flutter_inappwebview_linux/example/linux/runner/my_application.h b/flutter_inappwebview_linux/example/linux/runner/my_application.h deleted file mode 100644 index db16367a77..0000000000 --- a/flutter_inappwebview_linux/example/linux/runner/my_application.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef FLUTTER_MY_APPLICATION_H_ -#define FLUTTER_MY_APPLICATION_H_ - -#include - -G_DECLARE_FINAL_TYPE(MyApplication, - my_application, - MY, - APPLICATION, - GtkApplication) - -/** - * my_application_new: - * - * Creates a new Flutter-based application. - * - * Returns: a new #MyApplication. - */ -MyApplication* my_application_new(); - -#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/flutter_inappwebview_linux/example/pubspec.lock b/flutter_inappwebview_linux/example/pubspec.lock deleted file mode 100644 index 96ca68f39a..0000000000 --- a/flutter_inappwebview_linux/example/pubspec.lock +++ /dev/null @@ -1,361 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" - source: hosted - version: "2.13.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - ffi: - dependency: transitive - description: - name: ffi - sha256: d07d37192dbf97461359c1518788f203b0c9102cfd2c35a716b823741219542c - url: "https://pub.dev" - source: hosted - version: "2.1.5" - file: - dependency: transitive - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_driver: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_inappwebview_internal_annotations: - dependency: transitive - description: - path: "../../dev_packages/flutter_inappwebview_internal_annotations" - relative: true - source: path - version: "1.3.0" - flutter_inappwebview_linux: - dependency: "direct main" - description: - path: ".." - relative: true - source: path - version: "0.1.0-beta.1" - flutter_inappwebview_platform_interface: - dependency: "direct main" - description: - path: "../../flutter_inappwebview_platform_interface" - relative: true - source: path - version: "1.4.0-beta.3" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - fuchsia_remote_debug_protocol: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - integration_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" - source: hosted - version: "11.0.2" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" - source: hosted - version: "3.0.10" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - lints: - dependency: transitive - description: - name: lints - sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0 - url: "https://pub.dev" - source: hosted - version: "6.0.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" - url: "https://pub.dev" - source: hosted - version: "1.17.0" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - path_provider: - dependency: "direct main" - description: - name: path_provider - sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e - url: "https://pub.dev" - source: hosted - version: "2.2.22" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "6d13aece7b3f5c5a9731eaf553ff9dcbc2eff41087fd2df587fd0fed9a3eb0c4" - url: "https://pub.dev" - source: hosted - version: "2.5.1" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" - source: hosted - version: "2.3.0" - platform: - dependency: transitive - description: - name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" - source: hosted - version: "3.1.6" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - process: - dependency: transitive - description: - name: process - sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744 - url: "https://pub.dev" - source: hosted - version: "5.0.5" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_span: - dependency: transitive - description: - name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" - source: hosted - version: "1.10.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" - source: hosted - version: "1.4.1" - sync_http: - dependency: transitive - description: - name: sync_http - sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" - url: "https://pub.dev" - source: hosted - version: "0.3.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - test_api: - dependency: transitive - description: - name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 - url: "https://pub.dev" - source: hosted - version: "0.7.7" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" - source: hosted - version: "2.2.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" - url: "https://pub.dev" - source: hosted - version: "15.0.2" - webdriver: - dependency: transitive - description: - name: webdriver - sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" - url: "https://pub.dev" - source: hosted - version: "3.1.0" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" - source: hosted - version: "1.1.0" -sdks: - dart: ">=3.10.4 <4.0.0" - flutter: ">=3.35.0" diff --git a/flutter_inappwebview_linux/example/pubspec.yaml b/flutter_inappwebview_linux/example/pubspec.yaml deleted file mode 100644 index 718c864cdc..0000000000 --- a/flutter_inappwebview_linux/example/pubspec.yaml +++ /dev/null @@ -1,89 +0,0 @@ -name: flutter_inappwebview_linux_example -description: "Demonstrates how to use the flutter_inappwebview_linux plugin." -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -environment: - sdk: ^3.10.4 - -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. -dependencies: - flutter: - sdk: flutter - - flutter_inappwebview_linux: - # When depending on this package from a real application you should use: - # flutter_inappwebview_linux: ^x.y.z - # See https://dart.dev/tools/pub/dependencies#version-constraints - # The example app is bundled with the plugin so we use a path dependency on - # the parent directory to use the current plugin's version. - path: ../ - - flutter_inappwebview_platform_interface: - path: ../../flutter_inappwebview_platform_interface - - path_provider: ^2.1.0 - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.8 - -dev_dependencies: - integration_test: - sdk: flutter - flutter_test: - sdk: flutter - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^6.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - assets: - - assets/ - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/to/resolution-aware-images - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/to/asset-from-package - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/to/font-from-package diff --git a/flutter_inappwebview_linux/example/test/widget_test.dart b/flutter_inappwebview_linux/example/test/widget_test.dart deleted file mode 100644 index 769ed115f9..0000000000 --- a/flutter_inappwebview_linux/example/test/widget_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:flutter_inappwebview_linux_example/main.dart'; - -void main() { - testWidgets('Verify Platform version', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that platform version is retrieved. - expect( - find.byWidgetPredicate( - (Widget widget) => widget is Text && - widget.data!.startsWith('Running on:'), - ), - findsOneWidget, - ); - }); -} diff --git a/flutter_inappwebview_linux/lib/flutter_inappwebview_linux.dart b/flutter_inappwebview_linux/lib/flutter_inappwebview_linux.dart deleted file mode 100644 index 867711ef70..0000000000 --- a/flutter_inappwebview_linux/lib/flutter_inappwebview_linux.dart +++ /dev/null @@ -1,3 +0,0 @@ -library flutter_inappwebview_linux; - -export 'src/main.dart'; diff --git a/flutter_inappwebview_linux/lib/src/cookie_manager/cookie_manager.dart b/flutter_inappwebview_linux/lib/src/cookie_manager/cookie_manager.dart deleted file mode 100644 index 54113d19fa..0000000000 --- a/flutter_inappwebview_linux/lib/src/cookie_manager/cookie_manager.dart +++ /dev/null @@ -1,182 +0,0 @@ -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [LinuxCookieManager]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformCookieManagerCreationParams] for -/// more information. -class LinuxCookieManagerCreationParams - extends PlatformCookieManagerCreationParams { - /// Creates a new [LinuxCookieManagerCreationParams] instance. - const LinuxCookieManagerCreationParams(); - - /// Creates a [LinuxCookieManagerCreationParams] instance based on [PlatformCookieManagerCreationParams]. - factory LinuxCookieManagerCreationParams.fromPlatformCookieManagerCreationParams( - PlatformCookieManagerCreationParams params, - ) { - return const LinuxCookieManagerCreationParams(); - } -} - -/// Implementation of [PlatformCookieManager] for Linux using WebKitGTK. -class LinuxCookieManager extends PlatformCookieManager { - static const MethodChannel _channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_cookiemanager', - ); - - /// Constructs a [LinuxCookieManager]. - LinuxCookieManager(PlatformCookieManagerCreationParams params) - : super.implementation( - params is LinuxCookieManagerCreationParams - ? params - : LinuxCookieManagerCreationParams.fromPlatformCookieManagerCreationParams( - params, - ), - ); - - static final LinuxCookieManager _instance = LinuxCookieManager( - const LinuxCookieManagerCreationParams(), - ); - - /// The [LinuxCookieManager] singleton instance. - static LinuxCookieManager instance() => _instance; - - /// Creates and returns a new [LinuxCookieManager] for static methods. - factory LinuxCookieManager.static() => _instance; - - @override - Future setCookie({ - required WebUri url, - required String name, - required String value, - String path = "/", - String? domain, - int? expiresDate, - int? maxAge, - bool? isSecure, - bool? isHttpOnly, - HTTPCookieSameSitePolicy? sameSite, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - final Map cookie = { - 'name': name, - 'value': value, - 'path': path, - if (domain != null) 'domain': domain, - if (expiresDate != null) 'expiresDate': expiresDate, - if (maxAge != null) 'maxAge': maxAge, - if (isSecure != null) 'isSecure': isSecure, - if (isHttpOnly != null) 'isHttpOnly': isHttpOnly, - if (sameSite != null) 'sameSite': sameSite.toString().split('.').last, - }; - - final result = await _channel.invokeMethod('setCookie', { - 'url': url.toString(), - 'cookie': cookie, - }); - - return result ?? false; - } - - @override - Future> getCookies({ - required WebUri url, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - final result = await _channel.invokeMethod>('getCookies', { - 'url': url.toString(), - }); - - if (result == null) { - return []; - } - - return result - .cast>() - .map((cookieMap) => Cookie.fromMap(cookieMap.cast())!) - .toList(); - } - - @override - Future getCookie({ - required WebUri url, - required String name, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - final result = await _channel.invokeMethod?>( - 'getCookie', - {'url': url.toString(), 'name': name}, - ); - - if (result == null) { - return null; - } - - return Cookie.fromMap(result.cast()); - } - - @override - Future deleteCookie({ - required WebUri url, - required String name, - String path = "/", - String? domain, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - final result = await _channel.invokeMethod('deleteCookie', { - 'url': url.toString(), - 'name': name, - 'path': path, - 'domain': domain ?? '', - }); - - return result ?? false; - } - - @override - Future deleteCookies({ - required WebUri url, - String path = "/", - String? domain, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - final result = await _channel.invokeMethod('deleteCookies', { - 'url': url.toString(), - 'path': path, - 'domain': domain ?? '', - }); - - return result ?? false; - } - - @override - Future deleteAllCookies() async { - final result = await _channel.invokeMethod('deleteAllCookies'); - return result ?? false; - } - - @override - Future> getAllCookies() async { - final result = await _channel.invokeMethod>('getAllCookies'); - - if (result == null) { - return []; - } - - return result - .cast>() - .map((cookieMap) => Cookie.fromMap(cookieMap.cast())!) - .toList(); - } -} diff --git a/flutter_inappwebview_linux/lib/src/cookie_manager/main.dart b/flutter_inappwebview_linux/lib/src/cookie_manager/main.dart deleted file mode 100644 index e94e06a6ff..0000000000 --- a/flutter_inappwebview_linux/lib/src/cookie_manager/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'cookie_manager.dart'; diff --git a/flutter_inappwebview_linux/lib/src/find_interaction/find_interaction_controller.dart b/flutter_inappwebview_linux/lib/src/find_interaction/find_interaction_controller.dart deleted file mode 100644 index fedd1181a9..0000000000 --- a/flutter_inappwebview_linux/lib/src/find_interaction/find_interaction_controller.dart +++ /dev/null @@ -1,149 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [LinuxFindInteractionController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformFindInteractionControllerCreationParams] for -/// more information. -@immutable -class LinuxFindInteractionControllerCreationParams - extends PlatformFindInteractionControllerCreationParams { - /// Creates a new [LinuxFindInteractionControllerCreationParams] instance. - const LinuxFindInteractionControllerCreationParams({ - super.onFindResultReceived, - }); - - /// Creates a [LinuxFindInteractionControllerCreationParams] instance based on [PlatformFindInteractionControllerCreationParams]. - factory LinuxFindInteractionControllerCreationParams.fromPlatformFindInteractionControllerCreationParams( - PlatformFindInteractionControllerCreationParams params, - ) { - return LinuxFindInteractionControllerCreationParams( - onFindResultReceived: params.onFindResultReceived, - ); - } -} - -/// Implementation of [PlatformFindInteractionController] for Linux. -class LinuxFindInteractionController extends PlatformFindInteractionController - with ChannelController { - /// Creates a new [LinuxFindInteractionController]. - LinuxFindInteractionController( - PlatformFindInteractionControllerCreationParams params, - ) : super.implementation( - params is LinuxFindInteractionControllerCreationParams - ? params - : LinuxFindInteractionControllerCreationParams.fromPlatformFindInteractionControllerCreationParams( - params, - ), - ); - - static final LinuxFindInteractionController _staticValue = - LinuxFindInteractionController( - LinuxFindInteractionControllerCreationParams(), - ); - - /// Provide static access. - factory LinuxFindInteractionController.static() { - return _staticValue; - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - debugLoggingSettings: - PlatformFindInteractionController.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - _debugLog(call.method, call.arguments); - - switch (call.method) { - case "onFindResultReceived": - if (onFindResultReceived != null) { - int activeMatchOrdinal = call.arguments["activeMatchOrdinal"]; - int numberOfMatches = call.arguments["numberOfMatches"]; - bool isDoneCounting = call.arguments["isDoneCounting"]; - onFindResultReceived!( - this, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findAll} - @override - Future findAll({String? find}) async { - Map args = {}; - args.putIfAbsent('find', () => find); - await channel?.invokeMethod('findAll', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findNext} - @override - Future findNext({bool forward = true}) async { - Map args = {}; - args.putIfAbsent('forward', () => forward); - await channel?.invokeMethod('findNext', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.clearMatches} - @override - Future clearMatches() async { - Map args = {}; - await channel?.invokeMethod('clearMatches', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.setSearchText} - @override - Future setSearchText(String? searchText) async { - Map args = {}; - args.putIfAbsent('searchText', () => searchText); - await channel?.invokeMethod('setSearchText', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getSearchText} - @override - Future getSearchText() async { - Map args = {}; - return await channel?.invokeMethod('getSearchText', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getActiveFindSession} - @override - Future getActiveFindSession() async { - Map args = {}; - Map? result = (await channel?.invokeMethod( - 'getActiveFindSession', - args, - ))?.cast(); - return FindSession.fromMap(result); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.dispose} - @override - void dispose({bool isKeepAlive = false}) { - disposeChannel(removeMethodCallHandler: !isKeepAlive); - } -} - -extension InternalFindInteractionController on LinuxFindInteractionController { - void init(dynamic id) { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_find_interaction_$id', - ); - handler = _handleMethod; - initMethodCallHandler(); - } -} diff --git a/flutter_inappwebview_linux/lib/src/find_interaction/main.dart b/flutter_inappwebview_linux/lib/src/find_interaction/main.dart deleted file mode 100644 index a7adaacf7b..0000000000 --- a/flutter_inappwebview_linux/lib/src/find_interaction/main.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'find_interaction_controller.dart' - hide InternalFindInteractionController; diff --git a/flutter_inappwebview_linux/lib/src/http_auth_credentials_database.dart b/flutter_inappwebview_linux/lib/src/http_auth_credentials_database.dart deleted file mode 100644 index 674adb4783..0000000000 --- a/flutter_inappwebview_linux/lib/src/http_auth_credentials_database.dart +++ /dev/null @@ -1,180 +0,0 @@ -import 'dart:async'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [LinuxHttpAuthCredentialDatabase]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformHttpAuthCredentialDatabaseCreationParams] for -/// more information. -@immutable -class LinuxHttpAuthCredentialDatabaseCreationParams - extends PlatformHttpAuthCredentialDatabaseCreationParams { - /// Creates a new [LinuxHttpAuthCredentialDatabaseCreationParams] instance. - const LinuxHttpAuthCredentialDatabaseCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) : super(); - - /// Creates a [LinuxHttpAuthCredentialDatabaseCreationParams] instance based on [PlatformHttpAuthCredentialDatabaseCreationParams]. - factory LinuxHttpAuthCredentialDatabaseCreationParams.fromPlatformHttpAuthCredentialDatabaseCreationParams( - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) { - return LinuxHttpAuthCredentialDatabaseCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase} -/// -/// This implementation delegates to native C++ code which uses libsecret for secure storage. -/// Passwords are stored in the system keyring (gnome-keyring, KDE Wallet, etc.). -/// A JSON index file at ~/.local/share/flutter_inappwebview//credential_index.json -/// is used to enumerate stored credentials (contains only usernames, not passwords). -/// -/// The native `appId` is resolved from `GApplication.application_id` when available. -/// If it is null/empty, it falls back to the executable filename (from `/proc/self/exe`), sanitized. -class LinuxHttpAuthCredentialDatabase - extends PlatformHttpAuthCredentialDatabase { - static const MethodChannel _channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_credential_database', - ); - - /// Creates a new [LinuxHttpAuthCredentialDatabase]. - LinuxHttpAuthCredentialDatabase( - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) : super.implementation( - params is LinuxHttpAuthCredentialDatabaseCreationParams - ? params - : LinuxHttpAuthCredentialDatabaseCreationParams.fromPlatformHttpAuthCredentialDatabaseCreationParams( - params, - ), - ); - - static LinuxHttpAuthCredentialDatabase? _instance; - - /// Gets the database shared instance. - static LinuxHttpAuthCredentialDatabase instance() { - return (_instance != null) ? _instance! : _init(); - } - - static LinuxHttpAuthCredentialDatabase _init() { - _instance = LinuxHttpAuthCredentialDatabase( - LinuxHttpAuthCredentialDatabaseCreationParams( - const PlatformHttpAuthCredentialDatabaseCreationParams(), - ), - ); - return _instance!; - } - - static final LinuxHttpAuthCredentialDatabase _staticValue = - LinuxHttpAuthCredentialDatabase( - LinuxHttpAuthCredentialDatabaseCreationParams( - const PlatformHttpAuthCredentialDatabaseCreationParams(), - ), - ); - - factory LinuxHttpAuthCredentialDatabase.static() { - return _staticValue; - } - - @override - Future> - getAllAuthCredentials() async { - final List allCredentials = - await _channel.invokeMethod('getAllAuthCredentials', {}) ?? []; - - List result = []; - - for (final Map map in allCredentials) { - final element = URLProtectionSpaceHttpAuthCredentials.fromMap( - map.cast(), - ); - if (element != null) { - result.add(element); - } - } - return result; - } - - @override - Future> getHttpAuthCredentials({ - required URLProtectionSpace protectionSpace, - }) async { - final Map args = { - 'host': protectionSpace.host, - 'protocol': protectionSpace.protocol, - 'realm': protectionSpace.realm, - 'port': protectionSpace.port, - }; - - final List credentialList = - await _channel.invokeMethod('getHttpAuthCredentials', args) ?? []; - - List credentials = []; - for (final Map map in credentialList) { - final credential = URLCredential.fromMap(map.cast()); - if (credential != null) { - credentials.add(credential); - } - } - return credentials; - } - - @override - Future setHttpAuthCredential({ - required URLProtectionSpace protectionSpace, - required URLCredential credential, - }) async { - final Map args = { - 'host': protectionSpace.host, - 'protocol': protectionSpace.protocol, - 'realm': protectionSpace.realm, - 'port': protectionSpace.port, - 'username': credential.username, - 'password': credential.password, - }; - await _channel.invokeMethod('setHttpAuthCredential', args); - } - - @override - Future removeHttpAuthCredential({ - required URLProtectionSpace protectionSpace, - required URLCredential credential, - }) async { - final Map args = { - 'host': protectionSpace.host, - 'protocol': protectionSpace.protocol, - 'realm': protectionSpace.realm, - 'port': protectionSpace.port, - 'username': credential.username, - 'password': credential.password, - }; - await _channel.invokeMethod('removeHttpAuthCredential', args); - } - - @override - Future removeHttpAuthCredentials({ - required URLProtectionSpace protectionSpace, - }) async { - final Map args = { - 'host': protectionSpace.host, - 'protocol': protectionSpace.protocol, - 'realm': protectionSpace.realm, - 'port': protectionSpace.port, - }; - await _channel.invokeMethod('removeHttpAuthCredentials', args); - } - - @override - Future clearAllAuthCredentials() async { - await _channel.invokeMethod('clearAllAuthCredentials', {}); - } - - /// Disposes of any resources used by this database. - /// Nothing to dispose - native side manages its own lifecycle. - void dispose() { - // Nothing to dispose - } -} diff --git a/flutter_inappwebview_linux/lib/src/in_app_browser/in_app_browser.dart b/flutter_inappwebview_linux/lib/src/in_app_browser/in_app_browser.dart deleted file mode 100644 index 6472495f34..0000000000 --- a/flutter_inappwebview_linux/lib/src/in_app_browser/in_app_browser.dart +++ /dev/null @@ -1,413 +0,0 @@ -import 'dart:async'; -import 'dart:collection'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../find_interaction/find_interaction_controller.dart'; -import '../in_app_webview/in_app_webview_controller.dart'; -import '../webview_environment/webview_environment.dart'; - -/// Object specifying creation parameters for creating a [LinuxInAppBrowser]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformInAppBrowserCreationParams] for -/// more information. -class LinuxInAppBrowserCreationParams - extends PlatformInAppBrowserCreationParams { - /// Creates a new [LinuxInAppBrowserCreationParams] instance. - LinuxInAppBrowserCreationParams({ - super.contextMenu, - super.pullToRefreshController, - this.findInteractionController, - super.initialUserScripts, - super.windowId, - this.webViewEnvironment, - }); - - /// Creates a [LinuxInAppBrowserCreationParams] instance based on [PlatformInAppBrowserCreationParams]. - factory LinuxInAppBrowserCreationParams.fromPlatformInAppBrowserCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformInAppBrowserCreationParams params, - ) { - return LinuxInAppBrowserCreationParams( - contextMenu: params.contextMenu, - pullToRefreshController: params.pullToRefreshController, - findInteractionController: - params.findInteractionController as LinuxFindInteractionController?, - initialUserScripts: params.initialUserScripts, - windowId: params.windowId, - webViewEnvironment: - params.webViewEnvironment as LinuxWebViewEnvironment?, - ); - } - - @override - final LinuxFindInteractionController? findInteractionController; - - @override - final LinuxWebViewEnvironment? webViewEnvironment; -} - -///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser} -class LinuxInAppBrowser extends PlatformInAppBrowser with ChannelController { - @override - final String id = IdGenerator.generate(); - - /// Constructs a [LinuxInAppBrowser]. - LinuxInAppBrowser(PlatformInAppBrowserCreationParams params) - : super.implementation( - params is LinuxInAppBrowserCreationParams - ? params - : LinuxInAppBrowserCreationParams.fromPlatformInAppBrowserCreationParams( - params, - ), - ) { - _contextMenu = params.contextMenu; - } - - static final LinuxInAppBrowser _staticValue = LinuxInAppBrowser( - LinuxInAppBrowserCreationParams(), - ); - - /// Provide static access. - factory LinuxInAppBrowser.static() { - return _staticValue; - } - - LinuxInAppBrowserCreationParams get _linuxParams => - params as LinuxInAppBrowserCreationParams; - - static const MethodChannel _staticChannel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappbrowser', - ); - - ContextMenu? _contextMenu; - - @override - ContextMenu? get contextMenu => _contextMenu; - - Map _menuItems = HashMap(); - bool _isOpened = false; - LinuxInAppWebViewController? _webViewController; - - @override - LinuxInAppWebViewController? get webViewController { - return _isOpened ? _webViewController : null; - } - - _init() { - channel = MethodChannel('com.pichillilorenzo/flutter_inappbrowser_$id'); - handler = _handleMethod; - initMethodCallHandler(); - - _webViewController = LinuxInAppWebViewController.fromInAppBrowser( - LinuxInAppWebViewControllerCreationParams(id: id), - channel!, - this, - this.initialUserScripts, - ); - _linuxParams.findInteractionController?.init(id); - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - id: id, - debugLoggingSettings: PlatformInAppBrowser.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onBrowserCreated": - _debugLog(call.method, call.arguments); - eventHandler?.onBrowserCreated(); - break; - case "onMenuItemClicked": - _debugLog(call.method, call.arguments); - int id = call.arguments["id"].toInt(); - if (this._menuItems[id] != null) { - if (this._menuItems[id]?.onClick != null) { - this._menuItems[id]?.onClick!(); - } - } - break; - case "onMainWindowWillClose": - _debugLog(call.method, call.arguments); - eventHandler?.onMainWindowWillClose(); - break; - case "onExit": - _debugLog(call.method, call.arguments); - _isOpened = false; - final onExit = eventHandler?.onExit; - dispose(); - onExit?.call(); - break; - default: - return _webViewController?.handleMethod(call); - } - } - - Map _prepareOpenRequest({ - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) { - assert(!_isOpened, 'The browser is already opened.'); - _isOpened = true; - _init(); - - var initialSettings = - settings?.toMap() ?? - options?.toMap() ?? - InAppBrowserClassSettings().toMap(); - - Map pullToRefreshSettings = - pullToRefreshController?.settings.toMap() ?? - pullToRefreshController?.options.toMap() ?? - PullToRefreshSettings(enabled: false).toMap(); - - List> menuItemList = []; - _menuItems.forEach((key, value) { - menuItemList.add(value.toMap()); - }); - - Map args = {}; - args.putIfAbsent('id', () => id); - args.putIfAbsent('settings', () => initialSettings); - args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {}); - args.putIfAbsent('windowId', () => windowId); - args.putIfAbsent( - 'initialUserScripts', - () => initialUserScripts?.map((e) => e.toMap()).toList() ?? [], - ); - args.putIfAbsent('pullToRefreshSettings', () => pullToRefreshSettings); - args.putIfAbsent('menuItems', () => menuItemList); - args.putIfAbsent( - 'webViewEnvironmentId', - () => _linuxParams.webViewEnvironment?.id, - ); - return args; - } - - @override - Future openUrlRequest({ - required URLRequest urlRequest, - // ignore: deprecated_member_use_from_same_package - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) async { - assert(urlRequest.url != null && urlRequest.url.toString().isNotEmpty); - - Map args = _prepareOpenRequest( - options: options, - settings: settings, - ); - args.putIfAbsent('urlRequest', () => urlRequest.toMap()); - await _staticChannel.invokeMethod('open', args); - } - - @override - Future openFile({ - required String assetFilePath, - // ignore: deprecated_member_use_from_same_package - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) async { - assert(assetFilePath.isNotEmpty); - - Map args = _prepareOpenRequest( - options: options, - settings: settings, - ); - args.putIfAbsent('assetFilePath', () => assetFilePath); - await _staticChannel.invokeMethod('open', args); - } - - @override - Future openData({ - required String data, - String mimeType = "text/html", - String encoding = "utf8", - WebUri? baseUrl, - @Deprecated("Use historyUrl instead") Uri? androidHistoryUrl, - WebUri? historyUrl, - // ignore: deprecated_member_use_from_same_package - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) async { - Map args = _prepareOpenRequest( - options: options, - settings: settings, - ); - args.putIfAbsent('data', () => data); - args.putIfAbsent('mimeType', () => mimeType); - args.putIfAbsent('encoding', () => encoding); - args.putIfAbsent('baseUrl', () => baseUrl?.toString() ?? "about:blank"); - args.putIfAbsent( - 'historyUrl', - () => (historyUrl ?? androidHistoryUrl)?.toString() ?? "about:blank", - ); - await _staticChannel.invokeMethod('open', args); - } - - @override - Future openWithSystemBrowser({required WebUri url}) async { - assert(url.toString().isNotEmpty); - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - return await _staticChannel.invokeMethod('openWithSystemBrowser', args); - } - - @override - void addMenuItem(InAppBrowserMenuItem menuItem) { - _menuItems[menuItem.id] = menuItem; - } - - @override - void addMenuItems(List menuItems) { - menuItems.forEach((menuItem) { - _menuItems[menuItem.id] = menuItem; - }); - } - - @override - bool removeMenuItem(InAppBrowserMenuItem menuItem) { - return _menuItems.remove(menuItem.id) != null; - } - - @override - void removeMenuItems(List menuItems) { - for (final menuItem in menuItems) { - removeMenuItem(menuItem); - } - } - - @override - void removeAllMenuItem() { - _menuItems.clear(); - } - - @override - bool hasMenuItem(InAppBrowserMenuItem menuItem) { - return _menuItems.containsKey(menuItem.id); - } - - @override - Future show() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - await channel?.invokeMethod('show', args); - } - - @override - Future hide() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - await channel?.invokeMethod('hide', args); - } - - @override - Future close() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - await channel?.invokeMethod('close', args); - } - - @override - Future isHidden() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - return await channel?.invokeMethod('isHidden', args) ?? false; - } - - @override - @Deprecated('Use setSettings instead') - Future setOptions({required InAppBrowserClassOptions options}) async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - args.putIfAbsent('settings', () => options.toMap()); - await channel?.invokeMethod('setSettings', args); - } - - @override - @Deprecated('Use getSettings instead') - Future getOptions() async { - assert(_isOpened, 'The browser is not opened.'); - Map args = {}; - - Map? options = await channel?.invokeMethod( - 'getSettings', - args, - ); - if (options != null) { - options = options.cast(); - return InAppBrowserClassOptions.fromMap(options as Map); - } - - return null; - } - - @override - Future setSettings({ - required InAppBrowserClassSettings settings, - }) async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - args.putIfAbsent('settings', () => settings.toMap()); - await channel?.invokeMethod('setSettings', args); - } - - @override - Future getSettings() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - - Map? settings = await channel?.invokeMethod( - 'getSettings', - args, - ); - if (settings != null) { - settings = settings.cast(); - return InAppBrowserClassSettings.fromMap( - settings as Map, - ); - } - - return null; - } - - @override - bool isOpened() { - return this._isOpened; - } - - @override - @mustCallSuper - void dispose() { - super.dispose(); - disposeChannel(); - _webViewController?.dispose(); - _webViewController = null; - pullToRefreshController?.dispose(); - findInteractionController?.dispose(); - } -} - -extension InternalInAppBrowser on LinuxInAppBrowser { - void setContextMenu(ContextMenu? contextMenu) { - _contextMenu = contextMenu; - } -} diff --git a/flutter_inappwebview_linux/lib/src/in_app_browser/main.dart b/flutter_inappwebview_linux/lib/src/in_app_browser/main.dart deleted file mode 100644 index e11eb8b182..0000000000 --- a/flutter_inappwebview_linux/lib/src/in_app_browser/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'in_app_browser.dart' hide InternalInAppBrowser; diff --git a/flutter_inappwebview_linux/lib/src/in_app_webview/_static_channel.dart b/flutter_inappwebview_linux/lib/src/in_app_webview/_static_channel.dart deleted file mode 100644 index a02f01ece1..0000000000 --- a/flutter_inappwebview_linux/lib/src/in_app_webview/_static_channel.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:flutter/services.dart'; - -const IN_APP_WEBVIEW_STATIC_CHANNEL = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_manager', -); diff --git a/flutter_inappwebview_linux/lib/src/in_app_webview/custom_platform_view.dart b/flutter_inappwebview_linux/lib/src/in_app_webview/custom_platform_view.dart deleted file mode 100644 index 5ce9b2d297..0000000000 --- a/flutter_inappwebview_linux/lib/src/in_app_webview/custom_platform_view.dart +++ /dev/null @@ -1,686 +0,0 @@ -import 'package:flutter/services.dart'; -import 'dart:async'; -import 'dart:ui'; - -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; - -import '_static_channel.dart'; -import 'key_mappings.dart'; - -const Map _cursors = { - // CSS cursor names (used by WebKit and GDK) - 'none': SystemMouseCursors.none, - 'default': SystemMouseCursors.basic, - 'pointer': SystemMouseCursors.click, - 'text': SystemMouseCursors.text, - 'vertical-text': SystemMouseCursors.verticalText, - 'wait': SystemMouseCursors.wait, - 'progress': SystemMouseCursors.progress, - 'help': SystemMouseCursors.help, - 'crosshair': SystemMouseCursors.precise, - 'move': SystemMouseCursors.move, - 'all-scroll': SystemMouseCursors.allScroll, - 'grab': SystemMouseCursors.grab, - 'grabbing': SystemMouseCursors.grabbing, - 'not-allowed': SystemMouseCursors.forbidden, - 'no-drop': SystemMouseCursors.noDrop, - 'context-menu': SystemMouseCursors.contextMenu, - 'cell': SystemMouseCursors.cell, - 'copy': SystemMouseCursors.copy, - 'alias': SystemMouseCursors.alias, - 'col-resize': SystemMouseCursors.resizeColumn, - 'row-resize': SystemMouseCursors.resizeRow, - 'n-resize': SystemMouseCursors.resizeUp, - 's-resize': SystemMouseCursors.resizeDown, - 'e-resize': SystemMouseCursors.resizeRight, - 'w-resize': SystemMouseCursors.resizeLeft, - 'ns-resize': SystemMouseCursors.resizeUpDown, - 'ew-resize': SystemMouseCursors.resizeLeftRight, - 'ne-resize': SystemMouseCursors.resizeUpRight, - 'nw-resize': SystemMouseCursors.resizeUpLeft, - 'se-resize': SystemMouseCursors.resizeDownRight, - 'sw-resize': SystemMouseCursors.resizeDownLeft, - 'nesw-resize': SystemMouseCursors.resizeUpRightDownLeft, - 'nwse-resize': SystemMouseCursors.resizeUpLeftDownRight, - 'zoom-in': SystemMouseCursors.zoomIn, - 'zoom-out': SystemMouseCursors.zoomOut, - // Legacy internal names (for backward compatibility) - 'basic': SystemMouseCursors.basic, - 'click': SystemMouseCursors.click, - 'forbidden': SystemMouseCursors.forbidden, - 'contextMenu': SystemMouseCursors.contextMenu, - 'verticalText': SystemMouseCursors.verticalText, - 'precise': SystemMouseCursors.precise, - 'noDrop': SystemMouseCursors.noDrop, - 'disappearing': SystemMouseCursors.disappearing, - 'allScroll': SystemMouseCursors.allScroll, - 'resizeLeftRight': SystemMouseCursors.resizeLeftRight, - 'resizeUpDown': SystemMouseCursors.resizeUpDown, - 'resizeUpLeftDownRight': SystemMouseCursors.resizeUpLeftDownRight, - 'resizeUpRightDownLeft': SystemMouseCursors.resizeUpRightDownLeft, - 'resizeUp': SystemMouseCursors.resizeUp, - 'resizeDown': SystemMouseCursors.resizeDown, - 'resizeLeft': SystemMouseCursors.resizeLeft, - 'resizeRight': SystemMouseCursors.resizeRight, - 'resizeUpLeft': SystemMouseCursors.resizeUpLeft, - 'resizeUpRight': SystemMouseCursors.resizeUpRight, - 'resizeDownLeft': SystemMouseCursors.resizeDownLeft, - 'resizeDownRight': SystemMouseCursors.resizeDownRight, - 'resizeColumn': SystemMouseCursors.resizeColumn, - 'resizeRow': SystemMouseCursors.resizeRow, - 'zoomIn': SystemMouseCursors.zoomIn, - 'zoomOut': SystemMouseCursors.zoomOut, -}; - -SystemMouseCursor _getCursorByName(String name) => - _cursors[name] ?? SystemMouseCursors.basic; - -/// Pointer button type -enum PointerButton { none, primary, secondary, tertiary } - -/// Pointer Event kind -enum InAppWebViewPointerEventKind { - activate, - down, - enter, - leave, - up, - update, - cancel, -} - -/// Attempts to translate a button constant such as [kPrimaryMouseButton] -/// to a [PointerButton] -PointerButton _getButton(int value) { - switch (value) { - case kPrimaryMouseButton: - return PointerButton.primary; - case kSecondaryMouseButton: - return PointerButton.secondary; - case kTertiaryButton: - return PointerButton.tertiary; - default: - return PointerButton.none; - } -} - -const MethodChannel _pluginChannel = IN_APP_WEBVIEW_STATIC_CHANNEL; - -class CustomFlutterViewControllerValue { - const CustomFlutterViewControllerValue({required this.isInitialized}); - - final bool isInitialized; - - CustomFlutterViewControllerValue copyWith({bool? isInitialized}) { - return CustomFlutterViewControllerValue( - isInitialized: isInitialized ?? this.isInitialized, - ); - } - - CustomFlutterViewControllerValue.uninitialized() : this(isInitialized: false); -} - -/// Controls a WebView and provides streams for various change events. -class CustomPlatformViewController - extends ValueNotifier { - Completer _creatingCompleter = Completer(); - int _textureId = 0; - bool _isDisposed = false; - - Future get ready => _creatingCompleter.future; - - late MethodChannel _methodChannel; - late EventChannel _eventChannel; - StreamSubscription? _eventStreamSubscription; - - final StreamController _cursorStreamController = - StreamController.broadcast(); - - /// A stream reflecting the current cursor style. - Stream get _cursor => _cursorStreamController.stream; - - CustomPlatformViewController() - : super(CustomFlutterViewControllerValue.uninitialized()); - - /// Initializes the underlying platform view. - Future initialize({ - Function(int id)? onPlatformViewCreated, - dynamic arguments, - }) async { - if (_isDisposed) { - return; - } - _textureId = (await _pluginChannel.invokeMethod( - 'createInAppWebView', - arguments, - ))!; - - _methodChannel = MethodChannel( - 'com.pichillilorenzo/custom_platform_view_$_textureId', - ); - _eventChannel = EventChannel( - 'com.pichillilorenzo/custom_platform_view_${_textureId}_events', - ); - _eventStreamSubscription = _eventChannel.receiveBroadcastStream().listen(( - event, - ) { - final map = event as Map; - switch (map['type']) { - case 'cursorChanged': - _cursorStreamController.add(_getCursorByName(map['value'])); - break; - } - }); - - _methodChannel.setMethodCallHandler((call) { - throw MissingPluginException('Unknown method ${call.method}'); - }); - - value = value.copyWith(isInitialized: true); - - _creatingCompleter.complete(); - - onPlatformViewCreated?.call(_textureId); - } - - @override - Future dispose() async { - await _creatingCompleter.future; - if (!_isDisposed) { - _isDisposed = true; - await _eventStreamSubscription?.cancel(); - await _pluginChannel.invokeMethod('dispose', {"id": _textureId}); - } - super.dispose(); - } - - /// Sets the surface size to the provided [size]. - Future _setSize(Size size, double scaleFactor) async { - if (_isDisposed) { - return; - } - assert(value.isInitialized); - return _methodChannel.invokeMethod('setSize', [ - size.width, - size.height, - scaleFactor, - ]); - } - - /// Sets the texture offset (position within the Flutter window). - Future _setTextureOffset(Offset offset) async { - if (_isDisposed) { - return; - } - assert(value.isInitialized); - return _methodChannel.invokeMethod('setTextureOffset', [ - offset.dx, - offset.dy, - ]); - } - - /// Moves the virtual cursor to [position]. - Future _setCursorPos(Offset position) async { - if (_isDisposed) { - return; - } - assert(value.isInitialized); - return _methodChannel.invokeMethod('setCursorPos', [ - position.dx, - position.dy, - ]); - } - - /// Indicates whether the specified [button] is currently down. - Future _setPointerButtonState( - InAppWebViewPointerEventKind kind, - PointerButton button, - ) async { - if (_isDisposed) { - return; - } - assert(value.isInitialized); - return _methodChannel.invokeMethod('setPointerButton', { - 'kind': kind.index, - 'button': button.index, - 'clickCount': 1, - }); - } - - /// Indicates whether the specified [button] is currently down with click count. - Future _setPointerButtonStateWithClickCount( - InAppWebViewPointerEventKind kind, - PointerButton button, - int clickCount, - ) async { - if (_isDisposed) { - return; - } - assert(value.isInitialized); - return _methodChannel.invokeMethod('setPointerButton', { - 'kind': kind.index, - 'button': button.index, - 'clickCount': clickCount, - }); - } - - /// Sets the horizontal and vertical scroll delta. - Future _setScrollDelta(double dx, double dy) async { - if (_isDisposed) { - return; - } - assert(value.isInitialized); - return _methodChannel.invokeMethod('setScrollDelta', [dx, dy]); - } - - /// Sends a key event to the webview. - Future _sendKeyEvent( - int type, - int keyCode, - int scanCode, - int modifiers, - String? characters, - ) async { - if (_isDisposed) { - return; - } - assert(value.isInitialized); - return _methodChannel.invokeMethod('sendKeyEvent', { - 'type': type, // 0=press, 1=release - 'keyCode': keyCode, - 'scanCode': scanCode, - 'modifiers': modifiers, - 'characters': characters, - }); - } - - /// Sends a touch event to the webview. - /// [type]: 0=down, 1=up, 2=move, 3=cancel - /// [touchPoints]: List of touch point maps with {id, x, y, type} - Future _sendTouchEvent( - int type, - int id, - double x, - double y, - List> touchPoints, - ) async { - if (_isDisposed) { - return; - } - assert(value.isInitialized); - return _methodChannel.invokeMethod('sendTouchEvent', { - 'type': type, - 'id': id, - 'x': x, - 'y': y, - 'touchPoints': touchPoints, - }); - } - - /// Sets the focus state of the webview. - /// This is called when the Flutter widget gains or loses focus. - Future _setFocused(bool focused) async { - if (_isDisposed) { - return; - } - assert(value.isInitialized); - return _methodChannel.invokeMethod('setFocused', focused); - } -} - -class CustomPlatformView extends StatefulWidget { - /// An optional scale factor. Defaults to [FlutterView.devicePixelRatio] for - /// rendering in native resolution. - /// Setting this to 1.0 will disable high-DPI support. - final double? scaleFactor; - - /// The [FilterQuality] used for scaling the texture's contents. - /// Defaults to [FilterQuality.none] as this renders in native resolution. - final FilterQuality filterQuality; - - final dynamic creationParams; - - final Function(int id)? onPlatformViewCreated; - - const CustomPlatformView({ - this.creationParams, - this.onPlatformViewCreated, - this.scaleFactor, - this.filterQuality = FilterQuality.none, - Key? key, - }) : super(key: key); - - @override - _CustomPlatformViewState createState() => _CustomPlatformViewState(); -} - -class _CustomPlatformViewState extends State { - final GlobalKey _key = GlobalKey(); - final _downButtons = {}; - - PointerDeviceKind _pointerKind = PointerDeviceKind.unknown; - - MouseCursor _cursor = SystemMouseCursors.basic; - - final _controller = CustomPlatformViewController(); - final _focusNode = FocusNode(); - - StreamSubscription? _cursorSubscription; - - // Track click timing for double-click detection - DateTime? _lastClickTime; - Offset? _lastClickPosition; - int _clickCount = 0; - static const _doubleClickTimeout = Duration(milliseconds: 400); - static const _doubleClickDistance = 5.0; - - // Track active touch points for multi-touch support - final _activeTouchPoints = {}; - - @override - void initState() { - super.initState(); - - _controller.initialize( - onPlatformViewCreated: (id) { - widget.onPlatformViewCreated?.call(id); - setState(() {}); - }, - arguments: widget.creationParams, - ); - - // Report initial surface size - WidgetsBinding.instance.addPostFrameCallback((_) { - _reportSurfaceSize(); - }); - - _cursorSubscription = _controller._cursor.listen((cursor) { - setState(() { - _cursor = cursor; - }); - }); - } - - @override - Widget build(BuildContext context) { - return Focus( - autofocus: true, - focusNode: _focusNode, - canRequestFocus: true, - debugLabel: "flutter_inappwebview_linux_custom_platform_view", - onFocusChange: (focused) { - // Notify the native webview when focus changes. - // This is important for proper text input handling - without this, - // clicking inside text fields requires double-click because the - // webview doesn't know it has focus. - if (_controller.value.isInitialized) { - _controller._setFocused(focused); - } - }, - onKeyEvent: _handleKeyEvent, - child: SizedBox.expand(key: _key, child: _buildInner()), - ); - } - - KeyEventResult _handleKeyEvent(FocusNode node, KeyEvent event) { - if (!_controller.value.isInitialized) { - return KeyEventResult.ignored; - } - - // Determine event type: 0=press, 1=release - int type; - if (event is KeyDownEvent) { - type = 0; - } else if (event is KeyUpEvent) { - type = 1; - } else if (event is KeyRepeatEvent) { - type = 2; // Repeat event - } else { - return KeyEventResult.ignored; - } - - // Build modifiers bitmask matching WPE's wpe_input_modifier enum: - // Control = bit 0, Shift = bit 1, Alt = bit 2, Meta = bit 3 - int modifiers = 0; - if (HardwareKeyboard.instance.isControlPressed) - modifiers |= 1; // wpe_input_keyboard_modifier_control - if (HardwareKeyboard.instance.isShiftPressed) - modifiers |= 2; // wpe_input_keyboard_modifier_shift - if (HardwareKeyboard.instance.isAltPressed) - modifiers |= 4; // wpe_input_keyboard_modifier_alt - if (HardwareKeyboard.instance.isMetaPressed) - modifiers |= 8; // wpe_input_keyboard_modifier_meta - - // For Ctrl/Meta combinations, don't send the character - final hasControlOrMeta = (modifiers & 0x9) != 0; // Ctrl=1 or Meta=8 - String? characters = hasControlOrMeta ? null : event.character; - - // Get X11 keysym for the key - final keyCode = getX11Keysym(event.logicalKey, event.character); - - // Get X11 keycode from physical key (USB HID -> evdev -> X11) - final usbHid = event.physicalKey.usbHidUsage & 0xFFFF; - final scanCode = usbHidToX11Keycode(usbHid); - - _controller._sendKeyEvent(type, keyCode, scanCode, modifiers, characters); - - return KeyEventResult.handled; - } - - Widget _buildInner() { - return NotificationListener( - onNotification: (notification) { - _reportSurfaceSize(); - return true; - }, - child: SizeChangedLayoutNotifier( - child: _controller.value.isInitialized - ? Listener( - behavior: HitTestBehavior.opaque, - onPointerHover: (ev) { - if (_pointerKind == PointerDeviceKind.touch) { - return; - } - _controller._setCursorPos(ev.localPosition); - }, - onPointerDown: (ev) async { - _reportSurfaceSize(); - - final needsFocus = !_focusNode.hasFocus; - if (needsFocus) { - // IMPORTANT: Set the native focus state BEFORE sending the click - // and AWAIT it to ensure WebKit has processed the focus change. - // Without awaiting, WebKit may receive the click before it has - // the focused activity state, causing the click to only activate - // the view rather than focusing the clicked element. - if (_controller.value.isInitialized) { - await _controller._setFocused(true); - } - _focusNode.requestFocus(); - } - - _pointerKind = ev.kind; - if (ev.kind == PointerDeviceKind.touch) { - // Handle touch event - _activeTouchPoints[ev.pointer] = ev.localPosition; - _sendTouchEvent( - 0, - ev.pointer, - ev.localPosition, - ); // 0 = down - return; - } - - // Update cursor position first - _controller._setCursorPos(ev.localPosition); - - final button = _getButton(ev.buttons); - _downButtons[ev.pointer] = button; - - // Detect double/triple click - final now = DateTime.now(); - final timeSinceLastClick = _lastClickTime != null - ? now.difference(_lastClickTime!) - : const Duration(days: 1); - final distanceFromLastClick = _lastClickPosition != null - ? (ev.localPosition - _lastClickPosition!).distance - : double.infinity; - - if (timeSinceLastClick < _doubleClickTimeout && - distanceFromLastClick < _doubleClickDistance) { - _clickCount++; - if (_clickCount > 3) _clickCount = 1; - } else { - _clickCount = 1; - } - - _lastClickTime = now; - _lastClickPosition = ev.localPosition; - - // Send click with count for double/triple click - _controller._setPointerButtonStateWithClickCount( - InAppWebViewPointerEventKind.down, - button, - _clickCount, - ); - }, - onPointerUp: (ev) { - _pointerKind = ev.kind; - if (ev.kind == PointerDeviceKind.touch) { - // Handle touch event - _activeTouchPoints[ev.pointer] = ev.localPosition; - _sendTouchEvent(1, ev.pointer, ev.localPosition); // 1 = up - _activeTouchPoints.remove(ev.pointer); - return; - } - final button = _downButtons.remove(ev.pointer); - if (button != null) { - _controller._setPointerButtonState( - InAppWebViewPointerEventKind.up, - button, - ); - } - }, - onPointerCancel: (ev) { - _pointerKind = ev.kind; - if (ev.kind == PointerDeviceKind.touch) { - // Handle touch cancel - _activeTouchPoints.remove(ev.pointer); - _sendTouchEvent( - 3, - ev.pointer, - ev.localPosition, - ); // 3 = cancel - return; - } - final button = _downButtons.remove(ev.pointer); - if (button != null) { - _controller._setPointerButtonState( - InAppWebViewPointerEventKind.cancel, - button, - ); - } - }, - onPointerMove: (ev) { - _pointerKind = ev.kind; - if (ev.kind == PointerDeviceKind.touch) { - // Handle touch move - _activeTouchPoints[ev.pointer] = ev.localPosition; - _sendTouchEvent( - 2, - ev.pointer, - ev.localPosition, - ); // 2 = move - return; - } - _controller._setCursorPos(ev.localPosition); - }, - onPointerSignal: (signal) { - if (signal is PointerScrollEvent) { - _controller._setScrollDelta( - -signal.scrollDelta.dx, - -signal.scrollDelta.dy, - ); - } - }, - onPointerPanZoomUpdate: (ev) { - _controller._setScrollDelta(ev.panDelta.dx, ev.panDelta.dy); - }, - child: MouseRegion( - cursor: _cursor, - onEnter: (ev) { - final button = _getButton(ev.buttons); - _controller._setPointerButtonState( - InAppWebViewPointerEventKind.enter, - button, - ); - }, - onExit: (ev) { - final button = _getButton(ev.buttons); - _controller._setPointerButtonState( - InAppWebViewPointerEventKind.leave, - button, - ); - }, - child: Texture( - textureId: _controller._textureId, - filterQuality: widget.filterQuality, - ), - ), - ) - : const SizedBox(), - ), - ); - } - - /// Sends a touch event to the webview with all active touch points - void _sendTouchEvent(int type, int pointerId, Offset position) { - // Build list of all active touch points for multi-touch support - final touchPoints = _activeTouchPoints.entries.map((entry) { - // Determine the type for each touch point in the event - // The main touch point uses the event type, others are motion - int pointType = entry.key == pointerId ? type : 2; // 2 = motion - return { - 'id': entry.key, - 'x': entry.value.dx, - 'y': entry.value.dy, - 'type': pointType, - }; - }).toList(); - - _controller._sendTouchEvent( - type, - pointerId, - position.dx, - position.dy, - touchPoints, - ); - } - - void _reportSurfaceSize() async { - final box = _key.currentContext?.findRenderObject() as RenderBox?; - if (box != null) { - await _controller.ready; - unawaited( - _controller._setSize( - box.size, - widget.scaleFactor ?? window.devicePixelRatio, - ), - ); - - // Also report the texture offset (position within the window) - final globalPosition = box.localToGlobal(Offset.zero); - unawaited(_controller._setTextureOffset(globalPosition)); - } - } - - @override - void dispose() { - super.dispose(); - _cursorSubscription?.cancel(); - _controller.dispose(); - _focusNode.dispose(); - } -} diff --git a/flutter_inappwebview_linux/lib/src/in_app_webview/headless_in_app_webview.dart b/flutter_inappwebview_linux/lib/src/in_app_webview/headless_in_app_webview.dart deleted file mode 100644 index f6c057a6d6..0000000000 --- a/flutter_inappwebview_linux/lib/src/in_app_webview/headless_in_app_webview.dart +++ /dev/null @@ -1,470 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import '../find_interaction/find_interaction_controller.dart'; -import '../webview_environment/webview_environment.dart'; -import 'in_app_webview_controller.dart'; - -/// Object specifying creation parameters for creating a [LinuxHeadlessInAppWebView]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformHeadlessInAppWebViewCreationParams] for -/// more information. -@immutable -class LinuxHeadlessInAppWebViewCreationParams - extends PlatformHeadlessInAppWebViewCreationParams { - /// Creates a new [LinuxHeadlessInAppWebViewCreationParams] instance. - LinuxHeadlessInAppWebViewCreationParams({ - super.controllerFromPlatform, - super.initialSize, - super.windowId, - this.webViewEnvironment, - super.onWebViewCreated, - super.onLoadStart, - super.onLoadStop, - @Deprecated('Use onReceivedError instead') super.onLoadError, - super.onReceivedError, - @Deprecated("Use onReceivedHttpError instead") super.onLoadHttpError, - super.onReceivedHttpError, - super.onProgressChanged, - super.onConsoleMessage, - super.shouldOverrideUrlLoading, - super.onLoadResource, - super.onScrollChanged, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStart, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStartRequest, - super.onDownloadStarting, - @Deprecated('Use onLoadResourceWithCustomScheme instead') - super.onLoadResourceCustomScheme, - super.onLoadResourceWithCustomScheme, - super.onCreateWindow, - super.onCloseWindow, - super.onJsAlert, - super.onJsConfirm, - super.onJsPrompt, - super.onReceivedHttpAuthRequest, - super.onReceivedServerTrustAuthRequest, - super.onReceivedClientCertRequest, - @Deprecated('Use FindInteractionController.onFindResultReceived instead') - super.onFindResultReceived, - super.shouldInterceptAjaxRequest, - super.onAjaxReadyStateChange, - super.onAjaxProgress, - super.shouldInterceptFetchRequest, - super.onUpdateVisitedHistory, - @Deprecated("Use onPrintRequest instead") super.onPrint, - super.onPrintRequest, - super.onLongPressHitTestResult, - super.onEnterFullscreen, - super.onExitFullscreen, - super.onPageCommitVisible, - super.onTitleChanged, - super.onWindowFocus, - super.onWindowBlur, - super.onOverScrolled, - super.onZoomScaleChanged, - @Deprecated('Use onSafeBrowsingHit instead') super.androidOnSafeBrowsingHit, - super.onSafeBrowsingHit, - @Deprecated('Use onPermissionRequest instead') - super.androidOnPermissionRequest, - super.onPermissionRequest, - @Deprecated('Use onGeolocationPermissionsShowPrompt instead') - super.androidOnGeolocationPermissionsShowPrompt, - super.onGeolocationPermissionsShowPrompt, - @Deprecated('Use onGeolocationPermissionsHidePrompt instead') - super.androidOnGeolocationPermissionsHidePrompt, - super.onGeolocationPermissionsHidePrompt, - @Deprecated('Use shouldInterceptRequest instead') - super.androidShouldInterceptRequest, - super.shouldInterceptRequest, - @Deprecated('Use onRenderProcessGone instead') - super.androidOnRenderProcessGone, - super.onRenderProcessGone, - @Deprecated('Use onRenderProcessResponsive instead') - super.androidOnRenderProcessResponsive, - super.onRenderProcessResponsive, - @Deprecated('Use onRenderProcessUnresponsive instead') - super.androidOnRenderProcessUnresponsive, - super.onRenderProcessUnresponsive, - @Deprecated('Use onFormResubmission instead') - super.androidOnFormResubmission, - super.onFormResubmission, - @Deprecated('Use onZoomScaleChanged instead') super.androidOnScaleChanged, - @Deprecated('Use onReceivedIcon instead') super.androidOnReceivedIcon, - super.onReceivedIcon, - @Deprecated('Use onReceivedTouchIconUrl instead') - super.androidOnReceivedTouchIconUrl, - super.onReceivedTouchIconUrl, - @Deprecated('Use onJsBeforeUnload instead') super.androidOnJsBeforeUnload, - super.onJsBeforeUnload, - @Deprecated('Use onReceivedLoginRequest instead') - super.androidOnReceivedLoginRequest, - super.onReceivedLoginRequest, - super.onPermissionRequestCanceled, - super.onRequestFocus, - @Deprecated('Use onWebContentProcessDidTerminate instead') - super.iosOnWebContentProcessDidTerminate, - super.onWebContentProcessDidTerminate, - @Deprecated( - 'Use onDidReceiveServerRedirectForProvisionalNavigation instead', - ) - super.iosOnDidReceiveServerRedirectForProvisionalNavigation, - super.onDidReceiveServerRedirectForProvisionalNavigation, - @Deprecated('Use onNavigationResponse instead') - super.iosOnNavigationResponse, - super.onNavigationResponse, - @Deprecated('Use shouldAllowDeprecatedTLS instead') - super.iosShouldAllowDeprecatedTLS, - super.shouldAllowDeprecatedTLS, - super.onCameraCaptureStateChanged, - super.onMicrophoneCaptureStateChanged, - super.onContentSizeChanged, - super.initialUrlRequest, - super.initialFile, - super.initialData, - @Deprecated('Use initialSettings instead') super.initialOptions, - super.initialSettings, - super.contextMenu, - super.initialUserScripts, - super.pullToRefreshController, - this.findInteractionController, - }); - - /// Creates a [LinuxHeadlessInAppWebViewCreationParams] instance based on [PlatformHeadlessInAppWebViewCreationParams]. - LinuxHeadlessInAppWebViewCreationParams.fromPlatformHeadlessInAppWebViewCreationParams( - PlatformHeadlessInAppWebViewCreationParams params, - ) : this( - controllerFromPlatform: params.controllerFromPlatform, - initialSize: params.initialSize, - windowId: params.windowId, - webViewEnvironment: - params.webViewEnvironment as LinuxWebViewEnvironment?, - onWebViewCreated: params.onWebViewCreated, - onLoadStart: params.onLoadStart, - onLoadStop: params.onLoadStop, - onLoadError: params.onLoadError, - onReceivedError: params.onReceivedError, - onLoadHttpError: params.onLoadHttpError, - onReceivedHttpError: params.onReceivedHttpError, - onProgressChanged: params.onProgressChanged, - onConsoleMessage: params.onConsoleMessage, - shouldOverrideUrlLoading: params.shouldOverrideUrlLoading, - onLoadResource: params.onLoadResource, - onScrollChanged: params.onScrollChanged, - onDownloadStart: params.onDownloadStart, - onDownloadStartRequest: params.onDownloadStartRequest, - onDownloadStarting: params.onDownloadStarting, - onLoadResourceCustomScheme: params.onLoadResourceCustomScheme, - onLoadResourceWithCustomScheme: params.onLoadResourceWithCustomScheme, - onCreateWindow: params.onCreateWindow, - onCloseWindow: params.onCloseWindow, - onJsAlert: params.onJsAlert, - onJsConfirm: params.onJsConfirm, - onJsPrompt: params.onJsPrompt, - onReceivedHttpAuthRequest: params.onReceivedHttpAuthRequest, - onReceivedServerTrustAuthRequest: - params.onReceivedServerTrustAuthRequest, - onReceivedClientCertRequest: params.onReceivedClientCertRequest, - onFindResultReceived: params.onFindResultReceived, - shouldInterceptAjaxRequest: params.shouldInterceptAjaxRequest, - onAjaxReadyStateChange: params.onAjaxReadyStateChange, - onAjaxProgress: params.onAjaxProgress, - shouldInterceptFetchRequest: params.shouldInterceptFetchRequest, - onUpdateVisitedHistory: params.onUpdateVisitedHistory, - onPrint: params.onPrint, - onPrintRequest: params.onPrintRequest, - onLongPressHitTestResult: params.onLongPressHitTestResult, - onEnterFullscreen: params.onEnterFullscreen, - onExitFullscreen: params.onExitFullscreen, - onPageCommitVisible: params.onPageCommitVisible, - onTitleChanged: params.onTitleChanged, - onWindowFocus: params.onWindowFocus, - onWindowBlur: params.onWindowBlur, - onOverScrolled: params.onOverScrolled, - onZoomScaleChanged: params.onZoomScaleChanged, - androidOnSafeBrowsingHit: params.androidOnSafeBrowsingHit, - onSafeBrowsingHit: params.onSafeBrowsingHit, - androidOnPermissionRequest: params.androidOnPermissionRequest, - onPermissionRequest: params.onPermissionRequest, - androidOnGeolocationPermissionsShowPrompt: - params.androidOnGeolocationPermissionsShowPrompt, - onGeolocationPermissionsShowPrompt: - params.onGeolocationPermissionsShowPrompt, - androidOnGeolocationPermissionsHidePrompt: - params.androidOnGeolocationPermissionsHidePrompt, - onGeolocationPermissionsHidePrompt: - params.onGeolocationPermissionsHidePrompt, - androidShouldInterceptRequest: params.androidShouldInterceptRequest, - shouldInterceptRequest: params.shouldInterceptRequest, - androidOnRenderProcessGone: params.androidOnRenderProcessGone, - onRenderProcessGone: params.onRenderProcessGone, - androidOnRenderProcessResponsive: - params.androidOnRenderProcessResponsive, - onRenderProcessResponsive: params.onRenderProcessResponsive, - androidOnRenderProcessUnresponsive: - params.androidOnRenderProcessUnresponsive, - onRenderProcessUnresponsive: params.onRenderProcessUnresponsive, - androidOnFormResubmission: params.androidOnFormResubmission, - onFormResubmission: params.onFormResubmission, - androidOnScaleChanged: params.androidOnScaleChanged, - androidOnReceivedIcon: params.androidOnReceivedIcon, - onReceivedIcon: params.onReceivedIcon, - androidOnReceivedTouchIconUrl: params.androidOnReceivedTouchIconUrl, - onReceivedTouchIconUrl: params.onReceivedTouchIconUrl, - androidOnJsBeforeUnload: params.androidOnJsBeforeUnload, - onJsBeforeUnload: params.onJsBeforeUnload, - androidOnReceivedLoginRequest: params.androidOnReceivedLoginRequest, - onReceivedLoginRequest: params.onReceivedLoginRequest, - onPermissionRequestCanceled: params.onPermissionRequestCanceled, - onRequestFocus: params.onRequestFocus, - iosOnWebContentProcessDidTerminate: - params.iosOnWebContentProcessDidTerminate, - onWebContentProcessDidTerminate: params.onWebContentProcessDidTerminate, - iosOnDidReceiveServerRedirectForProvisionalNavigation: - params.iosOnDidReceiveServerRedirectForProvisionalNavigation, - onDidReceiveServerRedirectForProvisionalNavigation: - params.onDidReceiveServerRedirectForProvisionalNavigation, - iosOnNavigationResponse: params.iosOnNavigationResponse, - onNavigationResponse: params.onNavigationResponse, - iosShouldAllowDeprecatedTLS: params.iosShouldAllowDeprecatedTLS, - shouldAllowDeprecatedTLS: params.shouldAllowDeprecatedTLS, - onCameraCaptureStateChanged: params.onCameraCaptureStateChanged, - onMicrophoneCaptureStateChanged: params.onMicrophoneCaptureStateChanged, - onContentSizeChanged: params.onContentSizeChanged, - initialUrlRequest: params.initialUrlRequest, - initialFile: params.initialFile, - initialData: params.initialData, - initialOptions: params.initialOptions, - initialSettings: params.initialSettings, - contextMenu: params.contextMenu, - initialUserScripts: params.initialUserScripts, - pullToRefreshController: params.pullToRefreshController, - findInteractionController: - params.findInteractionController as LinuxFindInteractionController?, - ); - - @override - final LinuxWebViewEnvironment? webViewEnvironment; - - @override - final LinuxFindInteractionController? findInteractionController; -} - -///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView} -class LinuxHeadlessInAppWebView extends PlatformHeadlessInAppWebView - with ChannelController { - @override - late final String id; - - bool _started = false; - bool _running = false; - - static const MethodChannel _sharedChannel = const MethodChannel( - 'com.pichillilorenzo/flutter_headless_inappwebview', - ); - - LinuxInAppWebViewController? _webViewController; - - /// Constructs a [LinuxHeadlessInAppWebView]. - LinuxHeadlessInAppWebView(PlatformHeadlessInAppWebViewCreationParams params) - : super.implementation( - params is LinuxHeadlessInAppWebViewCreationParams - ? params - : LinuxHeadlessInAppWebViewCreationParams.fromPlatformHeadlessInAppWebViewCreationParams( - params, - ), - ) { - id = IdGenerator.generate(); - } - - static final LinuxHeadlessInAppWebView _staticValue = - LinuxHeadlessInAppWebView(LinuxHeadlessInAppWebViewCreationParams()); - - factory LinuxHeadlessInAppWebView.static() { - return _staticValue; - } - - @override - LinuxInAppWebViewController? get webViewController => _webViewController; - - dynamic _controllerFromPlatform; - - LinuxHeadlessInAppWebViewCreationParams get _linuxParams => - params as LinuxHeadlessInAppWebViewCreationParams; - - void _init() { - _webViewController = LinuxInAppWebViewController( - LinuxInAppWebViewControllerCreationParams(id: id, webviewParams: params), - ); - _controllerFromPlatform = - params.controllerFromPlatform?.call(_webViewController!) ?? - _webViewController!; - // Initialize the find interaction controller with the same ID - _linuxParams.findInteractionController?.init(id); - channel = MethodChannel( - 'com.pichillilorenzo/flutter_headless_inappwebview_$id', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onWebViewCreated": - if (params.onWebViewCreated != null && _webViewController != null) { - params.onWebViewCreated!(_controllerFromPlatform); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - Future run() async { - if (_started) { - return; - } - _started = true; - _init(); - - final initialSettings = params.initialSettings ?? InAppWebViewSettings(); - _inferInitialSettings(initialSettings); - - Map settingsMap = - (params.initialSettings != null ? initialSettings.toMap() : null) ?? - // ignore: deprecated_member_use_from_same_package - params.initialOptions?.toMap() ?? - initialSettings.toMap(); - - Map args = {}; - args.putIfAbsent('id', () => id); - args.putIfAbsent( - 'params', - () => { - 'initialUrlRequest': params.initialUrlRequest?.toMap(), - 'initialFile': params.initialFile, - 'initialData': params.initialData?.toMap(), - 'initialSettings': settingsMap, - 'contextMenu': params.contextMenu?.toMap() ?? {}, - 'windowId': params.windowId, - 'initialUserScripts': - params.initialUserScripts?.map((e) => e.toMap()).toList() ?? [], - 'initialSize': params.initialSize.toMap(), - 'webViewEnvironmentId': params.webViewEnvironment?.id, - }, - ); - try { - await _sharedChannel.invokeMethod('run', args); - _running = true; - } catch (e) { - _running = false; - _started = false; - rethrow; - } - } - - void _inferInitialSettings(InAppWebViewSettings settings) { - if (params.shouldOverrideUrlLoading != null && - settings.useShouldOverrideUrlLoading == null) { - settings.useShouldOverrideUrlLoading = true; - } - if (params.onLoadResource != null && settings.useOnLoadResource == null) { - settings.useOnLoadResource = true; - } - if ((params.onDownloadStartRequest != null || - params.onDownloadStarting != null) && - settings.useOnDownloadStart == null) { - settings.useOnDownloadStart = true; - } - if ((params.shouldInterceptAjaxRequest != null || - params.onAjaxProgress != null || - params.onAjaxReadyStateChange != null)) { - if (settings.useShouldInterceptAjaxRequest == null) { - settings.useShouldInterceptAjaxRequest = true; - } - if (params.onAjaxReadyStateChange != null && - settings.useOnAjaxReadyStateChange == null) { - settings.useOnAjaxReadyStateChange = true; - } - if (params.onAjaxProgress != null && settings.useOnAjaxProgress == null) { - settings.useOnAjaxProgress = true; - } - } - if (params.shouldInterceptFetchRequest != null && - settings.useShouldInterceptFetchRequest == null) { - settings.useShouldInterceptFetchRequest = true; - } - if (params.shouldInterceptRequest != null && - settings.useShouldInterceptRequest == null) { - settings.useShouldInterceptRequest = true; - } - if (params.onRenderProcessGone != null && - settings.useOnRenderProcessGone == null) { - settings.useOnRenderProcessGone = true; - } - if (params.onNavigationResponse != null && - settings.useOnNavigationResponse == null) { - settings.useOnNavigationResponse = true; - } - } - - @override - bool isRunning() { - return _running; - } - - @override - Future setSize(Size size) async { - if (!_running) { - return; - } - - Map args = {}; - args.putIfAbsent('size', () => size.toMap()); - await channel?.invokeMethod('setSize', args); - } - - @override - Future getSize() async { - if (!_running) { - return null; - } - - Map args = {}; - Map? sizeMap = (await channel?.invokeMethod( - 'getSize', - args, - ))?.cast(); - if (sizeMap == null) { - return null; - } - return MapSize.fromMap(sizeMap); - } - - @override - Future dispose() async { - if (!_running) { - return; - } - Map args = {}; - await channel?.invokeMethod('dispose', args); - disposeChannel(); - _started = false; - _running = false; - _webViewController?.dispose(); - _webViewController = null; - _controllerFromPlatform = null; - _linuxParams.findInteractionController?.dispose(); - } -} - -extension InternalHeadlessInAppWebView on LinuxHeadlessInAppWebView { - Future internalDispose() async { - _started = false; - _running = false; - } -} diff --git a/flutter_inappwebview_linux/lib/src/in_app_webview/in_app_webview.dart b/flutter_inappwebview_linux/lib/src/in_app_webview/in_app_webview.dart deleted file mode 100644 index bd8bfa415b..0000000000 --- a/flutter_inappwebview_linux/lib/src/in_app_webview/in_app_webview.dart +++ /dev/null @@ -1,370 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../find_interaction/find_interaction_controller.dart'; -import '../webview_environment/webview_environment.dart'; -import 'in_app_webview_controller.dart'; -import 'custom_platform_view.dart'; - -/// Object specifying creation parameters for creating a [PlatformInAppWebViewWidget]. -/// -/// Platform specific implementations can add additional fields by extending -/// this class. -class LinuxInAppWebViewWidgetCreationParams - extends PlatformInAppWebViewWidgetCreationParams { - LinuxInAppWebViewWidgetCreationParams({ - super.controllerFromPlatform, - super.key, - super.layoutDirection, - super.gestureRecognizers, - super.headlessWebView, - super.keepAlive, - super.preventGestureDelay, - super.windowId, - this.webViewEnvironment, - super.onWebViewCreated, - super.onLoadStart, - super.onLoadStop, - @Deprecated('Use onReceivedError instead') super.onLoadError, - super.onReceivedError, - @Deprecated("Use onReceivedHttpError instead") super.onLoadHttpError, - super.onReceivedHttpError, - super.onProgressChanged, - super.onConsoleMessage, - super.shouldOverrideUrlLoading, - super.onLoadResource, - super.onScrollChanged, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStart, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStartRequest, - super.onDownloadStarting, - @Deprecated('Use onLoadResourceWithCustomScheme instead') - super.onLoadResourceCustomScheme, - super.onLoadResourceWithCustomScheme, - super.onCreateWindow, - super.onCloseWindow, - super.onJsAlert, - super.onJsConfirm, - super.onJsPrompt, - super.onReceivedHttpAuthRequest, - super.onReceivedServerTrustAuthRequest, - super.onReceivedClientCertRequest, - @Deprecated('Use FindInteractionController.onFindResultReceived instead') - super.onFindResultReceived, - super.shouldInterceptAjaxRequest, - super.onAjaxReadyStateChange, - super.onAjaxProgress, - super.shouldInterceptFetchRequest, - super.onUpdateVisitedHistory, - @Deprecated("Use onPrintRequest instead") super.onPrint, - super.onPrintRequest, - super.onLongPressHitTestResult, - super.onEnterFullscreen, - super.onExitFullscreen, - super.onPageCommitVisible, - super.onTitleChanged, - super.onWindowFocus, - super.onWindowBlur, - super.onOverScrolled, - super.onZoomScaleChanged, - super.onSafeBrowsingHit, - super.onPermissionRequest, - super.onGeolocationPermissionsShowPrompt, - super.onGeolocationPermissionsHidePrompt, - super.shouldInterceptRequest, - super.onRenderProcessGone, - super.onRenderProcessResponsive, - super.onRenderProcessUnresponsive, - super.onFormResubmission, - super.onReceivedIcon, - super.onReceivedTouchIconUrl, - super.onJsBeforeUnload, - super.onReceivedLoginRequest, - super.onPermissionRequestCanceled, - super.onRequestFocus, - super.onWebContentProcessDidTerminate, - super.onDidReceiveServerRedirectForProvisionalNavigation, - super.onNavigationResponse, - super.shouldAllowDeprecatedTLS, - super.onCameraCaptureStateChanged, - super.onMicrophoneCaptureStateChanged, - super.onContentSizeChanged, - super.initialUrlRequest, - super.initialFile, - super.initialData, - @Deprecated('Use initialSettings instead') super.initialOptions, - super.initialSettings, - super.contextMenu, - super.initialUserScripts, - super.pullToRefreshController, - super.findInteractionController, - }); - - /// Constructs a [LinuxInAppWebViewWidgetCreationParams] using a - /// [PlatformInAppWebViewWidgetCreationParams]. - LinuxInAppWebViewWidgetCreationParams.fromPlatformInAppWebViewWidgetCreationParams( - PlatformInAppWebViewWidgetCreationParams params, - ) : this( - controllerFromPlatform: params.controllerFromPlatform, - key: params.key, - layoutDirection: params.layoutDirection, - gestureRecognizers: params.gestureRecognizers, - headlessWebView: params.headlessWebView, - keepAlive: params.keepAlive, - preventGestureDelay: params.preventGestureDelay, - windowId: params.windowId, - webViewEnvironment: - params.webViewEnvironment as LinuxWebViewEnvironment?, - onWebViewCreated: params.onWebViewCreated, - onLoadStart: params.onLoadStart, - onLoadStop: params.onLoadStop, - onLoadError: params.onLoadError, - onReceivedError: params.onReceivedError, - onLoadHttpError: params.onLoadHttpError, - onReceivedHttpError: params.onReceivedHttpError, - onProgressChanged: params.onProgressChanged, - onConsoleMessage: params.onConsoleMessage, - shouldOverrideUrlLoading: params.shouldOverrideUrlLoading, - onLoadResource: params.onLoadResource, - onScrollChanged: params.onScrollChanged, - onDownloadStart: params.onDownloadStart, - onDownloadStartRequest: params.onDownloadStartRequest, - onDownloadStarting: params.onDownloadStarting, - onLoadResourceCustomScheme: params.onLoadResourceCustomScheme, - onLoadResourceWithCustomScheme: params.onLoadResourceWithCustomScheme, - onCreateWindow: params.onCreateWindow, - onCloseWindow: params.onCloseWindow, - onJsAlert: params.onJsAlert, - onJsConfirm: params.onJsConfirm, - onJsPrompt: params.onJsPrompt, - onReceivedHttpAuthRequest: params.onReceivedHttpAuthRequest, - onReceivedServerTrustAuthRequest: - params.onReceivedServerTrustAuthRequest, - onReceivedClientCertRequest: params.onReceivedClientCertRequest, - onFindResultReceived: params.onFindResultReceived, - shouldInterceptAjaxRequest: params.shouldInterceptAjaxRequest, - onAjaxReadyStateChange: params.onAjaxReadyStateChange, - onAjaxProgress: params.onAjaxProgress, - shouldInterceptFetchRequest: params.shouldInterceptFetchRequest, - onUpdateVisitedHistory: params.onUpdateVisitedHistory, - onPrint: params.onPrint, - onPrintRequest: params.onPrintRequest, - onLongPressHitTestResult: params.onLongPressHitTestResult, - onEnterFullscreen: params.onEnterFullscreen, - onExitFullscreen: params.onExitFullscreen, - onPageCommitVisible: params.onPageCommitVisible, - onTitleChanged: params.onTitleChanged, - onWindowFocus: params.onWindowFocus, - onWindowBlur: params.onWindowBlur, - onOverScrolled: params.onOverScrolled, - onZoomScaleChanged: params.onZoomScaleChanged, - onSafeBrowsingHit: params.onSafeBrowsingHit, - onPermissionRequest: params.onPermissionRequest, - onGeolocationPermissionsShowPrompt: - params.onGeolocationPermissionsShowPrompt, - onGeolocationPermissionsHidePrompt: - params.onGeolocationPermissionsHidePrompt, - shouldInterceptRequest: params.shouldInterceptRequest, - onRenderProcessGone: params.onRenderProcessGone, - onRenderProcessResponsive: params.onRenderProcessResponsive, - onRenderProcessUnresponsive: params.onRenderProcessUnresponsive, - onFormResubmission: params.onFormResubmission, - onReceivedIcon: params.onReceivedIcon, - onReceivedTouchIconUrl: params.onReceivedTouchIconUrl, - onJsBeforeUnload: params.onJsBeforeUnload, - onReceivedLoginRequest: params.onReceivedLoginRequest, - onPermissionRequestCanceled: params.onPermissionRequestCanceled, - onRequestFocus: params.onRequestFocus, - onWebContentProcessDidTerminate: params.onWebContentProcessDidTerminate, - onDidReceiveServerRedirectForProvisionalNavigation: - params.onDidReceiveServerRedirectForProvisionalNavigation, - onNavigationResponse: params.onNavigationResponse, - shouldAllowDeprecatedTLS: params.shouldAllowDeprecatedTLS, - onCameraCaptureStateChanged: params.onCameraCaptureStateChanged, - onMicrophoneCaptureStateChanged: params.onMicrophoneCaptureStateChanged, - onContentSizeChanged: params.onContentSizeChanged, - initialUrlRequest: params.initialUrlRequest, - initialFile: params.initialFile, - initialData: params.initialData, - initialOptions: params.initialOptions, - initialSettings: params.initialSettings, - contextMenu: params.contextMenu, - initialUserScripts: params.initialUserScripts, - pullToRefreshController: params.pullToRefreshController, - findInteractionController: params.findInteractionController, - ); - - @override - final LinuxWebViewEnvironment? webViewEnvironment; -} - -///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewWidget} -class LinuxInAppWebViewWidget extends PlatformInAppWebViewWidget { - /// Constructs a [LinuxInAppWebViewWidget]. - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewWidget} - LinuxInAppWebViewWidget(PlatformInAppWebViewWidgetCreationParams params) - : super.implementation( - params is LinuxInAppWebViewWidgetCreationParams - ? params - : LinuxInAppWebViewWidgetCreationParams.fromPlatformInAppWebViewWidgetCreationParams( - params, - ), - ); - - LinuxInAppWebViewWidgetCreationParams get _linuxParams => - params as LinuxInAppWebViewWidgetCreationParams; - - LinuxInAppWebViewController? _controller; - - static final LinuxInAppWebViewWidget _staticValue = LinuxInAppWebViewWidget( - LinuxInAppWebViewWidgetCreationParams(), - ); - - factory LinuxInAppWebViewWidget.static() { - return _staticValue; - } - - @override - Widget build(BuildContext context) { - final initialSettings = params.initialSettings ?? InAppWebViewSettings(); - _inferInitialSettings(initialSettings); - - Map settingsMap = - (params.initialSettings != null ? initialSettings.toMap() : null) ?? - // ignore: deprecated_member_use_from_same_package - params.initialOptions?.toMap() ?? - initialSettings.toMap(); - - if ((params.headlessWebView?.isRunning() ?? false) && - params.keepAlive != null) { - final headlessId = params.headlessWebView?.id; - if (headlessId != null) { - // force keep alive id to match headless webview id - params.keepAlive?.id = headlessId; - } - } - - return CustomPlatformView( - onPlatformViewCreated: _onPlatformViewCreated, - creationParams: { - 'initialUrlRequest': params.initialUrlRequest?.toMap(), - 'initialFile': params.initialFile, - 'initialData': params.initialData?.toMap(), - 'initialSettings': settingsMap, - 'contextMenu': params.contextMenu?.toMap() ?? {}, - 'windowId': params.windowId, - 'headlessWebViewId': params.headlessWebView?.isRunning() ?? false - ? params.headlessWebView?.id - : null, - 'initialUserScripts': - params.initialUserScripts?.map((e) => e.toMap()).toList() ?? [], - 'keepAliveId': params.keepAlive?.id, - 'webViewEnvironmentId': params.webViewEnvironment?.id, - }, - ); - } - - void _onPlatformViewCreated(int id) { - dynamic viewId = id; - if (params.headlessWebView?.isRunning() ?? false) { - viewId = params.headlessWebView?.id; - } - viewId = params.keepAlive?.id ?? viewId ?? id; - - _controller = LinuxInAppWebViewController( - PlatformInAppWebViewControllerCreationParams( - id: viewId, - webviewParams: params, - ), - ); - - // Initialize the find interaction controller with the same view ID - if (_linuxParams.findInteractionController != null) { - var findInteractionController = - _linuxParams.findInteractionController - as LinuxFindInteractionController; - findInteractionController.init(viewId); - } - - debugLog( - className: runtimeType.toString(), - id: viewId?.toString(), - debugLoggingSettings: PlatformInAppWebViewController.debugLoggingSettings, - method: "onWebViewCreated", - args: [], - ); - if (params.onWebViewCreated != null) { - params.onWebViewCreated!( - params.controllerFromPlatform?.call(_controller!) ?? _controller!, - ); - } - } - - void _inferInitialSettings(InAppWebViewSettings settings) { - if (params.shouldOverrideUrlLoading != null && - settings.useShouldOverrideUrlLoading == null) { - settings.useShouldOverrideUrlLoading = true; - } - if (params.onLoadResource != null && settings.useOnLoadResource == null) { - settings.useOnLoadResource = true; - } - if ((params.onDownloadStartRequest != null || - params.onDownloadStarting != null) && - settings.useOnDownloadStart == null) { - settings.useOnDownloadStart = true; - } - if ((params.shouldInterceptAjaxRequest != null || - params.onAjaxProgress != null || - params.onAjaxReadyStateChange != null)) { - if (settings.useShouldInterceptAjaxRequest == null) { - settings.useShouldInterceptAjaxRequest = true; - } - if (params.onAjaxReadyStateChange != null && - settings.useOnAjaxReadyStateChange == null) { - settings.useOnAjaxReadyStateChange = true; - } - if (params.onAjaxProgress != null && settings.useOnAjaxProgress == null) { - settings.useOnAjaxProgress = true; - } - } - if (params.shouldInterceptFetchRequest != null && - settings.useShouldInterceptFetchRequest == null) { - settings.useShouldInterceptFetchRequest = true; - } - if (params.shouldInterceptRequest != null && - settings.useShouldInterceptRequest == null) { - settings.useShouldInterceptRequest = true; - } - if (params.onRenderProcessGone != null && - settings.useOnRenderProcessGone == null) { - settings.useOnRenderProcessGone = true; - } - if (params.onNavigationResponse != null && - settings.useOnNavigationResponse == null) { - settings.useOnNavigationResponse = true; - } - } - - @override - void dispose() { - dynamic viewId = _controller?.id; - debugLog( - className: runtimeType.toString(), - id: viewId?.toString(), - debugLoggingSettings: PlatformInAppWebViewController.debugLoggingSettings, - method: "dispose", - args: [], - ); - final isKeepAlive = params.keepAlive != null; - _controller?.dispose(isKeepAlive: isKeepAlive); - _controller = null; - params.findInteractionController?.dispose(isKeepAlive: isKeepAlive); - } - - @override - T controllerFromPlatform(PlatformInAppWebViewController controller) { - // unused - throw UnimplementedError(); - } -} diff --git a/flutter_inappwebview_linux/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_linux/lib/src/in_app_webview/in_app_webview_controller.dart deleted file mode 100644 index b4f5408839..0000000000 --- a/flutter_inappwebview_linux/lib/src/in_app_webview/in_app_webview_controller.dart +++ /dev/null @@ -1,2362 +0,0 @@ -import 'dart:collection'; -import 'dart:convert'; -import 'dart:core'; -import 'dart:io'; -import 'dart:typed_data'; -import 'dart:developer' as developer; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../in_app_browser/in_app_browser.dart'; -import '../web_message/web_message_channel.dart'; -import '../web_message/web_message_listener.dart'; -import '../web_storage/web_storage.dart'; -import '_static_channel.dart'; - -/// Object specifying creation parameters for creating a [LinuxInAppWebViewController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformInAppWebViewControllerCreationParams] for -/// more information. -@immutable -class LinuxInAppWebViewControllerCreationParams - extends PlatformInAppWebViewControllerCreationParams { - /// Creates a new [LinuxInAppWebViewControllerCreationParams] instance. - const LinuxInAppWebViewControllerCreationParams({ - required super.id, - super.webviewParams, - }); - - /// Creates a [LinuxInAppWebViewControllerCreationParams] instance based on [PlatformInAppWebViewControllerCreationParams]. - factory LinuxInAppWebViewControllerCreationParams.fromPlatformInAppWebViewControllerCreationParams( - PlatformInAppWebViewControllerCreationParams params, - ) { - return LinuxInAppWebViewControllerCreationParams( - id: params.id, - webviewParams: params.webviewParams, - ); - } -} - -/// Controls a WebView, such as an [InAppWebView] widget instance. -/// -/// If you are using the [InAppWebView] widget, an [InAppWebViewController] instance -/// can be obtained by setting the [InAppWebView.onWebViewCreated] callback. -class LinuxInAppWebViewController extends PlatformInAppWebViewController - with ChannelController { - static final MethodChannel _staticChannel = IN_APP_WEBVIEW_STATIC_CHANNEL; - - // List of properties to be saved and restored for keep alive feature - Map _javaScriptHandlersMap = HashMap(); - Map> _userScripts = { - UserScriptInjectionTime.AT_DOCUMENT_START: [], - UserScriptInjectionTime.AT_DOCUMENT_END: [], - }; - Set _webMessageListeners = Set(); - Set _webMessageListenerObjNames = Set(); - Set _webMessageChannels = Set(); - Map _injectedScriptsFromURL = {}; - - // static map that contains the properties to be saved and restored for keep alive feature - static final Map - _keepAliveMap = {}; - - LinuxInAppBrowser? _inAppBrowser; - - PlatformInAppBrowserEvents? get _inAppBrowserEventHandler => - _inAppBrowser?.eventHandler; - - dynamic _controllerFromPlatform; - - @override - late LinuxWebStorage webStorage; - - LinuxInAppWebViewController( - PlatformInAppWebViewControllerCreationParams params, - ) : super.implementation( - params is LinuxInAppWebViewControllerCreationParams - ? params - : LinuxInAppWebViewControllerCreationParams.fromPlatformInAppWebViewControllerCreationParams( - params, - ), - ) { - channel = MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id'); - handler = _handleMethod; - initMethodCallHandler(); - - final initialUserScripts = webviewParams?.initialUserScripts; - if (initialUserScripts != null) { - for (final userScript in initialUserScripts) { - if (userScript.injectionTime == - UserScriptInjectionTime.AT_DOCUMENT_START) { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.add( - userScript, - ); - } else { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.add( - userScript, - ); - } - } - } - - this._init(params); - } - - static final LinuxInAppWebViewController _staticValue = - LinuxInAppWebViewController( - LinuxInAppWebViewControllerCreationParams(id: null), - ); - - factory LinuxInAppWebViewController.static() { - return _staticValue; - } - - LinuxInAppWebViewController.fromInAppBrowser( - PlatformInAppWebViewControllerCreationParams params, - MethodChannel channel, - LinuxInAppBrowser inAppBrowser, - UnmodifiableListView? initialUserScripts, - ) : super.implementation( - params is LinuxInAppWebViewControllerCreationParams - ? params - : LinuxInAppWebViewControllerCreationParams.fromPlatformInAppWebViewControllerCreationParams( - params, - ), - ) { - this.channel = channel; - this._inAppBrowser = inAppBrowser; - - if (initialUserScripts != null) { - for (final userScript in initialUserScripts) { - if (userScript.injectionTime == - UserScriptInjectionTime.AT_DOCUMENT_START) { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.add( - userScript, - ); - } else { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.add( - userScript, - ); - } - } - } - this._init(params); - } - - void _init(PlatformInAppWebViewControllerCreationParams params) { - _controllerFromPlatform = - params.webviewParams?.controllerFromPlatform?.call(this) ?? this; - - webStorage = LinuxWebStorage( - LinuxWebStorageCreationParams( - localStorage: LinuxLocalStorage.defaultStorage(controller: this), - sessionStorage: LinuxSessionStorage.defaultStorage(controller: this), - ), - ); - - if (params.webviewParams is PlatformInAppWebViewWidgetCreationParams) { - final keepAlive = - (params.webviewParams as PlatformInAppWebViewWidgetCreationParams) - .keepAlive; - if (keepAlive != null) { - InAppWebViewControllerKeepAliveProps? props = _keepAliveMap[keepAlive]; - if (props == null) { - // save controller properties to restore it later - _keepAliveMap[keepAlive] = InAppWebViewControllerKeepAliveProps( - injectedScriptsFromURL: _injectedScriptsFromURL, - javaScriptHandlersMap: _javaScriptHandlersMap, - userScripts: _userScripts, - webMessageListenerObjNames: _webMessageListenerObjNames, - ); - } else { - // restore controller properties - _injectedScriptsFromURL = props.injectedScriptsFromURL; - _javaScriptHandlersMap = props.javaScriptHandlersMap; - _userScripts = props.userScripts; - _webMessageListenerObjNames = props.webMessageListenerObjNames; - } - } - } - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - name: _inAppBrowser == null - ? "WebView" - : _inAppBrowser.runtimeType.toString(), - id: (getViewId() ?? _inAppBrowser?.id).toString(), - debugLoggingSettings: PlatformInAppWebViewController.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - if (PlatformInAppWebViewController.debugLoggingSettings.enabled && - call.method != "onCallJsHandler") { - _debugLog(call.method, call.arguments); - } - - switch (call.method) { - case "onLoadStart": - _injectedScriptsFromURL.clear(); - if ((webviewParams != null && webviewParams!.onLoadStart != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - if (webviewParams != null && webviewParams!.onLoadStart != null) - webviewParams!.onLoadStart!(_controllerFromPlatform, uri); - else - _inAppBrowserEventHandler!.onLoadStart(uri); - } - break; - case "onLoadStop": - if ((webviewParams != null && webviewParams!.onLoadStop != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - if (webviewParams != null && webviewParams!.onLoadStop != null) - webviewParams!.onLoadStop!(_controllerFromPlatform, uri); - else - _inAppBrowserEventHandler!.onLoadStop(uri); - } - break; - case "shouldOverrideUrlLoading": - if ((webviewParams != null && - webviewParams!.shouldOverrideUrlLoading != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - NavigationAction navigationAction = NavigationAction.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.shouldOverrideUrlLoading != null) - return (await webviewParams!.shouldOverrideUrlLoading!( - _controllerFromPlatform, - navigationAction, - ))?.toNativeValue(); - return (await _inAppBrowserEventHandler!.shouldOverrideUrlLoading( - navigationAction, - ))?.toNativeValue(); - } - break; - case "onProgressChanged": - if ((webviewParams != null && - webviewParams!.onProgressChanged != null) || - _inAppBrowserEventHandler != null) { - int progress = call.arguments["progress"]; - if (webviewParams != null && webviewParams!.onProgressChanged != null) - webviewParams!.onProgressChanged!( - _controllerFromPlatform, - progress, - ); - else - _inAppBrowserEventHandler!.onProgressChanged(progress); - } - break; - case "onConsoleMessage": - if ((webviewParams != null && - webviewParams!.onConsoleMessage != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - ConsoleMessage consoleMessage = ConsoleMessage.fromMap(arguments)!; - if (webviewParams != null && webviewParams!.onConsoleMessage != null) - webviewParams!.onConsoleMessage!( - _controllerFromPlatform, - consoleMessage, - ); - else - _inAppBrowserEventHandler!.onConsoleMessage(consoleMessage); - } - break; - case "onLoadResource": - if ((webviewParams != null && webviewParams!.onLoadResource != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - LoadedResource resource = LoadedResource.fromMap(arguments)!; - if (webviewParams != null && webviewParams!.onLoadResource != null) - webviewParams!.onLoadResource!(_controllerFromPlatform, resource); - else - _inAppBrowserEventHandler!.onLoadResource(resource); - } - break; - case "onTitleChanged": - if ((webviewParams != null && webviewParams!.onTitleChanged != null) || - _inAppBrowserEventHandler != null) { - String? title = call.arguments["title"]; - if (webviewParams != null && webviewParams!.onTitleChanged != null) - webviewParams!.onTitleChanged!(_controllerFromPlatform, title); - else - _inAppBrowserEventHandler!.onTitleChanged(title); - } - break; - case "onUpdateVisitedHistory": - if ((webviewParams != null && - webviewParams!.onUpdateVisitedHistory != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - bool? isReload = call.arguments["isReload"]; - if (webviewParams != null && - webviewParams!.onUpdateVisitedHistory != null) - webviewParams!.onUpdateVisitedHistory!( - _controllerFromPlatform, - uri, - isReload, - ); - else - _inAppBrowserEventHandler!.onUpdateVisitedHistory(uri, isReload); - } - break; - case "onReceivedError": - if ((webviewParams != null && - (webviewParams!.onReceivedError != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadError != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - WebResourceRequest request = WebResourceRequest.fromMap( - arguments["request"]?.cast(), - )!; - WebResourceError error = WebResourceError.fromMap( - arguments["error"]?.cast(), - )!; - var isForMainFrame = request.isForMainFrame ?? false; - - if (webviewParams != null) { - if (webviewParams!.onReceivedError != null) - webviewParams!.onReceivedError!( - _controllerFromPlatform, - request, - error, - ); - else if (isForMainFrame) { - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadError!( - _controllerFromPlatform, - request.url, - error.type.toNativeValue() ?? -1, - error.description, - ); - } - } else { - if (isForMainFrame) { - _inAppBrowserEventHandler!.onLoadError( - request.url, - error.type.toNativeValue() ?? -1, - error.description, - ); - } - _inAppBrowserEventHandler!.onReceivedError(request, error); - } - } - break; - case "onReceivedHttpError": - if ((webviewParams != null && - (webviewParams!.onReceivedHttpError != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadHttpError != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - WebResourceRequest request = WebResourceRequest.fromMap( - arguments["request"]?.cast(), - )!; - WebResourceResponse errorResponse = WebResourceResponse.fromMap( - arguments["errorResponse"]?.cast(), - )!; - var isForMainFrame = request.isForMainFrame ?? false; - - if (webviewParams != null) { - if (webviewParams!.onReceivedHttpError != null) - webviewParams!.onReceivedHttpError!( - _controllerFromPlatform, - request, - errorResponse, - ); - else if (isForMainFrame) { - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadHttpError!( - _controllerFromPlatform, - request.url, - errorResponse.statusCode ?? -1, - errorResponse.reasonPhrase ?? '', - ); - } - } else { - if (isForMainFrame) { - _inAppBrowserEventHandler!.onLoadHttpError( - request.url, - errorResponse.statusCode ?? -1, - errorResponse.reasonPhrase ?? '', - ); - } - _inAppBrowserEventHandler!.onReceivedHttpError( - request, - errorResponse, - ); - } - } - break; - case "onPageCommitVisible": - if ((webviewParams != null && - webviewParams!.onPageCommitVisible != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - if (webviewParams != null && - webviewParams!.onPageCommitVisible != null) - webviewParams!.onPageCommitVisible!(_controllerFromPlatform, uri); - else - _inAppBrowserEventHandler!.onPageCommitVisible(uri); - } - break; - case "onZoomScaleChanged": - if ((webviewParams != null && - webviewParams!.onZoomScaleChanged != null) || - _inAppBrowserEventHandler != null) { - double oldScale = call.arguments["oldScale"]; - double newScale = call.arguments["newScale"]; - if (webviewParams != null && - webviewParams!.onZoomScaleChanged != null) - webviewParams!.onZoomScaleChanged!( - _controllerFromPlatform, - oldScale, - newScale, - ); - else - _inAppBrowserEventHandler!.onZoomScaleChanged(oldScale, newScale); - } - break; - case "onScrollChanged": - if ((webviewParams != null && webviewParams!.onScrollChanged != null) || - _inAppBrowserEventHandler != null) { - int x = call.arguments["x"]; - int y = call.arguments["y"]; - if (webviewParams != null && webviewParams!.onScrollChanged != null) - webviewParams!.onScrollChanged!(_controllerFromPlatform, x, y); - else - _inAppBrowserEventHandler!.onScrollChanged(x, y); - } - break; - case "onCloseWindow": - if (webviewParams != null && webviewParams!.onCloseWindow != null) - webviewParams!.onCloseWindow!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onCloseWindow(); - break; - case "onCreateWindow": - if ((webviewParams != null && webviewParams!.onCreateWindow != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - CreateWindowAction createWindowAction = CreateWindowAction.fromMap( - arguments, - )!; - - if (webviewParams != null && webviewParams!.onCreateWindow != null) - return await webviewParams!.onCreateWindow!( - _controllerFromPlatform, - createWindowAction, - ); - else - return await _inAppBrowserEventHandler!.onCreateWindow( - createWindowAction, - ); - } - return false; - case "onJsAlert": - if ((webviewParams != null && webviewParams!.onJsAlert != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsAlertRequest jsAlertRequest = JsAlertRequest.fromMap(arguments)!; - - if (webviewParams != null && webviewParams!.onJsAlert != null) - return (await webviewParams!.onJsAlert!( - _controllerFromPlatform, - jsAlertRequest, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onJsAlert( - jsAlertRequest, - ))?.toMap(); - } - return null; - case "onJsConfirm": - if ((webviewParams != null && webviewParams!.onJsConfirm != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsConfirmRequest jsConfirmRequest = JsConfirmRequest.fromMap( - arguments, - )!; - - if (webviewParams != null && webviewParams!.onJsConfirm != null) - return (await webviewParams!.onJsConfirm!( - _controllerFromPlatform, - jsConfirmRequest, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onJsConfirm( - jsConfirmRequest, - ))?.toMap(); - } - return null; - case "onJsPrompt": - if ((webviewParams != null && webviewParams!.onJsPrompt != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsPromptRequest jsPromptRequest = JsPromptRequest.fromMap(arguments)!; - - if (webviewParams != null && webviewParams!.onJsPrompt != null) - return (await webviewParams!.onJsPrompt!( - _controllerFromPlatform, - jsPromptRequest, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onJsPrompt( - jsPromptRequest, - ))?.toMap(); - } - return null; - case "onJsBeforeUnload": - if ((webviewParams != null && - webviewParams!.onJsBeforeUnload != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsBeforeUnloadRequest jsBeforeUnloadRequest = - JsBeforeUnloadRequest.fromMap(arguments)!; - - if (webviewParams != null && webviewParams!.onJsBeforeUnload != null) - return (await webviewParams!.onJsBeforeUnload!( - _controllerFromPlatform, - jsBeforeUnloadRequest, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onJsBeforeUnload( - jsBeforeUnloadRequest, - ))?.toMap(); - } - return null; - case "onPermissionRequest": - if ((webviewParams != null && - webviewParams!.onPermissionRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - PermissionRequest permissionRequest = PermissionRequest.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.onPermissionRequest != null) - return (await webviewParams!.onPermissionRequest!( - _controllerFromPlatform, - permissionRequest, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onPermissionRequest( - permissionRequest, - ))?.toMap(); - } - return null; - case "onReceivedHttpAuthRequest": - if ((webviewParams != null && - webviewParams!.onReceivedHttpAuthRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - HttpAuthenticationChallenge challenge = - HttpAuthenticationChallenge.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onReceivedHttpAuthRequest != null) - return (await webviewParams!.onReceivedHttpAuthRequest!( - _controllerFromPlatform, - challenge, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onReceivedHttpAuthRequest( - challenge, - ))?.toMap(); - } - return null; - case "onReceivedServerTrustAuthRequest": - if ((webviewParams != null && - webviewParams!.onReceivedServerTrustAuthRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - ServerTrustChallenge challenge = ServerTrustChallenge.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.onReceivedServerTrustAuthRequest != null) - return (await webviewParams!.onReceivedServerTrustAuthRequest!( - _controllerFromPlatform, - challenge, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler! - .onReceivedServerTrustAuthRequest(challenge)) - ?.toMap(); - } - return null; - case "onReceivedClientCertRequest": - if ((webviewParams != null && - webviewParams!.onReceivedClientCertRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - ClientCertChallenge challenge = ClientCertChallenge.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.onReceivedClientCertRequest != null) - return (await webviewParams!.onReceivedClientCertRequest!( - _controllerFromPlatform, - challenge, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler! - .onReceivedClientCertRequest(challenge)) - ?.toMap(); - } - return null; - case "onDownloadStarting": - if ((webviewParams != null && - (webviewParams!.onDownloadStart != null || - webviewParams!.onDownloadStartRequest != null || - webviewParams!.onDownloadStarting != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - DownloadStartRequest downloadStartRequest = - DownloadStartRequest.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.onDownloadStarting != null) - return (await webviewParams!.onDownloadStarting!( - _controllerFromPlatform, - downloadStartRequest, - ))?.toMap(); - else if (webviewParams!.onDownloadStartRequest != null) - webviewParams!.onDownloadStartRequest!( - _controllerFromPlatform, - downloadStartRequest, - ); - else { - webviewParams!.onDownloadStart!( - _controllerFromPlatform, - downloadStartRequest.url, - ); - } - } else { - _inAppBrowserEventHandler!.onDownloadStart( - downloadStartRequest.url, - ); - _inAppBrowserEventHandler!.onDownloadStartRequest( - downloadStartRequest, - ); - return (await _inAppBrowserEventHandler!.onDownloadStarting( - downloadStartRequest, - ))?.toMap(); - } - } - return null; - case "onEnterFullscreen": - if (webviewParams != null && webviewParams!.onEnterFullscreen != null) - webviewParams!.onEnterFullscreen!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onEnterFullscreen(); - break; - case "onExitFullscreen": - if (webviewParams != null && webviewParams!.onExitFullscreen != null) - webviewParams!.onExitFullscreen!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onExitFullscreen(); - break; - case "onReceivedIcon": - if ((webviewParams != null && webviewParams!.onReceivedIcon != null) || - _inAppBrowserEventHandler != null) { - // For now, we just have the URL, not the actual icon data - // This could be enhanced to download the favicon - String? faviconUrl = call.arguments["url"]; - if (faviconUrl != null) { - // Create a placeholder Uint8List since we don't have the actual icon - // The favicon URL could be used to download the icon if needed - if (webviewParams != null && webviewParams!.onReceivedIcon != null) - webviewParams!.onReceivedIcon!( - _controllerFromPlatform, - Uint8List(0), - ); - else - _inAppBrowserEventHandler!.onReceivedIcon(Uint8List(0)); - } - } - break; - case "onCreateContextMenu": - ContextMenu? contextMenu; - if (webviewParams != null && webviewParams!.contextMenu != null) { - contextMenu = webviewParams!.contextMenu; - } else if (_inAppBrowserEventHandler != null && - _inAppBrowser!.contextMenu != null) { - contextMenu = _inAppBrowser!.contextMenu; - } - - if (contextMenu != null && contextMenu.onCreateContextMenu != null) { - Map arguments = call.arguments - .cast(); - InAppWebViewHitTestResult hitTestResult = - InAppWebViewHitTestResult.fromMap(arguments)!; - contextMenu.onCreateContextMenu!(hitTestResult); - } - break; - case "onHideContextMenu": - ContextMenu? contextMenu; - if (webviewParams != null && webviewParams!.contextMenu != null) { - contextMenu = webviewParams!.contextMenu; - } else if (_inAppBrowserEventHandler != null && - _inAppBrowser!.contextMenu != null) { - contextMenu = _inAppBrowser!.contextMenu; - } - - if (contextMenu != null && contextMenu.onHideContextMenu != null) { - contextMenu.onHideContextMenu!(); - } - break; - case "onContextMenuActionItemClicked": - ContextMenu? contextMenu; - if (webviewParams != null && webviewParams!.contextMenu != null) { - contextMenu = webviewParams!.contextMenu; - } else if (_inAppBrowserEventHandler != null && - _inAppBrowser!.contextMenu != null) { - contextMenu = _inAppBrowser!.contextMenu; - } - - if (contextMenu != null) { - Map arguments = call.arguments - .cast(); - String id = arguments["id"] ?? ""; - String title = arguments["title"] ?? ""; - - ContextMenuItem menuItemClicked = ContextMenuItem( - id: id, - title: title, - action: null, - ); - - // Check if this matches any custom menu items - for (var menuItem in contextMenu.menuItems) { - if (menuItem.id == id) { - menuItemClicked = menuItem; - if (menuItem.action != null) { - menuItem.action!(); - } - break; - } - } - - if (contextMenu.onContextMenuActionItemClicked != null) { - contextMenu.onContextMenuActionItemClicked!(menuItemClicked); - } - } - break; - - case "onRenderProcessGone": - if ((webviewParams != null && - webviewParams!.onRenderProcessGone != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - RenderProcessGoneDetail detail = RenderProcessGoneDetail.fromMap( - arguments, - )!; - if (webviewParams != null && - webviewParams!.onRenderProcessGone != null) - webviewParams!.onRenderProcessGone!( - _controllerFromPlatform, - detail, - ); - else - _inAppBrowserEventHandler!.onRenderProcessGone(detail); - } - break; - case "onNavigationResponse": - if ((webviewParams != null && - webviewParams!.onNavigationResponse != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - NavigationResponse navigationResponse = NavigationResponse.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.onNavigationResponse != null) - return (await webviewParams!.onNavigationResponse!( - _controllerFromPlatform, - navigationResponse, - ))?.toNativeValue(); - else - return (await _inAppBrowserEventHandler!.onNavigationResponse( - navigationResponse, - ))?.toNativeValue(); - } - break; - case "onPrintRequest": - if ((webviewParams != null && - (webviewParams!.onPrintRequest != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onPrint != null)) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - - if (webviewParams != null) { - if (webviewParams!.onPrintRequest != null) - return await webviewParams!.onPrintRequest!( - _controllerFromPlatform, - uri, - null, // PrintJobController not supported on Linux - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.onPrint!(_controllerFromPlatform, uri); - return false; - } - } else { - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.onPrint(uri); - return await _inAppBrowserEventHandler!.onPrintRequest( - uri, - null, // PrintJobController not supported on Linux - ); - } - } - break; - case "onCameraCaptureStateChanged": - if ((webviewParams != null && - webviewParams!.onCameraCaptureStateChanged != null) || - _inAppBrowserEventHandler != null) { - var oldState = MediaCaptureState.fromNativeValue( - call.arguments["oldState"], - ); - var newState = MediaCaptureState.fromNativeValue( - call.arguments["newState"], - ); - - if (webviewParams != null && - webviewParams!.onCameraCaptureStateChanged != null) - webviewParams!.onCameraCaptureStateChanged!( - _controllerFromPlatform, - oldState, - newState, - ); - else - _inAppBrowserEventHandler!.onCameraCaptureStateChanged( - oldState, - newState, - ); - } - break; - case "onMicrophoneCaptureStateChanged": - if ((webviewParams != null && - webviewParams!.onMicrophoneCaptureStateChanged != null) || - _inAppBrowserEventHandler != null) { - var oldState = MediaCaptureState.fromNativeValue( - call.arguments["oldState"], - ); - var newState = MediaCaptureState.fromNativeValue( - call.arguments["newState"], - ); - - if (webviewParams != null && - webviewParams!.onMicrophoneCaptureStateChanged != null) - webviewParams!.onMicrophoneCaptureStateChanged!( - _controllerFromPlatform, - oldState, - newState, - ); - else - _inAppBrowserEventHandler!.onMicrophoneCaptureStateChanged( - oldState, - newState, - ); - } - break; - case "onShowFileChooser": - if ((webviewParams != null && - webviewParams!.onShowFileChooser != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - ShowFileChooserRequest request = ShowFileChooserRequest.fromMap( - arguments, - )!; - - if (webviewParams != null && webviewParams!.onShowFileChooser != null) - return (await webviewParams!.onShowFileChooser!( - _controllerFromPlatform, - request, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onShowFileChooser( - request, - ))?.toMap(); - } - return null; - // onFindResultReceived is now handled by FindInteractionController - case "onLoadResourceWithCustomScheme": - if ((webviewParams != null && - (webviewParams!.onLoadResourceWithCustomScheme != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadResourceCustomScheme != null)) || - _inAppBrowserEventHandler != null) { - Map requestMap = call.arguments - .cast(); - WebResourceRequest request = WebResourceRequest.fromMap(requestMap)!; - - if (webviewParams != null) { - if (webviewParams!.onLoadResourceWithCustomScheme != null) - return (await webviewParams!.onLoadResourceWithCustomScheme!( - _controllerFromPlatform, - request, - ))?.toMap(); - else { - return (await webviewParams! - // ignore: deprecated_member_use_from_same_package - .onLoadResourceCustomScheme!( - _controllerFromPlatform, - request.url, - )) - ?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler! - .onLoadResourceWithCustomScheme(request)) ?? - (await _inAppBrowserEventHandler! - .onLoadResourceCustomScheme(request.url))) - ?.toMap(); - } - } - break; - case "onCallJsHandler": - String handlerName = call.arguments["handlerName"]; - Map handlerDataMap = call.arguments["data"] - .cast(); - // decode args to json - handlerDataMap["args"] = jsonDecode(handlerDataMap["args"]); - final handlerData = JavaScriptHandlerFunctionData.fromMap( - handlerDataMap, - )!; - - _debugLog(handlerName, handlerData); - - switch (handlerName) { - case "onLoadResource": - if ((webviewParams != null && - webviewParams!.onLoadResource != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - arguments["startTime"] = arguments["startTime"] is int - ? arguments["startTime"].toDouble() - : arguments["startTime"]; - arguments["duration"] = arguments["duration"] is int - ? arguments["duration"].toDouble() - : arguments["duration"]; - - var response = LoadedResource.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onLoadResource != null) - webviewParams!.onLoadResource!( - _controllerFromPlatform, - response, - ); - else - _inAppBrowserEventHandler!.onLoadResource(response); - } - return null; - case "shouldInterceptAjaxRequest": - if ((webviewParams != null && - webviewParams!.shouldInterceptAjaxRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - AjaxRequest request = AjaxRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.shouldInterceptAjaxRequest != null) - return jsonEncode( - await webviewParams!.shouldInterceptAjaxRequest!( - _controllerFromPlatform, - request, - ), - ); - else - return jsonEncode( - await _inAppBrowserEventHandler!.shouldInterceptAjaxRequest( - request, - ), - ); - } - return null; - case "onAjaxReadyStateChange": - if ((webviewParams != null && - webviewParams!.onAjaxReadyStateChange != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - AjaxRequest request = AjaxRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onAjaxReadyStateChange != null) - return jsonEncode( - (await webviewParams!.onAjaxReadyStateChange!( - _controllerFromPlatform, - request, - ))?.toNativeValue(), - ); - else - return jsonEncode( - (await _inAppBrowserEventHandler!.onAjaxReadyStateChange( - request, - ))?.toNativeValue(), - ); - } - return null; - case "onAjaxProgress": - if ((webviewParams != null && - webviewParams!.onAjaxProgress != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - AjaxRequest request = AjaxRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onAjaxProgress != null) - return jsonEncode( - (await webviewParams!.onAjaxProgress!( - _controllerFromPlatform, - request, - ))?.toNativeValue(), - ); - else - return jsonEncode( - (await _inAppBrowserEventHandler!.onAjaxProgress( - request, - ))?.toNativeValue(), - ); - } - return null; - case "shouldInterceptFetchRequest": - if ((webviewParams != null && - webviewParams!.shouldInterceptFetchRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - FetchRequest request = FetchRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.shouldInterceptFetchRequest != null) - return jsonEncode( - await webviewParams!.shouldInterceptFetchRequest!( - _controllerFromPlatform, - request, - ), - ); - else - return jsonEncode( - await _inAppBrowserEventHandler!.shouldInterceptFetchRequest( - request, - ), - ); - } - return null; - case "onWindowFocus": - if (webviewParams != null && webviewParams!.onWindowFocus != null) - webviewParams!.onWindowFocus!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onWindowFocus(); - return null; - case "onWindowBlur": - if (webviewParams != null && webviewParams!.onWindowBlur != null) - webviewParams!.onWindowBlur!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onWindowBlur(); - return null; - case "onInjectedScriptLoaded": - String id = handlerData.args[0]; - var onLoadCallback = _injectedScriptsFromURL[id]?.onLoad; - if ((webviewParams != null || _inAppBrowserEventHandler != null) && - onLoadCallback != null) { - onLoadCallback(); - } - return null; - case "onInjectedScriptError": - String id = handlerData.args[0]; - var onErrorCallback = _injectedScriptsFromURL[id]?.onError; - if ((webviewParams != null || _inAppBrowserEventHandler != null) && - onErrorCallback != null) { - onErrorCallback(); - } - return null; - case "onWebMessageListenerPostMessageReceived": - Map arguments = handlerData.args[0] - .cast(); - String jsObjectName = arguments["jsObjectName"]; - // Find the corresponding web message listener - for (var listener in _webMessageListeners) { - if (listener.params.jsObjectName == jsObjectName) { - // Forward to the listener's channel - Map? messageMap = arguments["message"] - ?.cast(); - WebMessage? message = messageMap != null - ? WebMessage.fromMap(messageMap) - : null; - String? sourceOrigin = arguments["sourceOrigin"]; - bool isMainFrame = arguments["isMainFrame"] ?? true; - // Call the listener's onPostMessage callback via channel - listener.channel?.invokeMethod("onPostMessage", { - "message": message?.toMap(), - "sourceOrigin": sourceOrigin, - "isMainFrame": isMainFrame, - }); - break; - } - } - return null; - case "onWebMessagePortMessageReceived": - Map arguments = handlerData.args[0] - .cast(); - String webMessageChannelId = arguments["webMessageChannelId"]; - int index = arguments["index"]; - // Find the channel and forward the message - for (var webMessageChannel in _webMessageChannels) { - if (webMessageChannel.id == webMessageChannelId) { - Map? messageMap = arguments["message"] - ?.cast(); - WebMessage? message = messageMap != null - ? WebMessage.fromMap(messageMap) - : null; - webMessageChannel.internalChannel?.invokeMethod("onMessage", { - "index": index, - "message": message?.toMap(), - }); - break; - } - } - return null; - } - - if (_javaScriptHandlersMap.containsKey(handlerName)) { - // convert result to json - try { - var jsHandlerResult = null; - if (_javaScriptHandlersMap[handlerName] - is JavaScriptHandlerCallback) { - jsHandlerResult = - await (_javaScriptHandlersMap[handlerName] - as JavaScriptHandlerCallback)(handlerData.args); - } else if (_javaScriptHandlersMap[handlerName] - is JavaScriptHandlerFunction) { - jsHandlerResult = - await (_javaScriptHandlersMap[handlerName] - as JavaScriptHandlerFunction)(handlerData); - } else { - jsHandlerResult = await _javaScriptHandlersMap[handlerName]!(); - } - return jsonEncode(jsHandlerResult); - } catch (error, stacktrace) { - developer.log( - error.toString() + '\n' + stacktrace.toString(), - name: 'JavaScript Handler "$handlerName"', - ); - throw Exception(error.toString().replaceFirst('Exception: ', '')); - } - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - Future getUrl() async { - Map args = {}; - String? url = await channel?.invokeMethod('getUrl', args); - return url != null ? WebUri(url) : null; - } - - @override - Future getTitle() async { - Map args = {}; - return await channel?.invokeMethod('getTitle', args); - } - - @override - Future loadUrl({ - required URLRequest urlRequest, - @Deprecated('Use allowingReadAccessTo instead') - Uri? iosAllowingReadAccessTo, - WebUri? allowingReadAccessTo, - }) async { - Map args = {}; - args.putIfAbsent('urlRequest', () => urlRequest.toMap()); - args.putIfAbsent( - 'allowingReadAccessTo', - () => - allowingReadAccessTo?.toString() ?? - iosAllowingReadAccessTo?.toString(), - ); - await channel?.invokeMethod('loadUrl', args); - } - - @override - Future loadData({ - required String data, - String mimeType = "text/html", - String encoding = "utf8", - WebUri? baseUrl, - @Deprecated('Use historyUrl instead') Uri? androidHistoryUrl, - WebUri? historyUrl, - @Deprecated('Use allowingReadAccessTo instead') - Uri? iosAllowingReadAccessTo, - WebUri? allowingReadAccessTo, - }) async { - Map args = {}; - args.putIfAbsent('data', () => data); - args.putIfAbsent('mimeType', () => mimeType); - args.putIfAbsent('encoding', () => encoding); - args.putIfAbsent('baseUrl', () => baseUrl?.toString() ?? 'about:blank'); - await channel?.invokeMethod('loadData', args); - } - - @override - Future postUrl({ - required WebUri url, - required Uint8List postData, - }) async { - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - args.putIfAbsent('postData', () => postData); - await channel?.invokeMethod('postUrl', args); - } - - @override - Future reload() async { - Map args = {}; - await channel?.invokeMethod('reload', args); - } - - @override - Future reloadFromOrigin() async { - Map args = {}; - await channel?.invokeMethod('reloadFromOrigin', args); - } - - @override - Future goBack() async { - Map args = {}; - await channel?.invokeMethod('goBack', args); - } - - @override - Future goForward() async { - Map args = {}; - await channel?.invokeMethod('goForward', args); - } - - @override - Future canGoBack() async { - Map args = {}; - return await channel?.invokeMethod('canGoBack', args) ?? false; - } - - @override - Future canGoForward() async { - Map args = {}; - return await channel?.invokeMethod('canGoForward', args) ?? false; - } - - @override - Future stopLoading() async { - Map args = {}; - await channel?.invokeMethod('stopLoading', args); - } - - @override - Future isLoading() async { - Map args = {}; - return await channel?.invokeMethod('isLoading', args) ?? false; - } - - @override - Future getProgress() async { - Map args = {}; - return await channel?.invokeMethod('getProgress', args); - } - - @override - Future loadFile({required String assetFilePath}) async { - Map args = {}; - args.putIfAbsent('assetFilePath', () => assetFilePath); - await channel?.invokeMethod('loadFile', args); - } - - @override - Future evaluateJavascript({ - required String source, - ContentWorld? contentWorld, - }) async { - Map args = {}; - args.putIfAbsent('source', () => source); - if (contentWorld != null) { - args.putIfAbsent('contentWorld', () => contentWorld.toMap()); - } - var result = await channel?.invokeMethod('evaluateJavascript', args); - if (result != null && result is String) { - try { - result = jsonDecode(result); - } catch (e) {} - } - return result; - } - - @override - Future callAsyncJavaScript({ - required String functionBody, - Map arguments = const {}, - ContentWorld? contentWorld, - }) async { - Map args = {}; - args.putIfAbsent('functionBody', () => functionBody); - // JSON encode arguments to handle complex types (arrays, nested objects) - // that WPE WebKit's GVariant a{sv} format doesn't support directly - args.putIfAbsent('arguments', () => jsonEncode(arguments)); - args.putIfAbsent('argumentKeys', () => arguments.keys.toList()); - if (contentWorld != null) { - args.putIfAbsent('contentWorld', () => contentWorld.toMap()); - } - - // Native returns a JSON string: {"value": ..., "error": ...} - String? jsonResult = await channel?.invokeMethod( - 'callAsyncJavaScript', - args, - ); - - if (jsonResult != null) { - try { - Map result = jsonDecode(jsonResult); - return CallAsyncJavaScriptResult( - value: result['value'], - error: result['error'], - ); - } catch (e) { - return CallAsyncJavaScriptResult( - value: null, - error: 'Failed to decode result: $e', - ); - } - } - return null; - } - - @override - Future injectJavascriptFileFromUrl({ - required WebUri urlFile, - ScriptHtmlTagAttributes? scriptHtmlTagAttributes, - }) async { - Map args = {}; - args.putIfAbsent('urlFile', () => urlFile.toString()); - args.putIfAbsent( - 'scriptHtmlTagAttributes', - () => scriptHtmlTagAttributes?.toMap(), - ); - await channel?.invokeMethod('injectJavascriptFileFromUrl', args); - } - - @override - Future injectCSSCode({required String source}) async { - Map args = {}; - args.putIfAbsent('source', () => source); - await channel?.invokeMethod('injectCSSCode', args); - } - - @override - Future injectCSSFileFromUrl({ - required WebUri urlFile, - CSSLinkHtmlTagAttributes? cssLinkHtmlTagAttributes, - }) async { - Map args = {}; - args.putIfAbsent('urlFile', () => urlFile.toString()); - args.putIfAbsent( - 'cssLinkHtmlTagAttributes', - () => cssLinkHtmlTagAttributes?.toMap(), - ); - await channel?.invokeMethod('injectCSSFileFromUrl', args); - } - - @override - Future getHtml() async { - Map args = {}; - return await channel?.invokeMethod('getHtml', args); - } - - @override - Future getSelectedText() async { - Map args = {}; - return await channel?.invokeMethod('getSelectedText', args); - } - - @override - Future isSecureContext() async { - Map args = {}; - return await channel?.invokeMethod('isSecureContext', args) ?? false; - } - - @override - Future getCertificate() async { - Map args = {}; - Map? result = await channel?.invokeMethod( - 'getCertificate', - args, - ); - if (result != null) { - return SslCertificate.fromMap(result.cast()); - } - return null; - } - - @override - Future getHitTestResult() async { - Map args = {}; - Map? result = await channel?.invokeMethod( - 'getHitTestResult', - args, - ); - if (result != null) { - return InAppWebViewHitTestResult.fromMap(result.cast()); - } - return null; - } - - @override - Future clearAllCache({bool includeDiskFiles = true}) async { - Map args = {}; - args.putIfAbsent('includeDiskFiles', () => includeDiskFiles); - await _staticChannel.invokeMethod('clearAllCache', args); - } - - @override - Future setJavaScriptBridgeName(String bridgeName) async { - assert( - RegExp(r'^[a-zA-Z_]\w*$').hasMatch(bridgeName), - 'bridgeName must be a non-empty string with only alphanumeric and underscore characters. It can\'t start with a number.', - ); - Map args = {}; - args.putIfAbsent('bridgeName', () => bridgeName); - await _staticChannel.invokeMethod('setJavaScriptBridgeName', args); - } - - @override - Future getJavaScriptBridgeName() async { - Map args = {}; - return await _staticChannel.invokeMethod( - 'getJavaScriptBridgeName', - args, - ) ?? - 'flutter_inappwebview'; - } - - @override - Future disposeKeepAlive(InAppWebViewKeepAlive keepAlive) async { - Map args = {}; - args.putIfAbsent('keepAliveId', () => keepAlive.id); - await _staticChannel.invokeMethod('disposeKeepAlive', args); - _keepAliveMap[keepAlive] = null; - } - - @override - Future get tRexRunnerHtml async => await rootBundle.loadString( - 'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html', - ); - - @override - Future get tRexRunnerCss async => await rootBundle.loadString( - 'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.css', - ); - - @override - dynamic getViewId() { - return id; - } - - @override - Future handlesURLScheme(String urlScheme) async { - Map args = {}; - args.putIfAbsent('urlScheme', () => urlScheme); - return await _staticChannel.invokeMethod('handlesURLScheme', args) ?? - false; - } - - @override - Future canScrollVertically() async { - Map args = {}; - return await channel?.invokeMethod('canScrollVertically', args) ?? - false; - } - - @override - Future canScrollHorizontally() async { - Map args = {}; - return await channel?.invokeMethod('canScrollHorizontally', args) ?? - false; - } - - @override - Future getZoomScale() async { - Map args = {}; - return await channel?.invokeMethod('getZoomScale', args); - } - - @override - Future zoomBy({ - required double zoomFactor, - @Deprecated('Use animated instead') bool? iosAnimated, - bool animated = false, - }) async { - Map args = {}; - args.putIfAbsent('zoomFactor', () => zoomFactor); - await channel?.invokeMethod('setZoomScale', args); - } - - @override - Future scrollTo({ - required int x, - required int y, - bool animated = false, - }) async { - Map args = {}; - args.putIfAbsent('x', () => x); - args.putIfAbsent('y', () => y); - args.putIfAbsent('animated', () => animated); - await channel?.invokeMethod('scrollTo', args); - } - - @override - Future scrollBy({ - required int x, - required int y, - bool animated = false, - }) async { - Map args = {}; - args.putIfAbsent('x', () => x); - args.putIfAbsent('y', () => y); - args.putIfAbsent('animated', () => animated); - await channel?.invokeMethod('scrollBy', args); - } - - @override - Future getScrollX() async { - Map args = {}; - return await channel?.invokeMethod('getScrollX', args); - } - - @override - Future getScrollY() async { - Map args = {}; - return await channel?.invokeMethod('getScrollY', args); - } - - @override - Future getSettings() async { - Map args = {}; - Map? settings = await channel?.invokeMethod( - 'getSettings', - args, - ); - if (settings != null) { - settings = settings.cast(); - return InAppWebViewSettings.fromMap(settings as Map); - } - return null; - } - - @override - Future setSettings({required InAppWebViewSettings settings}) async { - Map args = {}; - args.putIfAbsent('settings', () => settings.toMap()); - await channel?.invokeMethod('setSettings', args); - } - - @override - void addJavaScriptHandler({ - required String handlerName, - required Function callback, - }) { - assert( - !kJavaScriptHandlerForbiddenNames.contains(handlerName), - '"$handlerName" is a reserved name and cannot be used as a JavaScript handler name.', - ); - _javaScriptHandlersMap[handlerName] = callback; - } - - @override - Function? removeJavaScriptHandler({required String handlerName}) { - return _javaScriptHandlersMap.remove(handlerName); - } - - @override - bool hasJavaScriptHandler({required String handlerName}) { - return _javaScriptHandlersMap.containsKey(handlerName); - } - - @override - Future addUserScript({required UserScript userScript}) async { - // Note: WebKitGTK doesn't support content worlds like WKWebView, - // so we ignore the contentWorld parameter - Map args = {}; - args.putIfAbsent('userScript', () => userScript.toMap()); - await channel?.invokeMethod('addUserScript', args); - - _userScripts[userScript.injectionTime]?.add(userScript); - } - - @override - Future addUserScripts({required List userScripts}) async { - for (var userScript in userScripts) { - await addUserScript(userScript: userScript); - } - } - - @override - Future removeUserScript({required UserScript userScript}) async { - var index = - _userScripts[userScript.injectionTime]?.indexOf(userScript) ?? -1; - if (index == -1) { - return false; - } - - Map args = {}; - args.putIfAbsent('index', () => index); - args.putIfAbsent( - 'injectionTime', - () => userScript.injectionTime.toNativeValue(), - ); - await channel?.invokeMethod('removeUserScript', args); - - _userScripts[userScript.injectionTime]?.remove(userScript); - return true; - } - - @override - Future removeUserScriptsByGroupName({required String groupName}) async { - Map args = {}; - args.putIfAbsent('groupName', () => groupName); - await channel?.invokeMethod('removeUserScriptsByGroupName', args); - - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.removeWhere( - (element) => element.groupName == groupName, - ); - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.removeWhere( - (element) => element.groupName == groupName, - ); - } - - @override - Future removeUserScripts({ - required List userScripts, - }) async { - for (var userScript in userScripts) { - await removeUserScript(userScript: userScript); - } - } - - @override - Future removeAllUserScripts() async { - await channel?.invokeMethod('removeAllUserScripts', {}); - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.clear(); - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.clear(); - } - - /// Returns all user scripts that have been added. - /// This is a Linux-specific method for accessing the user scripts cache. - Future> getUserScripts() async { - List result = []; - result.addAll( - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_START] ?? [], - ); - result.addAll(_userScripts[UserScriptInjectionTime.AT_DOCUMENT_END] ?? []); - return result; - } - - @override - bool hasUserScript({required UserScript userScript}) { - return _userScripts[userScript.injectionTime]?.contains(userScript) ?? - false; - } - - @override - Future addWebMessageListener( - PlatformWebMessageListener webMessageListener, - ) async { - assert( - !_webMessageListeners.contains(webMessageListener), - "${webMessageListener} was already added.", - ); - assert( - !_webMessageListenerObjNames.contains( - webMessageListener.params.jsObjectName, - ), - "jsObjectName ${webMessageListener.params.jsObjectName} was already added.", - ); - _webMessageListeners.add(webMessageListener as LinuxWebMessageListener); - _webMessageListenerObjNames.add(webMessageListener.params.jsObjectName); - - Map args = {}; - args.putIfAbsent('webMessageListener', () => webMessageListener.toMap()); - await channel?.invokeMethod('addWebMessageListener', args); - } - - @override - bool hasWebMessageListener(PlatformWebMessageListener webMessageListener) { - return _webMessageListeners.contains(webMessageListener) || - _webMessageListenerObjNames.contains( - webMessageListener.params.jsObjectName, - ); - } - - @override - Future createWebMessageChannel() async { - Map args = {}; - Map? result = (await channel?.invokeMethod( - 'createWebMessageChannel', - args, - ))?.cast(); - final webMessageChannel = LinuxWebMessageChannel.static().fromMap(result); - if (webMessageChannel != null) { - _webMessageChannels.add(webMessageChannel); - } - return webMessageChannel; - } - - @override - Future postWebMessage({ - required WebMessage message, - WebUri? targetOrigin, - }) async { - if (targetOrigin == null) { - targetOrigin = WebUri(''); - } - Map args = {}; - args.putIfAbsent('message', () => message.toMap()); - args.putIfAbsent('targetOrigin', () => targetOrigin.toString()); - await channel?.invokeMethod('postWebMessage', args); - } - - @override - Future getOriginalUrl() async { - Map args = {}; - String? url = await channel?.invokeMethod('getOriginalUrl', args); - return url != null ? WebUri(url) : null; - } - - /// Sets the zoom level of the WebView. - /// This is a Linux-specific method that directly sets the zoom level. - /// For cross-platform code, use [zoomBy] instead. - Future setZoomScale({ - required double zoomScale, - @Deprecated('Use animated instead') bool? iosAnimated, - bool animated = false, - }) async { - Map args = {}; - args.putIfAbsent('zoomScale', () => zoomScale); - args.putIfAbsent('animated', () => animated); - await channel?.invokeMethod('setZoomScale', args); - } - - @override - Future isInFullscreen() async { - return await channel?.invokeMethod('isInFullscreen', {}) ?? false; - } - - @override - Future requestEnterFullscreen() async { - await channel?.invokeMethod('requestEnterFullscreen', {}); - } - - @override - Future requestExitFullscreen() async { - await channel?.invokeMethod('requestExitFullscreen', {}); - } - - @override - Future setVisible({required bool visible}) async { - await channel?.invokeMethod('setVisible', visible); - } - - @override - Future setTargetRefreshRate({required int rate}) async { - await channel?.invokeMethod('setTargetRefreshRate', rate); - } - - @override - Future getTargetRefreshRate() async { - return await channel?.invokeMethod('getTargetRefreshRate', {}) ?? 0; - } - - @override - Future getScreenScale() async { - return await channel?.invokeMethod('getScreenScale', {}) ?? 1.0; - } - - @override - Future setScreenScale({required double scale}) async { - await channel?.invokeMethod('setScreenScale', scale); - } - - @override - Future isVisible() async { - return await channel?.invokeMethod('isVisible', {}) ?? false; - } - - @override - Future requestPointerLock() async { - return await channel?.invokeMethod('requestPointerLock', {}) ?? false; - } - - @override - Future requestPointerUnlock() async { - return await channel?.invokeMethod('requestPointerUnlock', {}) ?? - false; - } - - @override - Future takeScreenshot({ - ScreenshotConfiguration? screenshotConfiguration, - }) async { - Map args = {}; - args.putIfAbsent( - 'screenshotConfiguration', - () => screenshotConfiguration?.toMap(), - ); - return await channel?.invokeMethod('takeScreenshot', args); - } - - @override - Future saveState() async { - Map args = {}; - return await channel?.invokeMethod('saveState', args); - } - - @override - Future restoreState(Uint8List state) async { - Map args = {}; - args.putIfAbsent('state', () => state); - return await channel?.invokeMethod('restoreState', args) ?? false; - } - - @override - Future saveWebArchive({ - required String filePath, - bool autoname = false, - }) async { - if (!autoname) { - assert( - WebArchiveFormat.MHT.isSupported() && - filePath.endsWith("." + WebArchiveFormat.MHT.toNativeValue()!), - ); - } - - Map args = {}; - args.putIfAbsent('filePath', () => filePath); - args.putIfAbsent('autoname', () => autoname); - return await channel?.invokeMethod('saveWebArchive', args); - } - - @override - Future getContentHeight() async { - Map args = {}; - return await channel?.invokeMethod('getContentHeight', args); - } - - @override - Future getContentWidth() async { - Map args = {}; - return await channel?.invokeMethod('getContentWidth', args); - } - - @override - Future getCopyBackForwardList() async { - Map args = {}; - Map? result = await channel?.invokeMethod( - 'getCopyBackForwardList', - args, - ); - if (result != null) { - return WebHistory.fromMap(result.cast()); - } - return null; - } - - @override - Future goBackOrForward({required int steps}) async { - Map args = {}; - args.putIfAbsent('steps', () => steps); - await channel?.invokeMethod('goBackOrForward', args); - } - - @override - Future canGoBackOrForward({required int steps}) async { - Map args = {}; - args.putIfAbsent('steps', () => steps); - return await channel?.invokeMethod('canGoBackOrForward', args) ?? - false; - } - - @override - Future> getFavicons() async { - List favicons = []; - - var webviewUrl = await getUrl(); - - if (webviewUrl == null) { - return favicons; - } - - String? manifestUrl; - - var html = await getHtml(); - if (html == null || html.isEmpty) { - return favicons; - } - var assetPathBase; - - if (webviewUrl.isScheme("file")) { - var assetPathSplit = webviewUrl.toString().split("/flutter_assets/"); - assetPathBase = assetPathSplit[0] + "/flutter_assets/"; - } - - InAppWebViewSettings? settings = await getSettings(); - if (settings != null && settings.javaScriptEnabled == true) { - var jsResult = await evaluateJavascript( - source: """ -(function() { - var linkNodes = document.head.getElementsByTagName("link"); - var links = []; - for (var i = 0; i < linkNodes.length; i++) { - var linkNode = linkNodes[i]; - if (linkNode.rel === 'manifest') { - links.push( - { - rel: linkNode.rel, - href: linkNode.href, - sizes: null - } - ); - } else if (linkNode.rel != null && linkNode.rel.indexOf('icon') >= 0) { - links.push( - { - rel: linkNode.rel, - href: linkNode.href, - sizes: linkNode.sizes != null && linkNode.sizes.value != "" ? linkNode.sizes.value : null - } - ); - } - } - return links; -})(); -""", - ); - List> links = []; - if (jsResult is List) { - links = jsResult.cast>(); - } - for (var link in links) { - if (link["rel"] == "manifest") { - manifestUrl = link["href"]; - if (!_isUrlAbsolute(manifestUrl!)) { - if (manifestUrl.startsWith("/")) { - manifestUrl = manifestUrl.substring(1); - } - manifestUrl = - ((assetPathBase == null) - ? webviewUrl.scheme + "://" + webviewUrl.host + "/" - : assetPathBase) + - manifestUrl; - } - continue; - } - favicons.addAll( - _createFavicons( - webviewUrl, - assetPathBase, - link["href"], - link["rel"], - link["sizes"], - false, - ), - ); - } - } - - // try to get /favicon.ico - try { - HttpClient client = HttpClient(); - var faviconUrl = - webviewUrl.scheme + "://" + webviewUrl.host + "/favicon.ico"; - var faviconUri = WebUri(faviconUrl); - var headRequest = await client.headUrl(faviconUri); - var headResponse = await headRequest.close(); - if (headResponse.statusCode == 200) { - favicons.add(Favicon(url: faviconUri, rel: "shortcut icon")); - } - } catch (e) { - developer.log( - "/favicon.ico file not found: " + e.toString(), - name: runtimeType.toString(), - ); - } - - // try to get the manifest file - HttpClientRequest? manifestRequest; - HttpClientResponse? manifestResponse; - bool manifestFound = false; - if (manifestUrl == null) { - manifestUrl = - webviewUrl.scheme + "://" + webviewUrl.host + "/manifest.json"; - } - try { - HttpClient client = HttpClient(); - manifestRequest = await client.getUrl(Uri.parse(manifestUrl)); - manifestResponse = await manifestRequest.close(); - manifestFound = - manifestResponse.statusCode == 200 && - manifestResponse.headers.contentType?.mimeType == "application/json"; - } catch (e) { - developer.log( - "Manifest file not found: " + e.toString(), - name: this.runtimeType.toString(), - ); - } - - if (manifestFound) { - try { - Map manifest = json.decode( - await manifestResponse!.transform(Utf8Decoder()).join(), - ); - if (manifest.containsKey("icons")) { - for (Map icon in manifest["icons"]) { - favicons.addAll( - _createFavicons( - webviewUrl, - assetPathBase, - icon["src"], - icon["rel"], - icon["sizes"], - true, - ), - ); - } - } - } catch (e) { - developer.log( - "Cannot get favicons from Manifest file. It might not have a valid format: " + - e.toString(), - error: e, - name: runtimeType.toString(), - ); - } - } - - return favicons; - } - - bool _isUrlAbsolute(String url) { - return url.startsWith("http://") || url.startsWith("https://"); - } - - List _createFavicons( - WebUri url, - String? assetPathBase, - String urlIcon, - String? rel, - String? sizes, - bool isManifest, - ) { - List favicons = []; - - List urlSplit = urlIcon.split("/"); - if (!_isUrlAbsolute(urlIcon)) { - if (urlIcon.startsWith("/")) { - urlIcon = urlIcon.substring(1); - } - urlIcon = - ((assetPathBase == null) - ? url.scheme + "://" + url.host + "/" - : assetPathBase) + - urlIcon; - } - if (isManifest) { - rel = (sizes != null) - ? urlSplit[urlSplit.length - 1] - .replaceFirst("-" + sizes, "") - .split(" ")[0] - .split(".")[0] - : null; - } - if (sizes != null && sizes.isNotEmpty && sizes != "any") { - List sizesSplit = sizes.split(" "); - for (String size in sizesSplit) { - int width = int.parse(size.split("x")[0]); - int height = int.parse(size.split("x")[1]); - favicons.add( - Favicon(url: WebUri(urlIcon), rel: rel, width: width, height: height), - ); - } - } else { - favicons.add( - Favicon(url: WebUri(urlIcon), rel: rel, width: null, height: null), - ); - } - - return favicons; - } - - @override - Future pauseAllMediaPlayback() async { - Map args = {}; - await channel?.invokeMethod('pauseAllMediaPlayback', args); - } - - @override - Future setAllMediaPlaybackSuspended({required bool suspended}) async { - Map args = {}; - args.putIfAbsent('suspended', () => suspended); - await channel?.invokeMethod('setAllMediaPlaybackSuspended', args); - } - - @override - Future closeAllMediaPresentations() async { - Map args = {}; - await channel?.invokeMethod('closeAllMediaPresentations', args); - } - - @override - Future requestMediaPlaybackState() async { - Map args = {}; - int? result = await channel?.invokeMethod( - 'requestMediaPlaybackState', - args, - ); - if (result != null) { - return MediaPlaybackState.fromNativeValue(result); - } - return null; - } - - @override - Future getCameraCaptureState() async { - Map args = {}; - int? result = await channel?.invokeMethod( - 'getCameraCaptureState', - args, - ); - if (result != null) { - return MediaCaptureState.fromNativeValue(result); - } - return null; - } - - @override - Future setCameraCaptureState({required MediaCaptureState state}) async { - Map args = {}; - args.putIfAbsent('state', () => state.toNativeValue()); - await channel?.invokeMethod('setCameraCaptureState', args); - } - - @override - Future getMicrophoneCaptureState() async { - Map args = {}; - int? result = await channel?.invokeMethod( - 'getMicrophoneCaptureState', - args, - ); - if (result != null) { - return MediaCaptureState.fromNativeValue(result); - } - return null; - } - - @override - Future setMicrophoneCaptureState({ - required MediaCaptureState state, - }) async { - Map args = {}; - args.putIfAbsent('state', () => state.toNativeValue()); - await channel?.invokeMethod('setMicrophoneCaptureState', args); - } - - @override - Future> getMetaTags() async { - List metaTags = []; - - List>? metaTagList = (await evaluateJavascript( - source: """ -(function() { - var metaTags = []; - var metaTagNodes = document.head.getElementsByTagName('meta'); - for (var i = 0; i < metaTagNodes.length; i++) { - var metaTagNode = metaTagNodes[i]; - - var otherAttributes = metaTagNode.getAttributeNames(); - var nameIndex = otherAttributes.indexOf("name"); - if (nameIndex !== -1) otherAttributes.splice(nameIndex, 1); - var contentIndex = otherAttributes.indexOf("content"); - if (contentIndex !== -1) otherAttributes.splice(contentIndex, 1); - - var attrs = []; - for (var j = 0; j < otherAttributes.length; j++) { - var otherAttribute = otherAttributes[j]; - attrs.push( - { - name: otherAttribute, - value: metaTagNode.getAttribute(otherAttribute) - } - ); - } - - metaTags.push( - { - name: metaTagNode.name, - content: metaTagNode.content, - attrs: attrs - } - ); - } - return metaTags; -})(); - """, - ))?.cast>(); - - if (metaTagList == null) { - return metaTags; - } - - for (var metaTag in metaTagList) { - var attrs = []; - - for (var metaTagAttr in metaTag["attrs"]) { - attrs.add( - MetaTagAttribute( - name: metaTagAttr["name"], - value: metaTagAttr["value"], - ), - ); - } - - metaTags.add( - MetaTag( - name: metaTag["name"], - content: metaTag["content"], - attrs: attrs, - ), - ); - } - - return metaTags; - } - - @override - Future getMetaThemeColor() async { - Map args = {}; - String? hexColor = await channel?.invokeMethod( - 'getMetaThemeColor', - args, - ); - if (hexColor == null || hexColor.isEmpty) { - return null; - } - // Parse hex color string like #RRGGBB or #RRGGBBAA - return UtilColor.fromHex(hexColor); - } - - @override - Future isPlayingAudio() async { - Map args = {}; - return await channel?.invokeMethod('isPlayingAudio', args) ?? false; - } - - @override - Future isMuted() async { - Map args = {}; - return await channel?.invokeMethod('isMuted', args) ?? false; - } - - @override - Future setMuted({required bool muted}) async { - Map args = {}; - args.putIfAbsent('muted', () => muted); - await channel?.invokeMethod('setMuted', args); - } - - @override - Future terminateWebProcess() async { - Map args = {}; - await channel?.invokeMethod('terminateWebProcess', args); - } - - @override - Future clearFocus() async { - Map args = {}; - await channel?.invokeMethod('clearFocus', args); - } - - @override - Future requestFocus({ - FocusDirection? direction, - InAppWebViewRect? previouslyFocusedRect, - }) async { - Map args = {}; - return await channel?.invokeMethod('requestFocus', args); - } - - @override - void dispose({bool isKeepAlive = false}) { - if (!isKeepAlive) { - for (final webMessageListener in _webMessageListeners) { - webMessageListener.dispose(); - } - _webMessageListeners.clear(); - _webMessageListenerObjNames.clear(); - for (final webMessageChannel in _webMessageChannels) { - webMessageChannel.dispose(); - } - _webMessageChannels.clear(); - } - webStorage.dispose(); - disposeChannel(removeMethodCallHandler: !isKeepAlive); - } -} - -extension InternalInAppWebViewController on LinuxInAppWebViewController { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_linux/lib/src/in_app_webview/key_mappings.dart b/flutter_inappwebview_linux/lib/src/in_app_webview/key_mappings.dart deleted file mode 100644 index 25bd7c3d90..0000000000 --- a/flutter_inappwebview_linux/lib/src/in_app_webview/key_mappings.dart +++ /dev/null @@ -1,145 +0,0 @@ -/// Key mapping tables for WPE WebKit keyboard input -/// -/// WPE WebKit expects: -/// - key_code: XKB keysym (Unicode for printable chars, 0xFF00+ for special keys) -/// - hardware_key_code: X11 keycode (evdev scancode + 8) - -import 'package:flutter/services.dart'; - -/// USB HID usage code to Linux evdev scancode mapping. -/// Based on Linux kernel's hid-input.c hid_keyboard[] table. -/// Reference: https://www.usb.org/sites/default/files/hut1_3_0.pdf (page 89) -const kUsbHidToEvdev = { - // Letters (a-z) - 0x04: 30, 0x05: 48, 0x06: 46, 0x07: 32, 0x08: 18, 0x09: 33, - 0x0a: 34, 0x0b: 35, 0x0c: 23, 0x0d: 36, 0x0e: 37, 0x0f: 38, - 0x10: 50, 0x11: 49, 0x12: 24, 0x13: 25, 0x14: 16, 0x15: 19, - 0x16: 31, 0x17: 20, 0x18: 22, 0x19: 47, 0x1a: 17, 0x1b: 45, - 0x1c: 21, 0x1d: 44, - // Numbers (1-0) - 0x1e: 2, 0x1f: 3, 0x20: 4, 0x21: 5, 0x22: 6, - 0x23: 7, 0x24: 8, 0x25: 9, 0x26: 10, 0x27: 11, - // Common keys - 0x28: 28, // Enter - 0x29: 1, // Escape - 0x2a: 14, // Backspace - 0x2b: 15, // Tab - 0x2c: 57, // Space - // Symbols - 0x2d: 12, 0x2e: 13, 0x2f: 26, 0x30: 27, 0x31: 43, - 0x33: 39, 0x34: 40, 0x35: 41, 0x36: 51, 0x37: 52, 0x38: 53, - // Lock keys - 0x39: 58, // CapsLock - // Function keys (F1-F12) - 0x3a: 59, 0x3b: 60, 0x3c: 61, 0x3d: 62, 0x3e: 63, 0x3f: 64, - 0x40: 65, 0x41: 66, 0x42: 67, 0x43: 68, 0x44: 87, 0x45: 88, - // System keys - 0x46: 99, 0x47: 70, 0x48: 119, - // Navigation - 0x49: 110, 0x4a: 102, 0x4b: 104, 0x4c: 111, 0x4d: 107, 0x4e: 109, - // Arrow keys - 0x4f: 106, 0x50: 105, 0x51: 108, 0x52: 103, - // Keypad - 0x53: 69, 0x54: 98, 0x55: 55, 0x56: 74, 0x57: 78, 0x58: 96, - 0x59: 79, 0x5a: 80, 0x5b: 81, 0x5c: 75, 0x5d: 76, 0x5e: 77, - 0x5f: 71, 0x60: 72, 0x61: 73, 0x62: 82, 0x63: 83, - // Modifiers - 0xe0: 29, 0xe1: 42, 0xe2: 56, 0xe3: 125, - 0xe4: 97, 0xe5: 54, 0xe6: 100, 0xe7: 126, -}; - -/// Convert USB HID usage code to X11 keycode. -/// X11 keycode = evdev scancode + 8 -int usbHidToX11Keycode(int usbHid) { - final evdev = kUsbHidToEvdev[usbHid] ?? 0; - return evdev + 8; -} - -/// X11 keysym values for special keys. -/// For printable characters, the Unicode code point IS the keysym. -int getX11Keysym(LogicalKeyboardKey key, String? character) { - // For printable characters, use Unicode code point directly - if (character != null && character.isNotEmpty) { - final codeUnit = character.codeUnitAt(0); - if (codeUnit >= 0x20 && codeUnit < 0x7f) { - return codeUnit; // ASCII printable -> Unicode keysym - } - // Extended Latin and other Unicode characters (keysym = Unicode codepoint) - if (codeUnit >= 0x00a0 && codeUnit <= 0xffff) { - return codeUnit; - } - } - - // Special keys use X11 keysym constants - final keyId = key.keyId; - - // Check explicit mapping first - final mapped = _specialKeyToKeysym[keyId]; - if (mapped != null) { - return mapped; - } - - // Function keys (F1-F24): XK_F1 = 0xffbe, XK_F13 = 0xffc8 - if (keyId >= LogicalKeyboardKey.f1.keyId && - keyId <= LogicalKeyboardKey.f24.keyId) { - return 0xffbe + (keyId - LogicalKeyboardKey.f1.keyId); - } - - // Try keyLabel for printable characters that weren't caught above - final label = key.keyLabel; - if (label.length == 1) { - final codeUnit = label.codeUnitAt(0); - // ASCII printable or extended Latin - if ((codeUnit >= 0x20 && codeUnit < 0x7f) || - (codeUnit >= 0x00a0 && codeUnit <= 0xffff)) { - return codeUnit; - } - } - - // Return 0 for unknown keys - safer than truncating keyId which could - // collide with valid keysyms or produce unexpected behavior - return 0; -} - -const _specialKeyToKeysym = { - // Control keys - 0x100000008: 0xff08, // Backspace (XK_BackSpace) - 0x100000009: 0xff09, // Tab (XK_Tab) - 0x10000000d: 0xff0d, // Enter (XK_Return) - 0x10000001b: 0xff1b, // Escape (XK_Escape) - 0x10000007f: 0xffff, // Delete (XK_Delete) - - // Arrow keys - Flutter LogicalKeyboardKey.arrow*.keyId values - 0x100000301: 0xff54, // ArrowDown (XK_Down) - 0x100000302: 0xff51, // ArrowLeft (XK_Left) - 0x100000303: 0xff53, // ArrowRight (XK_Right) - 0x100000304: 0xff52, // ArrowUp (XK_Up) - - // Navigation keys - Flutter LogicalKeyboardKey.*.keyId values - 0x100000305: 0xff57, // End (XK_End) - 0x100000306: 0xff50, // Home (XK_Home) - 0x100000307: 0xff56, // PageDown (XK_Page_Down) - 0x100000308: 0xff55, // PageUp (XK_Page_Up) - 0x100000407: 0xff63, // Insert (XK_Insert) - - // Lock keys - 0x100000104: 0xffe5, // CapsLock (XK_Caps_Lock) - 0x10000010a: 0xff7f, // NumLock (XK_Num_Lock) - 0x10000010c: 0xff14, // ScrollLock (XK_Scroll_Lock) - - // Modifier keys (note: 0x200000xxx range) - 0x200000100: 0xffe3, // ControlLeft (XK_Control_L) - 0x200000101: 0xffe4, // ControlRight (XK_Control_R) - 0x200000102: 0xffe1, // ShiftLeft (XK_Shift_L) - 0x200000103: 0xffe2, // ShiftRight (XK_Shift_R) - 0x200000104: 0xffe9, // AltLeft (XK_Alt_L) - 0x200000105: 0xffea, // AltRight (XK_Alt_R) - 0x200000106: 0xffeb, // MetaLeft (XK_Super_L) - 0x200000107: 0xffec, // MetaRight (XK_Super_R) - - // Misc - 0x20: 0x0020, // Space - 0x100000505: 0xff67, // ContextMenu (XK_Menu) - 0x100000509: 0xff13, // Pause (XK_Pause) - 0x100000608: 0xff61, // PrintScreen (XK_Print) -}; diff --git a/flutter_inappwebview_linux/lib/src/in_app_webview/main.dart b/flutter_inappwebview_linux/lib/src/in_app_webview/main.dart deleted file mode 100644 index b83b0611e7..0000000000 --- a/flutter_inappwebview_linux/lib/src/in_app_webview/main.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'in_app_webview_controller.dart' hide InternalInAppWebViewController; -export 'in_app_webview.dart'; -export 'headless_in_app_webview.dart' hide InternalHeadlessInAppWebView; diff --git a/flutter_inappwebview_linux/lib/src/inappwebview_platform.dart b/flutter_inappwebview_linux/lib/src/inappwebview_platform.dart deleted file mode 100644 index d811241d02..0000000000 --- a/flutter_inappwebview_linux/lib/src/inappwebview_platform.dart +++ /dev/null @@ -1,616 +0,0 @@ -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import 'cookie_manager/cookie_manager.dart'; -import 'find_interaction/find_interaction_controller.dart'; -import 'http_auth_credentials_database.dart'; -import 'in_app_browser/in_app_browser.dart'; -import 'in_app_webview/in_app_webview.dart'; -import 'in_app_webview/in_app_webview_controller.dart'; -import 'in_app_webview/headless_in_app_webview.dart'; -import 'proxy_controller/proxy_controller.dart'; -import 'web_message/web_message_channel.dart'; -import 'web_message/web_message_listener.dart'; -import 'web_message/web_message_port.dart'; -import 'web_storage/web_storage.dart'; -import 'web_storage/web_storage_manager.dart'; -import 'webview_environment/webview_environment.dart'; - -/// Implementation of [InAppWebViewPlatform] using WPE WebKit. -class LinuxInAppWebViewPlatform extends InAppWebViewPlatform { - /// Registers this class as the default instance of [InAppWebViewPlatform]. - static void registerWith() { - InAppWebViewPlatform.instance = LinuxInAppWebViewPlatform(); - } - - /// Creates a new [LinuxInAppWebViewController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebViewController] in `flutter_inappwebview` instead. - @override - LinuxInAppWebViewController createPlatformInAppWebViewController( - PlatformInAppWebViewControllerCreationParams params, - ) { - return LinuxInAppWebViewController(params); - } - - /// Creates a new empty [LinuxInAppWebViewController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebViewController] in `flutter_inappwebview` instead. - @override - LinuxInAppWebViewController createPlatformInAppWebViewControllerStatic() { - return LinuxInAppWebViewController.static(); - } - - /// Creates a new [LinuxInAppWebViewWidget]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebView] in `flutter_inappwebview` instead. - @override - LinuxInAppWebViewWidget createPlatformInAppWebViewWidget( - PlatformInAppWebViewWidgetCreationParams params, - ) { - return LinuxInAppWebViewWidget(params); - } - - /// Creates a new empty [LinuxInAppWebViewWidget] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebView] in `flutter_inappwebview` instead. - @override - LinuxInAppWebViewWidget createPlatformInAppWebViewWidgetStatic() { - return LinuxInAppWebViewWidget.static(); - } - - /// Creates a new empty [PlatformCookieManager] to access static methods. - @override - PlatformCookieManager createPlatformCookieManagerStatic() { - return LinuxCookieManager.static(); - } - - /// Creates a new [LinuxCookieManager]. - @override - LinuxCookieManager createPlatformCookieManager( - PlatformCookieManagerCreationParams params, - ) { - return LinuxCookieManager(params); - } - - /// Creates a new empty [PlatformWebViewEnvironment] to access static methods. - @override - PlatformWebViewEnvironment createPlatformWebViewEnvironmentStatic() { - return LinuxWebViewEnvironment.static(); - } - - /// Creates a new [LinuxWebViewEnvironment]. - @override - LinuxWebViewEnvironment createPlatformWebViewEnvironment( - PlatformWebViewEnvironmentCreationParams params, - ) { - return LinuxWebViewEnvironment(params); - } - - // ************************************************************************ // - // Create static instances of unsupported classes to be able to call // - // isClassSupported, isMethodSupported, isPropertySupported, etc. // - // static methods without throwing a missing platform implementation // - // exception. // - // ************************************************************************ // - - /// Creates a new empty [PlatformChromeSafariBrowser] to access static methods. - @override - PlatformChromeSafariBrowser createPlatformChromeSafariBrowserStatic() { - return _PlatformChromeSafariBrowser.static(); - } - - /// Creates a new [LinuxHttpAuthCredentialDatabase]. - @override - LinuxHttpAuthCredentialDatabase createPlatformHttpAuthCredentialDatabase( - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) { - return LinuxHttpAuthCredentialDatabase(params); - } - - /// Creates a new empty [LinuxHttpAuthCredentialDatabase] to access static methods. - @override - LinuxHttpAuthCredentialDatabase - createPlatformHttpAuthCredentialDatabaseStatic() { - return LinuxHttpAuthCredentialDatabase.static(); - } - - /// Creates a new empty [LinuxInAppBrowser] to access static methods. - @override - LinuxInAppBrowser createPlatformInAppBrowserStatic() { - return LinuxInAppBrowser.static(); - } - - /// Creates a new [LinuxInAppBrowser]. - @override - LinuxInAppBrowser createPlatformInAppBrowser( - PlatformInAppBrowserCreationParams params, - ) { - return LinuxInAppBrowser(params); - } - - /// Creates a new empty [PlatformHeadlessInAppWebView] to access static methods. - @override - PlatformHeadlessInAppWebView createPlatformHeadlessInAppWebViewStatic() { - return LinuxHeadlessInAppWebView.static(); - } - - /// Creates a new [LinuxHeadlessInAppWebView]. - @override - LinuxHeadlessInAppWebView createPlatformHeadlessInAppWebView( - PlatformHeadlessInAppWebViewCreationParams params, - ) { - return LinuxHeadlessInAppWebView(params); - } - - /// Creates a new empty [PlatformProcessGlobalConfig] to access static methods. - @override - PlatformProcessGlobalConfig createPlatformProcessGlobalConfigStatic() { - return _PlatformProcessGlobalConfig.static(); - } - - /// Creates a new empty [PlatformProxyController] to access static methods. - @override - PlatformProxyController createPlatformProxyControllerStatic() { - return LinuxProxyController.static(); - } - - /// Creates a new [LinuxProxyController]. - @override - LinuxProxyController createPlatformProxyController( - PlatformProxyControllerCreationParams params, - ) { - return LinuxProxyController(params); - } - - /// Creates a new empty [PlatformServiceWorkerController] to access static methods. - @override - PlatformServiceWorkerController - createPlatformServiceWorkerControllerStatic() { - return _PlatformServiceWorkerController.static(); - } - - /// Creates a new empty [PlatformTracingController] to access static methods. - @override - PlatformTracingController createPlatformTracingControllerStatic() { - return _PlatformTracingController.static(); - } - - /// Creates a new empty [PlatformFindInteractionController] to access static methods. - @override - PlatformFindInteractionController - createPlatformFindInteractionControllerStatic() { - return LinuxFindInteractionController.static(); - } - - /// Creates a new [LinuxFindInteractionController]. - @override - LinuxFindInteractionController createPlatformFindInteractionController( - PlatformFindInteractionControllerCreationParams params, - ) { - return LinuxFindInteractionController(params); - } - - /// Creates a new empty [PlatformPrintJobController] to access static methods. - @override - PlatformPrintJobController createPlatformPrintJobControllerStatic() { - return _PlatformPrintJobController.static(); - } - - /// Creates a new empty [PlatformPullToRefreshController] to access static methods. - @override - PlatformPullToRefreshController - createPlatformPullToRefreshControllerStatic() { - return _PlatformPullToRefreshController.static(); - } - - /// Creates a new empty [PlatformWebAuthenticationSession] to access static methods. - @override - PlatformWebAuthenticationSession - createPlatformWebAuthenticationSessionStatic() { - return _PlatformWebAuthenticationSession.static(); - } - - /// Creates a new empty [PlatformWebNotificationController] to access static methods. - @override - PlatformWebNotificationController - createPlatformWebNotificationControllerStatic() { - return _PlatformWebNotificationController.static(); - } - - /// Creates a new empty [LinuxWebMessageChannel] to access static methods. - @override - LinuxWebMessageChannel createPlatformWebMessageChannelStatic() { - return LinuxWebMessageChannel.static(); - } - - /// Creates a new [LinuxWebMessageChannel]. - @override - LinuxWebMessageChannel createPlatformWebMessageChannel( - PlatformWebMessageChannelCreationParams params, - ) { - return LinuxWebMessageChannel(params); - } - - /// Creates a new [LinuxWebMessagePort]. - @override - LinuxWebMessagePort createPlatformWebMessagePort( - PlatformWebMessagePortCreationParams params, - ) { - return LinuxWebMessagePort(params); - } - - /// Creates a new empty [PlatformWebMessageListener] to access static methods. - @override - PlatformWebMessageListener createPlatformWebMessageListenerStatic() { - return LinuxWebMessageListener.static(); - } - - /// Creates a new [LinuxWebMessageListener]. - @override - LinuxWebMessageListener createPlatformWebMessageListener( - PlatformWebMessageListenerCreationParams params, - ) { - return LinuxWebMessageListener(params); - } - - /// Creates a new [LinuxWebStorage]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebStorage] in `flutter_inappwebview` instead. - @override - LinuxWebStorage createPlatformWebStorage( - PlatformWebStorageCreationParams params, - ) { - return LinuxWebStorage(params); - } - - /// Creates a new empty [LinuxWebStorage] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebStorage] in `flutter_inappwebview` instead. - @override - LinuxWebStorage createPlatformWebStorageStatic() { - return LinuxWebStorage( - LinuxWebStorageCreationParams( - localStorage: createPlatformLocalStorageStatic(), - sessionStorage: createPlatformSessionStorageStatic(), - ), - ); - } - - /// Creates a new [LinuxLocalStorage]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [LocalStorage] in `flutter_inappwebview` instead. - @override - LinuxLocalStorage createPlatformLocalStorage( - PlatformLocalStorageCreationParams params, - ) { - return LinuxLocalStorage(params); - } - - /// Creates a new empty [LinuxLocalStorage] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [LocalStorage] in `flutter_inappwebview` instead. - @override - LinuxLocalStorage createPlatformLocalStorageStatic() { - return LinuxLocalStorage.defaultStorage(controller: null); - } - - /// Creates a new [LinuxSessionStorage]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [SessionStorage] in `flutter_inappwebview` instead. - @override - LinuxSessionStorage createPlatformSessionStorage( - PlatformSessionStorageCreationParams params, - ) { - return LinuxSessionStorage(params); - } - - /// Creates a new empty [LinuxSessionStorage] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [SessionStorage] in `flutter_inappwebview` instead. - @override - LinuxSessionStorage createPlatformSessionStorageStatic() { - return LinuxSessionStorage.defaultStorage(controller: null); - } - - /// Creates a new empty [PlatformWebStorageManager] to access static methods. - @override - PlatformWebStorageManager createPlatformWebStorageManagerStatic() { - return LinuxWebStorageManager.static(); - } - - /// Creates a new [LinuxWebStorageManager]. - @override - LinuxWebStorageManager createPlatformWebStorageManager( - PlatformWebStorageManagerCreationParams params, - ) { - return LinuxWebStorageManager(params); - } - - /// Creates a new empty [PlatformAssetsPathHandler] to access static methods. - @override - PlatformAssetsPathHandler createPlatformAssetsPathHandlerStatic() { - return _PlatformAssetsPathHandler.static(); - } - - /// Creates a new empty [PlatformResourcesPathHandler] to access static methods. - @override - PlatformResourcesPathHandler createPlatformResourcesPathHandlerStatic() { - return _PlatformResourcesPathHandler.static(); - } - - /// Creates a new empty [PlatformInternalStoragePathHandler] to access static methods. - @override - PlatformInternalStoragePathHandler - createPlatformInternalStoragePathHandlerStatic() { - return _PlatformInternalStoragePathHandler.static(); - } - - /// Creates a new empty [PlatformCustomPathHandler] to access static methods. - @override - PlatformCustomPathHandler createPlatformCustomPathHandlerStatic() { - return _PlatformCustomPathHandler.static(); - } - - /// Creates a new [DefaultInAppLocalhostServer]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppLocalhostServer] in `flutter_inappwebview` instead. - @override - DefaultInAppLocalhostServer createPlatformInAppLocalhostServer( - PlatformInAppLocalhostServerCreationParams params, - ) { - return DefaultInAppLocalhostServer(params); - } - - /// Creates a new empty [DefaultInAppLocalhostServer] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppLocalhostServer] in `flutter_inappwebview` instead. - @override - DefaultInAppLocalhostServer createPlatformInAppLocalhostServerStatic() { - return DefaultInAppLocalhostServer.static(); - } - - /// Creates a new empty [PlatformWebViewFeature] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebViewFeature] in `flutter_inappwebview` instead - @override - PlatformWebViewFeature createPlatformWebViewFeatureStatic() { - return _PlatformWebViewFeature.static(); - } -} - -// Stub implementations for unsupported classes - -class _PlatformChromeSafariBrowser extends PlatformChromeSafariBrowser { - _PlatformChromeSafariBrowser(PlatformChromeSafariBrowserCreationParams params) - : super.implementation(params); - static final _PlatformChromeSafariBrowser _staticValue = - _PlatformChromeSafariBrowser( - const PlatformChromeSafariBrowserCreationParams(), - ); - - factory _PlatformChromeSafariBrowser.static() => _staticValue; -} - -class _PlatformProcessGlobalConfig extends PlatformProcessGlobalConfig { - _PlatformProcessGlobalConfig(PlatformProcessGlobalConfigCreationParams params) - : super.implementation(params); - static final _PlatformProcessGlobalConfig _staticValue = - _PlatformProcessGlobalConfig( - const PlatformProcessGlobalConfigCreationParams(), - ); - - factory _PlatformProcessGlobalConfig.static() => _staticValue; -} - -class _PlatformServiceWorkerController extends PlatformServiceWorkerController { - _PlatformServiceWorkerController( - PlatformServiceWorkerControllerCreationParams params, - ) : super.implementation(params); - static final _PlatformServiceWorkerController _staticValue = - _PlatformServiceWorkerController( - const PlatformServiceWorkerControllerCreationParams(), - ); - - factory _PlatformServiceWorkerController.static() => _staticValue; - - @override - ServiceWorkerClient? get serviceWorkerClient => throw UnimplementedError(); -} - -class _PlatformTracingController extends PlatformTracingController { - _PlatformTracingController(PlatformTracingControllerCreationParams params) - : super.implementation(params); - static final _PlatformTracingController _staticValue = - _PlatformTracingController( - const PlatformTracingControllerCreationParams(), - ); - - factory _PlatformTracingController.static() => _staticValue; -} - -class _PlatformPrintJobController extends PlatformPrintJobController { - _PlatformPrintJobController(PlatformPrintJobControllerCreationParams params) - : super.implementation(params); - - static final _PlatformPrintJobController _staticValue = - _PlatformPrintJobController( - const PlatformPrintJobControllerCreationParams(id: ''), - ); - - factory _PlatformPrintJobController.static() => _staticValue; -} - -class _PlatformPullToRefreshController extends PlatformPullToRefreshController { - _PlatformPullToRefreshController( - PlatformPullToRefreshControllerCreationParams params, - ) : super.implementation(params); - - static final _PlatformPullToRefreshController _staticValue = - _PlatformPullToRefreshController( - PlatformPullToRefreshControllerCreationParams(), - ); - - factory _PlatformPullToRefreshController.static() => _staticValue; -} - -class _PlatformWebAuthenticationSession - extends PlatformWebAuthenticationSession { - _PlatformWebAuthenticationSession( - PlatformWebAuthenticationSessionCreationParams params, - ) : super.implementation(params); - - static final _PlatformWebAuthenticationSession _staticValue = - _PlatformWebAuthenticationSession( - const PlatformWebAuthenticationSessionCreationParams(), - ); - - factory _PlatformWebAuthenticationSession.static() => _staticValue; -} - -class _PlatformWebNotificationController - extends PlatformWebNotificationController { - _PlatformWebNotificationController( - PlatformWebNotificationControllerCreationParams params, - ) : super.implementation(params); - - static final _PlatformWebNotificationController _staticValue = - _PlatformWebNotificationController( - PlatformWebNotificationControllerCreationParams( - id: '', - notification: WebNotification(), - ), - ); - - factory _PlatformWebNotificationController.static() => _staticValue; -} - -class _PlatformWebViewFeature extends PlatformWebViewFeature { - _PlatformWebViewFeature(PlatformWebViewFeatureCreationParams params) - : super.implementation(params); - - static final _PlatformWebViewFeature _staticValue = _PlatformWebViewFeature( - PlatformWebViewFeatureCreationParams(), - ); - factory _PlatformWebViewFeature.static() => _staticValue; -} - -class _PlatformAssetsPathHandler extends PlatformAssetsPathHandler { - _PlatformAssetsPathHandler(PlatformAssetsPathHandlerCreationParams params) - : super.implementation(params); - - static final _PlatformAssetsPathHandler _staticValue = - _PlatformAssetsPathHandler( - PlatformAssetsPathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - ), - ); - - factory _PlatformAssetsPathHandler.static() => _staticValue; - - @override - PlatformPathHandlerEvents? eventHandler; - - @override - Map toMap({EnumMethod? enumMethod}) => { - "path": path, - "type": type, - }; - - @override - Map toJson() => toMap(); -} - -class _PlatformResourcesPathHandler extends PlatformResourcesPathHandler { - _PlatformResourcesPathHandler( - PlatformResourcesPathHandlerCreationParams params, - ) : super.implementation(params); - - static final _PlatformResourcesPathHandler _staticValue = - _PlatformResourcesPathHandler( - PlatformResourcesPathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - ), - ); - - factory _PlatformResourcesPathHandler.static() => _staticValue; - - @override - PlatformPathHandlerEvents? eventHandler; - - @override - Map toMap({EnumMethod? enumMethod}) => { - "path": path, - "type": type, - }; - - @override - Map toJson() => toMap(); -} - -class _PlatformInternalStoragePathHandler - extends PlatformInternalStoragePathHandler { - _PlatformInternalStoragePathHandler( - PlatformInternalStoragePathHandlerCreationParams params, - ) : super.implementation(params); - - static final _PlatformInternalStoragePathHandler _staticValue = - _PlatformInternalStoragePathHandler( - PlatformInternalStoragePathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - directory: '', - ), - ); - - factory _PlatformInternalStoragePathHandler.static() => _staticValue; - - @override - PlatformPathHandlerEvents? eventHandler; - - @override - Map toMap({EnumMethod? enumMethod}) => { - "path": path, - "type": type, - }; - - @override - Map toJson() => toMap(); -} - -class _PlatformCustomPathHandler extends PlatformCustomPathHandler { - _PlatformCustomPathHandler(PlatformCustomPathHandlerCreationParams params) - : super.implementation(params); - - static final _PlatformCustomPathHandler _staticValue = - _PlatformCustomPathHandler( - PlatformCustomPathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - ), - ); - - factory _PlatformCustomPathHandler.static() => _staticValue; - - @override - PlatformPathHandlerEvents? eventHandler; - - @override - Map toMap({EnumMethod? enumMethod}) => { - "path": path, - "type": type, - }; - - @override - Map toJson() => toMap(); -} diff --git a/flutter_inappwebview_linux/lib/src/main.dart b/flutter_inappwebview_linux/lib/src/main.dart deleted file mode 100644 index 3528f2fac6..0000000000 --- a/flutter_inappwebview_linux/lib/src/main.dart +++ /dev/null @@ -1,10 +0,0 @@ -export 'inappwebview_platform.dart'; -export 'cookie_manager/main.dart'; -export 'find_interaction/main.dart'; -export 'http_auth_credentials_database.dart'; -export 'in_app_browser/main.dart'; -export 'in_app_webview/main.dart'; -export 'proxy_controller/proxy_controller.dart'; -export 'web_message/main.dart'; -export 'web_storage/main.dart'; -export 'webview_environment/main.dart'; diff --git a/flutter_inappwebview_linux/lib/src/proxy_controller/proxy_controller.dart b/flutter_inappwebview_linux/lib/src/proxy_controller/proxy_controller.dart deleted file mode 100644 index 3956cf0655..0000000000 --- a/flutter_inappwebview_linux/lib/src/proxy_controller/proxy_controller.dart +++ /dev/null @@ -1,86 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [LinuxProxyController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformProxyControllerCreationParams] for -/// more information. -@immutable -class LinuxProxyControllerCreationParams - extends PlatformProxyControllerCreationParams { - /// Creates a new [LinuxProxyControllerCreationParams] instance. - const LinuxProxyControllerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformProxyControllerCreationParams params, - ) : super(); - - /// Creates a [LinuxProxyControllerCreationParams] instance based on [PlatformProxyControllerCreationParams]. - factory LinuxProxyControllerCreationParams.fromPlatformProxyControllerCreationParams( - PlatformProxyControllerCreationParams params, - ) { - return LinuxProxyControllerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformProxyController} -/// -/// Linux implementation of [PlatformProxyController] using WPE WebKit's -/// [WebKitNetworkProxySettings](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/struct.NetworkProxySettings.html). -class LinuxProxyController extends PlatformProxyController { - static const MethodChannel _channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_proxycontroller', - ); - - /// Creates a new [LinuxProxyController]. - LinuxProxyController(PlatformProxyControllerCreationParams params) - : super.implementation( - params is LinuxProxyControllerCreationParams - ? params - : LinuxProxyControllerCreationParams.fromPlatformProxyControllerCreationParams( - params, - ), - ); - - static LinuxProxyController? _instance; - - /// Gets the [LinuxProxyController] shared instance. - static LinuxProxyController instance() { - return (_instance != null) ? _instance! : _init(); - } - - static LinuxProxyController _init() { - _instance = LinuxProxyController( - LinuxProxyControllerCreationParams( - const PlatformProxyControllerCreationParams(), - ), - ); - return _instance!; - } - - static final LinuxProxyController _staticValue = LinuxProxyController( - LinuxProxyControllerCreationParams( - const PlatformProxyControllerCreationParams(), - ), - ); - - /// Provide static access. - factory LinuxProxyController.static() { - return _staticValue; - } - - @override - Future setProxyOverride({required ProxySettings settings}) async { - Map args = {}; - args.putIfAbsent("settings", () => settings.toMap()); - await _channel.invokeMethod('setProxyOverride', args); - } - - @override - Future clearProxyOverride() async { - Map args = {}; - await _channel.invokeMethod('clearProxyOverride', args); - } -} diff --git a/flutter_inappwebview_linux/lib/src/web_message/main.dart b/flutter_inappwebview_linux/lib/src/web_message/main.dart deleted file mode 100644 index 5be15cbd4f..0000000000 --- a/flutter_inappwebview_linux/lib/src/web_message/main.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'web_message_channel.dart' hide InternalWebMessageChannel; -export 'web_message_listener.dart'; -export 'web_message_port.dart' hide InternalWebMessagePort; diff --git a/flutter_inappwebview_linux/lib/src/web_message/web_message_channel.dart b/flutter_inappwebview_linux/lib/src/web_message/web_message_channel.dart deleted file mode 100644 index dacfd1baac..0000000000 --- a/flutter_inappwebview_linux/lib/src/web_message/web_message_channel.dart +++ /dev/null @@ -1,130 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import 'web_message_port.dart'; - -/// Object specifying creation parameters for creating a [LinuxWebMessageChannel]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebMessageChannelCreationParams] for -/// more information. -@immutable -class LinuxWebMessageChannelCreationParams - extends PlatformWebMessageChannelCreationParams { - /// Creates a new [LinuxWebMessageChannelCreationParams] instance. - const LinuxWebMessageChannelCreationParams({ - required super.id, - required super.port1, - required super.port2, - }); - - /// Creates a [LinuxWebMessageChannelCreationParams] instance based on [PlatformWebMessageChannelCreationParams]. - factory LinuxWebMessageChannelCreationParams.fromPlatformWebMessageChannelCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebMessageChannelCreationParams params, - ) { - return LinuxWebMessageChannelCreationParams( - id: params.id, - port1: params.port1, - port2: params.port2, - ); - } - - @override - String toString() { - return 'LinuxWebMessageChannelCreationParams{id: $id, port1: $port1, port2: $port2}'; - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel} -class LinuxWebMessageChannel extends PlatformWebMessageChannel - with ChannelController { - /// Constructs a [LinuxWebMessageChannel]. - LinuxWebMessageChannel(PlatformWebMessageChannelCreationParams params) - : super.implementation( - params is LinuxWebMessageChannelCreationParams - ? params - : LinuxWebMessageChannelCreationParams.fromPlatformWebMessageChannelCreationParams( - params, - ), - ) { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_web_message_channel_${params.id}', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - static final LinuxWebMessageChannel _staticValue = LinuxWebMessageChannel( - LinuxWebMessageChannelCreationParams( - id: '', - port1: LinuxWebMessagePort(LinuxWebMessagePortCreationParams(index: 0)), - port2: LinuxWebMessagePort(LinuxWebMessagePortCreationParams(index: 1)), - ), - ); - - /// Provide static access. - factory LinuxWebMessageChannel.static() { - return _staticValue; - } - - LinuxWebMessagePort get _linuxPort1 => port1 as LinuxWebMessagePort; - - LinuxWebMessagePort get _linuxPort2 => port2 as LinuxWebMessagePort; - - static LinuxWebMessageChannel? _fromMap(Map? map) { - if (map == null) { - return null; - } - var webMessageChannel = LinuxWebMessageChannel( - LinuxWebMessageChannelCreationParams( - id: map["id"], - port1: LinuxWebMessagePort(LinuxWebMessagePortCreationParams(index: 0)), - port2: LinuxWebMessagePort(LinuxWebMessagePortCreationParams(index: 1)), - ), - ); - webMessageChannel._linuxPort1.webMessageChannel = webMessageChannel; - webMessageChannel._linuxPort2.webMessageChannel = webMessageChannel; - return webMessageChannel; - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onMessage": - int index = call.arguments["index"]; - var port = index == 0 ? _linuxPort1 : _linuxPort2; - if (port.onMessage != null) { - WebMessage? message = call.arguments["message"] != null - ? WebMessage.fromMap( - call.arguments["message"].cast(), - ) - : null; - port.onMessage!(message); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - LinuxWebMessageChannel? fromMap(Map? map) { - return _fromMap(map); - } - - @override - void dispose() { - disposeChannel(); - } - - @override - String toString() { - return 'LinuxWebMessageChannel{id: $id, port1: $port1, port2: $port2}'; - } -} - -extension InternalWebMessageChannel on LinuxWebMessageChannel { - MethodChannel? get internalChannel => channel; -} diff --git a/flutter_inappwebview_linux/lib/src/web_message/web_message_listener.dart b/flutter_inappwebview_linux/lib/src/web_message/web_message_listener.dart deleted file mode 100644 index 8806b7cf07..0000000000 --- a/flutter_inappwebview_linux/lib/src/web_message/web_message_listener.dart +++ /dev/null @@ -1,186 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [LinuxWebMessageListener]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebMessageListenerCreationParams] for -/// more information. -@immutable -class LinuxWebMessageListenerCreationParams - extends PlatformWebMessageListenerCreationParams { - /// Creates a new [LinuxWebMessageListenerCreationParams] instance. - const LinuxWebMessageListenerCreationParams({ - required this.allowedOriginRules, - required super.jsObjectName, - super.onPostMessage, - }); - - /// Creates a [LinuxWebMessageListenerCreationParams] instance based on [PlatformWebMessageListenerCreationParams]. - factory LinuxWebMessageListenerCreationParams.fromPlatformWebMessageListenerCreationParams( - PlatformWebMessageListenerCreationParams params, - ) { - return LinuxWebMessageListenerCreationParams( - allowedOriginRules: params.allowedOriginRules ?? Set.from(["*"]), - jsObjectName: params.jsObjectName, - onPostMessage: params.onPostMessage, - ); - } - - @override - final Set allowedOriginRules; - - @override - String toString() { - return 'LinuxWebMessageListenerCreationParams{jsObjectName: $jsObjectName, allowedOriginRules: $allowedOriginRules, onPostMessage: $onPostMessage}'; - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener} -class LinuxWebMessageListener extends PlatformWebMessageListener - with ChannelController { - /// Constructs a [LinuxWebMessageListener]. - LinuxWebMessageListener(PlatformWebMessageListenerCreationParams params) - : super.implementation( - params is LinuxWebMessageListenerCreationParams - ? params - : LinuxWebMessageListenerCreationParams.fromPlatformWebMessageListenerCreationParams( - params, - ), - ) { - assert( - !this._linuxParams.allowedOriginRules.contains(""), - "allowedOriginRules cannot contain empty strings", - ); - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_web_message_listener_${_id}_${params.jsObjectName}', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - static final LinuxWebMessageListener _staticValue = LinuxWebMessageListener( - LinuxWebMessageListenerCreationParams( - jsObjectName: '', - allowedOriginRules: Set.from(["*"]), - ), - ); - - /// Provide static access. - factory LinuxWebMessageListener.static() { - return _staticValue; - } - - ///Message Listener ID used internally. - final String _id = IdGenerator.generate(); - - LinuxJavaScriptReplyProxy? _replyProxy; - - LinuxWebMessageListenerCreationParams get _linuxParams => - params as LinuxWebMessageListenerCreationParams; - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onPostMessage": - if (_replyProxy == null) { - _replyProxy = LinuxJavaScriptReplyProxy( - PlatformJavaScriptReplyProxyCreationParams( - webMessageListener: this, - ), - ); - } - if (onPostMessage != null) { - WebMessage? message = call.arguments["message"] != null - ? WebMessage.fromMap( - call.arguments["message"].cast(), - ) - : null; - WebUri? sourceOrigin = call.arguments["sourceOrigin"] != null - ? WebUri(call.arguments["sourceOrigin"]) - : null; - bool isMainFrame = call.arguments["isMainFrame"]; - onPostMessage!(message, sourceOrigin, isMainFrame, _replyProxy!); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - void dispose() { - disposeChannel(); - } - - @override - Map toMap() { - return { - "id": _id, - "jsObjectName": params.jsObjectName, - "allowedOriginRules": _linuxParams.allowedOriginRules.toList(), - }; - } - - @override - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return 'LinuxWebMessageListener{id: ${_id}, jsObjectName: ${params.jsObjectName}, allowedOriginRules: ${params.allowedOriginRules}, replyProxy: $_replyProxy}'; - } -} - -/// Object specifying creation parameters for creating a [LinuxJavaScriptReplyProxy]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformJavaScriptReplyProxyCreationParams] for -/// more information. -@immutable -class LinuxJavaScriptReplyProxyCreationParams - extends PlatformJavaScriptReplyProxyCreationParams { - /// Creates a new [LinuxJavaScriptReplyProxyCreationParams] instance. - const LinuxJavaScriptReplyProxyCreationParams({ - required super.webMessageListener, - }); - - /// Creates a [LinuxJavaScriptReplyProxyCreationParams] instance based on [PlatformJavaScriptReplyProxyCreationParams]. - factory LinuxJavaScriptReplyProxyCreationParams.fromPlatformJavaScriptReplyProxyCreationParams( - PlatformJavaScriptReplyProxyCreationParams params, - ) { - return LinuxJavaScriptReplyProxyCreationParams( - webMessageListener: params.webMessageListener, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.JavaScriptReplyProxy} -class LinuxJavaScriptReplyProxy extends PlatformJavaScriptReplyProxy { - /// Constructs a [LinuxWebMessageListener]. - LinuxJavaScriptReplyProxy(PlatformJavaScriptReplyProxyCreationParams params) - : super.implementation( - params is LinuxJavaScriptReplyProxyCreationParams - ? params - : LinuxJavaScriptReplyProxyCreationParams.fromPlatformJavaScriptReplyProxyCreationParams( - params, - ), - ); - - LinuxWebMessageListener get _linuxWebMessageListener => - params.webMessageListener as LinuxWebMessageListener; - - @override - Future postMessage(WebMessage message) async { - Map args = {}; - args.putIfAbsent('message', () => message.toMap()); - await _linuxWebMessageListener.channel?.invokeMethod('postMessage', args); - } - - @override - String toString() { - return 'LinuxJavaScriptReplyProxy{}'; - } -} diff --git a/flutter_inappwebview_linux/lib/src/web_message/web_message_port.dart b/flutter_inappwebview_linux/lib/src/web_message/web_message_port.dart deleted file mode 100644 index ebdad3e4ca..0000000000 --- a/flutter_inappwebview_linux/lib/src/web_message/web_message_port.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import 'web_message_channel.dart'; - -/// Object specifying creation parameters for creating a [LinuxWebMessagePort]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebMessagePortCreationParams] for -/// more information. -@immutable -class LinuxWebMessagePortCreationParams - extends PlatformWebMessagePortCreationParams { - /// Creates a new [LinuxWebMessagePortCreationParams] instance. - const LinuxWebMessagePortCreationParams({required super.index}); - - /// Creates a [LinuxWebMessagePortCreationParams] instance based on [PlatformWebMessagePortCreationParams]. - factory LinuxWebMessagePortCreationParams.fromPlatformWebMessagePortCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebMessagePortCreationParams params, - ) { - return LinuxWebMessagePortCreationParams(index: params.index); - } - - @override - String toString() { - return 'LinuxWebMessagePortCreationParams{index: $index}'; - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessagePort} -class LinuxWebMessagePort extends PlatformWebMessagePort { - WebMessageCallback? _onMessage; - late LinuxWebMessageChannel _webMessageChannel; - - /// Constructs a [LinuxWebMessagePort]. - LinuxWebMessagePort(PlatformWebMessagePortCreationParams params) - : super.implementation( - params is LinuxWebMessagePortCreationParams - ? params - : LinuxWebMessagePortCreationParams.fromPlatformWebMessagePortCreationParams( - params, - ), - ); - - @override - Future setWebMessageCallback(WebMessageCallback? onMessage) async { - Map args = {}; - args.putIfAbsent('index', () => params.index); - await _webMessageChannel.internalChannel?.invokeMethod( - 'setWebMessageCallback', - args, - ); - _onMessage = onMessage; - } - - @override - Future postMessage(WebMessage message) async { - Map args = {}; - args.putIfAbsent('index', () => params.index); - args.putIfAbsent('message', () => message.toMap()); - await _webMessageChannel.internalChannel?.invokeMethod('postMessage', args); - } - - @override - Future close() async { - Map args = {}; - args.putIfAbsent('index', () => params.index); - await _webMessageChannel.internalChannel?.invokeMethod('close', args); - } - - @override - Map toMap({EnumMethod? enumMethod}) { - return { - "index": params.index, - "webMessageChannelId": _webMessageChannel.params.id, - }; - } - - @override - Map toJson() { - return toMap(); - } - - @override - String toString() { - return 'LinuxWebMessagePort{index: ${params.index}}'; - } -} - -extension InternalWebMessagePort on LinuxWebMessagePort { - WebMessageCallback? get onMessage => _onMessage; - set onMessage(WebMessageCallback? value) => _onMessage = value; - - LinuxWebMessageChannel get webMessageChannel => _webMessageChannel; - set webMessageChannel(LinuxWebMessageChannel value) => - _webMessageChannel = value; -} diff --git a/flutter_inappwebview_linux/lib/src/web_storage/main.dart b/flutter_inappwebview_linux/lib/src/web_storage/main.dart deleted file mode 100644 index dab327ba6d..0000000000 --- a/flutter_inappwebview_linux/lib/src/web_storage/main.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'web_storage.dart'; -export 'web_storage_manager.dart'; diff --git a/flutter_inappwebview_linux/lib/src/web_storage/web_storage.dart b/flutter_inappwebview_linux/lib/src/web_storage/web_storage.dart deleted file mode 100644 index d44d072afe..0000000000 --- a/flutter_inappwebview_linux/lib/src/web_storage/web_storage.dart +++ /dev/null @@ -1,305 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../in_app_webview/in_app_webview_controller.dart'; - -/// Object specifying creation parameters for creating a [LinuxWebStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebStorageCreationParams] for -/// more information. -class LinuxWebStorageCreationParams extends PlatformWebStorageCreationParams { - /// Creates a new [LinuxWebStorageCreationParams] instance. - LinuxWebStorageCreationParams({ - required super.localStorage, - required super.sessionStorage, - }); - - /// Creates a [LinuxWebStorageCreationParams] instance based on [PlatformWebStorageCreationParams]. - factory LinuxWebStorageCreationParams.fromPlatformWebStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebStorageCreationParams params, - ) { - return LinuxWebStorageCreationParams( - localStorage: params.localStorage, - sessionStorage: params.sessionStorage, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage} -class LinuxWebStorage extends PlatformWebStorage { - /// Constructs a [LinuxWebStorage]. - LinuxWebStorage(PlatformWebStorageCreationParams params) - : super.implementation( - params is LinuxWebStorageCreationParams - ? params - : LinuxWebStorageCreationParams.fromPlatformWebStorageCreationParams( - params, - ), - ); - - @override - PlatformLocalStorage get localStorage => params.localStorage; - - @override - PlatformSessionStorage get sessionStorage => params.sessionStorage; - - @override - void dispose() { - localStorage.dispose(); - sessionStorage.dispose(); - } -} - -/// Object specifying creation parameters for creating a [LinuxStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformStorageCreationParams] for -/// more information. -class LinuxStorageCreationParams extends PlatformStorageCreationParams { - /// Creates a new [LinuxStorageCreationParams] instance. - LinuxStorageCreationParams({ - required super.controller, - required super.webStorageType, - }); - - /// Creates a [LinuxStorageCreationParams] instance based on [PlatformStorageCreationParams]. - factory LinuxStorageCreationParams.fromPlatformStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformStorageCreationParams params, - ) { - return LinuxStorageCreationParams( - controller: params.controller, - webStorageType: params.webStorageType, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformStorage} -abstract mixin class LinuxStorage implements PlatformStorage { - @override - LinuxInAppWebViewController? controller; - - @override - Future length() async { - var result = await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.length; - """, - ); - return result != null ? int.parse(json.decode(result)) : null; - } - - @override - Future setItem({required String key, required dynamic value}) async { - var encodedValue = json.encode(value); - await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.setItem("$key", ${value is String ? encodedValue : "JSON.stringify($encodedValue)"}); - """, - ); - } - - @override - Future getItem({required String key}) async { - var itemValue = await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.getItem("$key"); - """, - ); - - if (itemValue == null) { - return null; - } - - try { - return json.decode(itemValue); - } catch (e) {} - - return itemValue; - } - - @override - Future removeItem({required String key}) async { - await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.removeItem("$key"); - """, - ); - } - - @override - Future> getItems() async { - var webStorageItems = []; - - List>? items = (await controller?.evaluateJavascript( - source: - """ -(function() { - var webStorageItems = []; - for(var i = 0; i < window.$webStorageType.length; i++){ - var key = window.$webStorageType.key(i); - webStorageItems.push( - { - key: key, - value: window.$webStorageType.getItem(key) - } - ); - } - return webStorageItems; -})(); - """, - ))?.cast>(); - - if (items == null) { - return webStorageItems; - } - - for (var item in items) { - webStorageItems.add( - WebStorageItem(key: item["key"], value: item["value"]), - ); - } - - return webStorageItems; - } - - @override - Future clear() async { - await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.clear(); - """, - ); - } - - @override - Future key({required int index}) async { - var result = await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.key($index); - """, - ); - return result != null ? json.decode(result) : null; - } - - @override - void dispose() { - controller = null; - } -} - -/// Object specifying creation parameters for creating a [LinuxLocalStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformLocalStorageCreationParams] for -/// more information. -class LinuxLocalStorageCreationParams extends PlatformLocalStorageCreationParams { - /// Creates a new [LinuxLocalStorageCreationParams] instance. - LinuxLocalStorageCreationParams(super.params); - - /// Creates a [LinuxLocalStorageCreationParams] instance based on [PlatformLocalStorageCreationParams]. - factory LinuxLocalStorageCreationParams.fromPlatformLocalStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformLocalStorageCreationParams params, - ) { - return LinuxLocalStorageCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformLocalStorage} -class LinuxLocalStorage extends PlatformLocalStorage with LinuxStorage { - /// Constructs a [LinuxLocalStorage]. - LinuxLocalStorage(PlatformLocalStorageCreationParams params) - : super.implementation( - params is LinuxLocalStorageCreationParams - ? params - : LinuxLocalStorageCreationParams.fromPlatformLocalStorageCreationParams( - params, - ), - ); - - /// Default storage - factory LinuxLocalStorage.defaultStorage({ - required PlatformInAppWebViewController? controller, - }) { - return LinuxLocalStorage( - LinuxLocalStorageCreationParams( - PlatformLocalStorageCreationParams( - PlatformStorageCreationParams( - controller: controller, - webStorageType: WebStorageType.LOCAL_STORAGE, - ), - ), - ), - ); - } - - @override - LinuxInAppWebViewController? get controller => - params.controller as LinuxInAppWebViewController?; -} - -/// Object specifying creation parameters for creating a [LinuxSessionStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformSessionStorageCreationParams] for -/// more information. -class LinuxSessionStorageCreationParams - extends PlatformSessionStorageCreationParams { - /// Creates a new [LinuxSessionStorageCreationParams] instance. - LinuxSessionStorageCreationParams(super.params); - - /// Creates a [LinuxSessionStorageCreationParams] instance based on [PlatformSessionStorageCreationParams]. - factory LinuxSessionStorageCreationParams.fromPlatformSessionStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformSessionStorageCreationParams params, - ) { - return LinuxSessionStorageCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformSessionStorage} -class LinuxSessionStorage extends PlatformSessionStorage with LinuxStorage { - /// Constructs a [LinuxSessionStorage]. - LinuxSessionStorage(PlatformSessionStorageCreationParams params) - : super.implementation( - params is LinuxSessionStorageCreationParams - ? params - : LinuxSessionStorageCreationParams.fromPlatformSessionStorageCreationParams( - params, - ), - ); - - /// Default storage - factory LinuxSessionStorage.defaultStorage({ - required PlatformInAppWebViewController? controller, - }) { - return LinuxSessionStorage( - LinuxSessionStorageCreationParams( - PlatformSessionStorageCreationParams( - PlatformStorageCreationParams( - controller: controller, - webStorageType: WebStorageType.SESSION_STORAGE, - ), - ), - ), - ); - } - - @override - LinuxInAppWebViewController? get controller => - params.controller as LinuxInAppWebViewController?; -} diff --git a/flutter_inappwebview_linux/lib/src/web_storage/web_storage_manager.dart b/flutter_inappwebview_linux/lib/src/web_storage/web_storage_manager.dart deleted file mode 100644 index 80b41c098e..0000000000 --- a/flutter_inappwebview_linux/lib/src/web_storage/web_storage_manager.dart +++ /dev/null @@ -1,183 +0,0 @@ -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [LinuxWebStorageManager]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebStorageManagerCreationParams] for -/// more information. -class LinuxWebStorageManagerCreationParams - extends PlatformWebStorageManagerCreationParams { - /// Creates a new [LinuxWebStorageManagerCreationParams] instance. - const LinuxWebStorageManagerCreationParams(); - - /// Creates a [LinuxWebStorageManagerCreationParams] instance based on [PlatformWebStorageManagerCreationParams]. - factory LinuxWebStorageManagerCreationParams.fromPlatformWebStorageManagerCreationParams( - PlatformWebStorageManagerCreationParams params, - ) { - return const LinuxWebStorageManagerCreationParams(); - } -} - -/// Implementation of [PlatformWebStorageManager] for Linux using WPE WebKit. -/// -/// Uses [WebKitWebsiteDataManager](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/class.WebsiteDataManager.html) -/// to manage website data. -class LinuxWebStorageManager extends PlatformWebStorageManager { - static const MethodChannel _channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_webstoragemanager', - ); - - /// Constructs a [LinuxWebStorageManager]. - LinuxWebStorageManager(PlatformWebStorageManagerCreationParams params) - : super.implementation( - params is LinuxWebStorageManagerCreationParams - ? params - : LinuxWebStorageManagerCreationParams.fromPlatformWebStorageManagerCreationParams( - params, - ), - ); - - static final LinuxWebStorageManager _instance = LinuxWebStorageManager( - const LinuxWebStorageManagerCreationParams(), - ); - - /// The [LinuxWebStorageManager] singleton instance. - static LinuxWebStorageManager instance() => _instance; - - /// Creates and returns a new [LinuxWebStorageManager] for static methods. - factory LinuxWebStorageManager.static() => _instance; - - /// Maps WebsiteDataType to WPE WebKit data type strings. - static String _toWpeDataType(WebsiteDataType type) { - if (type == WebsiteDataType.WKWebsiteDataTypeDiskCache) { - return 'WEBKIT_WEBSITE_DATA_DISK_CACHE'; - } else if (type == WebsiteDataType.WKWebsiteDataTypeMemoryCache) { - return 'WEBKIT_WEBSITE_DATA_MEMORY_CACHE'; - } else if (type == - WebsiteDataType.WKWebsiteDataTypeOfflineWebApplicationCache) { - return 'WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE'; - } else if (type == WebsiteDataType.WKWebsiteDataTypeCookies) { - return 'WEBKIT_WEBSITE_DATA_COOKIES'; - } else if (type == WebsiteDataType.WKWebsiteDataTypeSessionStorage) { - return 'WEBKIT_WEBSITE_DATA_SESSION_STORAGE'; - } else if (type == WebsiteDataType.WKWebsiteDataTypeLocalStorage) { - return 'WEBKIT_WEBSITE_DATA_LOCAL_STORAGE'; - } else if (type == WebsiteDataType.WKWebsiteDataTypeIndexedDBDatabases) { - return 'WEBKIT_WEBSITE_DATA_INDEXEDDB_DATABASES'; - } else if (type == - WebsiteDataType.WKWebsiteDataTypeServiceWorkerRegistrations) { - return 'WEBKIT_WEBSITE_DATA_SERVICE_WORKER_REGISTRATIONS'; - } else if (type == WebsiteDataType.WKWebsiteDataTypeFetchCache) { - // WPE uses same as disk cache for fetch cache - return 'WEBKIT_WEBSITE_DATA_DISK_CACHE'; - } else if (type == WebsiteDataType.WKWebsiteDataTypeWebSQLDatabases) { - // WebSQL is deprecated, map to local storage - return 'WEBKIT_WEBSITE_DATA_LOCAL_STORAGE'; - } - // Default fallback - return 'WEBKIT_WEBSITE_DATA_LOCAL_STORAGE'; - } - - /// Maps WPE WebKit data type string to WebsiteDataType. - static WebsiteDataType? _fromWpeDataType(String wpeType) { - if (wpeType == 'WEBKIT_WEBSITE_DATA_DISK_CACHE') { - return WebsiteDataType.WKWebsiteDataTypeDiskCache; - } else if (wpeType == 'WEBKIT_WEBSITE_DATA_MEMORY_CACHE') { - return WebsiteDataType.WKWebsiteDataTypeMemoryCache; - } else if (wpeType == 'WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE') { - return WebsiteDataType.WKWebsiteDataTypeOfflineWebApplicationCache; - } else if (wpeType == 'WEBKIT_WEBSITE_DATA_COOKIES') { - return WebsiteDataType.WKWebsiteDataTypeCookies; - } else if (wpeType == 'WEBKIT_WEBSITE_DATA_SESSION_STORAGE') { - return WebsiteDataType.WKWebsiteDataTypeSessionStorage; - } else if (wpeType == 'WEBKIT_WEBSITE_DATA_LOCAL_STORAGE') { - return WebsiteDataType.WKWebsiteDataTypeLocalStorage; - } else if (wpeType == 'WEBKIT_WEBSITE_DATA_INDEXEDDB_DATABASES') { - return WebsiteDataType.WKWebsiteDataTypeIndexedDBDatabases; - } else if (wpeType == 'WEBKIT_WEBSITE_DATA_SERVICE_WORKER_REGISTRATIONS') { - return WebsiteDataType.WKWebsiteDataTypeServiceWorkerRegistrations; - } - return null; - } - - @override - Future> fetchDataRecords({ - required Set dataTypes, - }) async { - final List wpeDataTypes = dataTypes - .map((type) => _toWpeDataType(type)) - .toList(); - - final result = await _channel.invokeMethod>( - 'fetchDataRecords', - {'dataTypes': wpeDataTypes}, - ); - - if (result == null) { - return []; - } - - return result.cast>().map((recordMap) { - final String? displayName = recordMap['displayName'] as String?; - final List? dataTypesRaw = - recordMap['dataTypes'] as List?; - - Set? dataTypesSet; - if (dataTypesRaw != null) { - dataTypesSet = dataTypesRaw - .cast() - .map((typeStr) => _fromWpeDataType(typeStr)) - .whereType() - .toSet(); - } - - return WebsiteDataRecord( - displayName: displayName, - dataTypes: dataTypesSet, - ); - }).toList(); - } - - @override - Future removeDataFor({ - required Set dataTypes, - required List dataRecords, - }) async { - final List wpeDataTypes = dataTypes - .map((type) => _toWpeDataType(type)) - .toList(); - - final List> recordList = dataRecords.map((record) { - return { - 'displayName': record.displayName, - 'dataTypes': record.dataTypes - ?.map((type) => _toWpeDataType(type)) - .toList(), - }; - }).toList(); - - await _channel.invokeMethod('removeDataFor', { - 'dataTypes': wpeDataTypes, - 'recordList': recordList, - }); - } - - @override - Future removeDataModifiedSince({ - required Set dataTypes, - required DateTime date, - }) async { - final List wpeDataTypes = dataTypes - .map((type) => _toWpeDataType(type)) - .toList(); - - // Convert DateTime to Unix timestamp (seconds since epoch) - final int timestamp = date.millisecondsSinceEpoch ~/ 1000; - - await _channel.invokeMethod('removeDataModifiedSince', { - 'dataTypes': wpeDataTypes, - 'timestamp': timestamp, - }); - } -} diff --git a/flutter_inappwebview_linux/lib/src/webview_environment/main.dart b/flutter_inappwebview_linux/lib/src/webview_environment/main.dart deleted file mode 100644 index f9bf33a73a..0000000000 --- a/flutter_inappwebview_linux/lib/src/webview_environment/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'webview_environment.dart'; diff --git a/flutter_inappwebview_linux/lib/src/webview_environment/webview_environment.dart b/flutter_inappwebview_linux/lib/src/webview_environment/webview_environment.dart deleted file mode 100644 index fd95f3e0ff..0000000000 --- a/flutter_inappwebview_linux/lib/src/webview_environment/webview_environment.dart +++ /dev/null @@ -1,158 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [LinuxWebViewEnvironment]. -/// -/// Platform specific implementations can add additional fields by extending -/// this class. -@immutable -class LinuxWebViewEnvironmentCreationParams - extends PlatformWebViewEnvironmentCreationParams { - /// Creates a new [LinuxWebViewEnvironmentCreationParams] instance. - const LinuxWebViewEnvironmentCreationParams({super.settings}); - - /// Creates a [LinuxWebViewEnvironmentCreationParams] instance based on [PlatformWebViewEnvironmentCreationParams]. - factory LinuxWebViewEnvironmentCreationParams.fromPlatformWebViewEnvironmentCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebViewEnvironmentCreationParams params, - ) { - return LinuxWebViewEnvironmentCreationParams(settings: params.settings); - } -} - -/// Linux implementation of [PlatformWebViewEnvironment]. -/// -/// This class provides access to WPE WebKit version information and -/// WebKitWebContext management on Linux. -/// -///**Officially Supported Platforms/Implementations**: -///- Linux -class LinuxWebViewEnvironment extends PlatformWebViewEnvironment - with ChannelController { - /// Static method channel for WebViewEnvironment operations. - static final MethodChannel _staticChannel = MethodChannel( - 'com.pichillilorenzo/flutter_webview_environment', - ); - - @override - final String id = IdGenerator.generate(); - - /// Creates a new [LinuxWebViewEnvironment]. - LinuxWebViewEnvironment(PlatformWebViewEnvironmentCreationParams params) - : super.implementation( - params is LinuxWebViewEnvironmentCreationParams - ? params - : LinuxWebViewEnvironmentCreationParams.fromPlatformWebViewEnvironmentCreationParams( - params, - ), - ); - - /// Static instance for accessing static methods. - static final LinuxWebViewEnvironment _staticValue = LinuxWebViewEnvironment( - LinuxWebViewEnvironmentCreationParams(), - ); - - /// Factory constructor for accessing static methods. - factory LinuxWebViewEnvironment.static() { - return _staticValue; - } - - _debugLog(String method, dynamic args) { - debugLog( - className: runtimeType.toString(), - id: id, - debugLoggingSettings: PlatformWebViewEnvironment.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - if (PlatformWebViewEnvironment.debugLoggingSettings.enabled) { - _debugLog(call.method, call.arguments); - } - - switch (call.method) { - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - } - - /// {@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.create} - /// - /// On Linux, this creates a new WebKitWebContext instance. - @override - Future create({ - WebViewEnvironmentSettings? settings, - }) async { - final env = LinuxWebViewEnvironment( - LinuxWebViewEnvironmentCreationParams(settings: settings), - ); - - Map args = {}; - args.putIfAbsent('id', () => env.id); - if (settings != null) { - args.putIfAbsent('settings', () => settings.toMap()); - } - await _staticChannel.invokeMethod('create', args); - - env.channel = MethodChannel( - 'com.pichillilorenzo/flutter_webview_environment_${env.id}', - ); - env.handler = env.handleMethod; - env.initMethodCallHandler(); - return env; - } - - /// {@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getAvailableVersion} - /// - /// On Linux, this returns the WPE WebKit version (e.g., "2.42.0"). - /// - /// The [browserExecutableFolder] parameter is ignored on Linux as WPE WebKit - /// is a system library. - @override - Future getAvailableVersion({String? browserExecutableFolder}) async { - return await _staticChannel.invokeMethod('getAvailableVersion'); - } - - /// {@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isSpellCheckingEnabled} - @override - Future isSpellCheckingEnabled() async { - return await channel?.invokeMethod('isSpellCheckingEnabled') ?? false; - } - - /// {@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getSpellCheckingLanguages} - @override - Future> getSpellCheckingLanguages() async { - final result = await channel?.invokeMethod( - 'getSpellCheckingLanguages', - ); - return result?.cast() ?? []; - } - - /// {@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getCacheModel} - @override - Future getCacheModel() async { - final result = await channel?.invokeMethod('getCacheModel'); - return CacheModel.fromNativeValue(result); - } - - /// {@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isAutomationAllowed} - @override - Future isAutomationAllowed() async { - return await channel?.invokeMethod('isAutomationAllowed') ?? false; - } - - @override - Future dispose() async { - Map args = {}; - await channel?.invokeMethod('dispose', args); - disposeChannel(); - } -} - -extension InternalLinuxWebViewEnvironment on LinuxWebViewEnvironment { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_linux/linux/.clang-format b/flutter_inappwebview_linux/linux/.clang-format deleted file mode 100644 index aa5e2d6759..0000000000 --- a/flutter_inappwebview_linux/linux/.clang-format +++ /dev/null @@ -1,50 +0,0 @@ -# Clang-format configuration for flutter_inappwebview_linux -# Based on Google style with some adjustments for consistency - -BasedOnStyle: Google -Language: Cpp -Standard: c++17 - -# Indentation -IndentWidth: 2 -TabWidth: 2 -UseTab: Never -IndentCaseLabels: true -NamespaceIndentation: None - -# Line length -ColumnLimit: 100 - -# Braces -BreakBeforeBraces: Attach -AllowShortBlocksOnASingleLine: Empty -AllowShortFunctionsOnASingleLine: Inline -AllowShortIfStatementsOnASingleLine: Never -AllowShortLoopsOnASingleLine: false - -# Alignment -AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: false -AlignConsecutiveDeclarations: false -AlignOperands: true -AlignTrailingComments: true - -# Pointers and References -DerivePointerAlignment: false -PointerAlignment: Left - -# Includes -IncludeBlocks: Regroup -SortIncludes: true - -# Other -SpaceAfterCStyleCast: false -SpaceBeforeParens: ControlStatements -SpacesInAngles: false -SpacesInContainerLiterals: true -SpacesInParentheses: false -SpacesInSquareBrackets: false - -# Keep existing line breaks where sensible -MaxEmptyLinesToKeep: 1 -KeepEmptyLinesAtTheStartOfBlocks: false diff --git a/flutter_inappwebview_linux/linux/CMakeLists.txt b/flutter_inappwebview_linux/linux/CMakeLists.txt deleted file mode 100644 index 27f9334810..0000000000 --- a/flutter_inappwebview_linux/linux/CMakeLists.txt +++ /dev/null @@ -1,430 +0,0 @@ -# The Flutter tooling requires that developers have CMake 3.10 or later -# installed. You should not increase this version, as doing so will cause -# the plugin to fail to compile for some customers of the plugin. -cmake_minimum_required(VERSION 3.10) - -# Project-level configuration. -set(PROJECT_NAME "flutter_inappwebview_linux") -project(${PROJECT_NAME} LANGUAGES CXX C) - -# This value is used when generating builds using this plugin, so it must -# not be changed. -set(PLUGIN_NAME "flutter_inappwebview_linux_plugin") - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# nlohmann/json version for JSON parsing -set(NLOHMANN_JSON_VERSION "3.11.3") - -# === WPE WebKit Backend === -# This plugin uses WPE WebKit for offscreen web rendering. -# WPE WebKit is designed for embedded systems and provides excellent offscreen -# rendering performance through DMA-BUF buffer sharing. -# -# Dual API Support: -# - WPEPlatform API (wpe-platform-2.0): NEW default API for WPE WebKit 2.40+ -# - WPEBackend-FDO (wpebackend-fdo-1.0): Legacy fallback for older systems -# -# Required packages: -# - wpe-webkit-2.0 (or wpe-webkit-1.1 on older systems) -# - wpe-platform-2.0 (preferred) OR wpebackend-fdo-1.0 (fallback) -# - libwpe-1.0 -# -# See WPE_BACKEND.md for installation instructions. - -find_package(PkgConfig REQUIRED) - -# Always require epoxy for OpenGL support -pkg_check_modules(EPOXY REQUIRED IMPORTED_TARGET epoxy) - -# GTK is still needed for GDK (display access, event handling) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) - -message(STATUS "flutter_inappwebview_linux: Using WPE WebKit backend") - -# Try wpe-webkit-2.0 first (newer API), fall back to wpe-webkit-1.1, then wpe-webkit-1.0 -pkg_check_modules(WPE_WEBKIT QUIET IMPORTED_TARGET wpe-webkit-2.0) -if(NOT WPE_WEBKIT_FOUND) - pkg_check_modules(WPE_WEBKIT QUIET IMPORTED_TARGET wpe-webkit-1.1) - if(WPE_WEBKIT_FOUND) - message(STATUS "flutter_inappwebview_linux: Found wpe-webkit-1.1 (${WPE_WEBKIT_VERSION})") - else() - pkg_check_modules(WPE_WEBKIT QUIET IMPORTED_TARGET wpe-webkit-1.0) - if(WPE_WEBKIT_FOUND) - message(STATUS "flutter_inappwebview_linux: Found wpe-webkit-1.0 (${WPE_WEBKIT_VERSION})") - endif() - endif() -else() - message(STATUS "flutter_inappwebview_linux: Found wpe-webkit-2.0 (${WPE_WEBKIT_VERSION})") -endif() - -if(NOT WPE_WEBKIT_FOUND) - message(FATAL_ERROR "WPE WebKit not found. Please install libwpewebkit-1.0-dev (Ubuntu/Debian) or wpe-webkit package.\n" - "See WPE_BACKEND.md or https://wpewebkit.org/about/get-wpe.html") -endif() - -# === WPE Platform API Detection (NEW - default) === -# Check for WPEPlatform API first (wpe-platform-2.0) - this is the modern API -# introduced in WPE WebKit 2.40+ and is the preferred approach. -pkg_check_modules(WPE_PLATFORM QUIET IMPORTED_TARGET wpe-platform-2.0) -pkg_check_modules(WPE_PLATFORM_HEADLESS QUIET IMPORTED_TARGET wpe-platform-headless-2.0) - -if(WPE_PLATFORM_FOUND AND WPE_PLATFORM_HEADLESS_FOUND) - # Additional check: verify that WebKit was actually built WITH WPEPlatform support - # The pkg-config file may exist but WebKit headers may not have the required functions - # This happens when WPE WebKit is rebuilt without WPEPlatform support - include(CheckCXXSourceCompiles) - set(CMAKE_REQUIRED_INCLUDES ${WPE_WEBKIT_INCLUDE_DIRS} ${WPE_PLATFORM_INCLUDE_DIRS}) - set(CMAKE_REQUIRED_LIBRARIES ${WPE_WEBKIT_LIBRARIES} ${WPE_PLATFORM_LIBRARIES}) - check_cxx_source_compiles(" - #include - int main() { - WebKitWebView* view = nullptr; - webkit_web_view_get_wpe_view(view); - return 0; - } - " WEBKIT_HAS_WPE_PLATFORM_API) - - if(WEBKIT_HAS_WPE_PLATFORM_API) - message(STATUS "flutter_inappwebview_linux: Found wpe-platform-2.0 (WPEPlatform API - DEFAULT)") - message(STATUS "flutter_inappwebview_linux: Found wpe-platform-headless-2.0") - message(STATUS "flutter_inappwebview_linux: WebKit has WPEPlatform API support (webkit_web_view_get_wpe_view)") - set(HAVE_WPE_PLATFORM ON) - add_compile_definitions(HAVE_WPE_PLATFORM=1) - else() - message(STATUS "flutter_inappwebview_linux: wpe-platform-2.0 pkg-config found, but WebKit lacks WPEPlatform API") - message(STATUS "flutter_inappwebview_linux: WebKit was likely built without WPEPlatform support, falling back to legacy FDO") - endif() -endif() - -# === WPE Backend FDO Detection (Legacy - fallback) === -# Check for WPEBackend-FDO as fallback ONLY if WPEPlatform is NOT available -# WPEPlatform and WPEBackend-FDO are mutually exclusive at compile time -pkg_check_modules(WPE_FDO QUIET IMPORTED_TARGET wpebackend-fdo-1.0) -if(WPE_FDO_FOUND AND NOT HAVE_WPE_PLATFORM) - message(STATUS "flutter_inappwebview_linux: Found wpebackend-fdo-1.0 (Legacy FDO API)") - set(HAVE_WPE_FDO ON) - add_compile_definitions(HAVE_WPE_BACKEND_LEGACY=1) -elseif(WPE_FDO_FOUND AND HAVE_WPE_PLATFORM) - message(STATUS "flutter_inappwebview_linux: wpebackend-fdo-1.0 available but not used (WPEPlatform preferred)") -endif() - -# Require at least one backend -if(NOT HAVE_WPE_PLATFORM AND NOT HAVE_WPE_FDO) - message(FATAL_ERROR "Neither WPEPlatform (wpe-platform-2.0) nor WPEBackend-FDO (wpebackend-fdo-1.0) found.\n" - "Please install one of:\n" - " - WPE WebKit 2.40+ with WPEPlatform support (recommended)\n" - " - wpebackend-fdo-1.0-dev (legacy fallback)\n" - "See WPE_BACKEND.md for installation instructions.") -endif() - -# Check for libwpe -pkg_check_modules(LIBWPE QUIET IMPORTED_TARGET wpe-1.0) -if(NOT LIBWPE_FOUND) - message(FATAL_ERROR "libwpe (wpe-1.0) not found. Please install libwpe-1.0-dev.") -endif() - -# Check for libsecret for secure credential storage -pkg_check_modules(LIBSECRET REQUIRED IMPORTED_TARGET libsecret-1) -message(STATUS "flutter_inappwebview_linux: Found libsecret-1 (${LIBSECRET_VERSION})") - -# Find wayland-server for SHM buffer handling -pkg_check_modules(WAYLAND_SERVER REQUIRED IMPORTED_TARGET wayland-server) - -# Enable SIMD optimizations for color conversion -# These flags enable NEON on ARM64 and SSE/SSSE3 on x86_64 -include(CheckCXXCompilerFlag) -if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64") - # ARM64: NEON is always available - message(STATUS "flutter_inappwebview_linux: ARM64 detected, NEON enabled") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|amd64") - # x86_64: Check for SSSE3 support - check_cxx_compiler_flag("-mssse3" COMPILER_SUPPORTS_SSSE3) - if(COMPILER_SUPPORTS_SSSE3) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mssse3") - message(STATUS "flutter_inappwebview_linux: x86_64 with SSSE3 enabled") - else() - check_cxx_compiler_flag("-msse2" COMPILER_SUPPORTS_SSE2) - if(COMPILER_SUPPORTS_SSE2) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2") - message(STATUS "flutter_inappwebview_linux: x86_64 with SSE2 enabled") - endif() - endif() -endif() - -# === nlohmann/json dependency for JSON parsing === -include(FetchContent) -FetchContent_Declare( - nlohmann_json - URL https://github.com/nlohmann/json/releases/download/v${NLOHMANN_JSON_VERSION}/json.tar.xz - DOWNLOAD_EXTRACT_TIMESTAMP TRUE -) -# Don't build tests/examples -set(JSON_BuildTests OFF CACHE INTERNAL "") -FetchContent_MakeAvailable(nlohmann_json) -# Suppress deprecated literal operator warnings from nlohmann_json -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-literal-operator") -message(STATUS "flutter_inappwebview_linux: nlohmann/json ${NLOHMANN_JSON_VERSION} configured") - -# Plugin source files -list(APPEND PLUGIN_SOURCES - "flutter_inappwebview_linux_plugin.cc" - "plugin_instance.cc" - "cookie_manager.cc" - "credential_database.cc" - "proxy_manager.cc" - "utils/software_rendering.cc" - "web_storage_manager.cc" - "webview_environment.cc" - "content_blocker/content_blocker_handler.cc" - "find_interaction/find_interaction_controller.cc" - "find_interaction/find_interaction_channel_delegate.cc" - "headless_in_app_webview/headless_in_app_webview.cc" - "headless_in_app_webview/headless_in_app_webview_manager.cc" - "headless_in_app_webview/headless_webview_channel_delegate.cc" - "in_app_browser/in_app_browser.cc" - "in_app_browser/in_app_browser_channel_delegate.cc" - "in_app_browser/in_app_browser_manager.cc" - "in_app_browser/in_app_browser_settings.cc" - "in_app_webview/in_app_webview_manager.cc" - "in_app_webview/custom_platform_view.cc" - "in_app_webview/inappwebview_texture.cc" - "in_app_webview/inappwebview_egl_texture.cc" - "in_app_webview/in_app_webview.cc" - "in_app_webview/in_app_webview_settings.cc" - "in_app_webview/user_content_controller.cc" - "in_app_webview/webview_channel_delegate.cc" - "types/channel_delegate.cc" - "types/client_cert_challenge.cc" - "types/client_cert_response.cc" - "types/content_world.cc" - "types/context_menu_popup.cc" - "types/create_window_action.cc" - "types/custom_scheme_response.cc" - "types/download_start_request.cc" - "types/download_start_response.cc" - "types/find_session.cc" - "types/http_auth_response.cc" - "types/http_authentication_challenge.cc" - "types/javascript_handler_function_data.cc" - "types/js_alert_request.cc" - "types/js_alert_response.cc" - "types/js_before_unload_response.cc" - "types/js_confirm_request.cc" - "types/js_confirm_response.cc" - "types/js_prompt_request.cc" - "types/js_prompt_response.cc" - "types/hit_test_result.cc" - "types/navigation_action.cc" - "types/option_menu_popup.cc" - "types/permission_request.cc" - "types/permission_response.cc" - "types/plugin_script.cc" - "types/server_trust_auth_response.cc" - "types/server_trust_challenge.cc" - "types/show_file_chooser_response.cc" - "types/ssl_certificate.cc" - "types/url_credential.cc" - "types/url_protection_space.cc" - "types/url_request.cc" - "types/user_script.cc" - "types/web_resource_error.cc" - "types/web_resource_request.cc" - "types/web_resource_response.cc" - "types/web_view_transport.cc" - "web_message/web_message_channel.cc" - "web_message/web_message_listener.cc" - "web_message/web_message_listener_channel_delegate.cc" -) - -# Define the plugin library target. Its name must not be changed (see comment -# on PLUGIN_NAME above). -add_library(${PLUGIN_NAME} SHARED - ${PLUGIN_SOURCES} -) - -# Apply a standard set of build settings that are configured in the -# application-level CMakeLists.txt. This can be removed for plugins that want -# full control over build settings. -apply_standard_settings(${PLUGIN_NAME}) - -# Symbols are hidden by default to reduce the chance of accidental conflicts -# between plugins. This should not be removed; any symbols that should be -# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro. -set_target_properties(${PLUGIN_NAME} PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) - -# Set RPATH so the plugin loads bundled WPE libraries from the same directory. -# $ORIGIN refers to the directory containing the plugin shared library. -# This eliminates the need for LD_LIBRARY_PATH or launcher scripts. -set_target_properties(${PLUGIN_NAME} PROPERTIES - INSTALL_RPATH "$ORIGIN" - BUILD_RPATH "$ORIGIN" - BUILD_WITH_INSTALL_RPATH TRUE) - -# Source include directories and library dependencies -target_include_directories(${PLUGIN_NAME} INTERFACE - "${CMAKE_CURRENT_SOURCE_DIR}/include") -target_include_directories(${PLUGIN_NAME} PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}" - ${EPOXY_INCLUDE_DIRS} - ${WPE_WEBKIT_INCLUDE_DIRS}) - -target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) -target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) -target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::EPOXY) -target_link_libraries(${PLUGIN_NAME} PRIVATE nlohmann_json::nlohmann_json) -target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::WPE_WEBKIT) -target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::LIBWPE) -target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::WAYLAND_SERVER) -target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::LIBSECRET) - -# Link WPEPlatform if available (new API - default) -if(HAVE_WPE_PLATFORM) - target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::WPE_PLATFORM) - target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::WPE_PLATFORM_HEADLESS) -endif() - -# Link WPEBackend-FDO if available (legacy fallback) -if(HAVE_WPE_FDO) - target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::WPE_FDO) -endif() - -# === Library Bundling === -# Collect WPE libraries to bundle with the application -# This ensures the app can run without setting LD_LIBRARY_PATH - -set(WPE_BUNDLED_LIBS "") - -# Helper function to find and add real shared library files (resolving symlinks) -function(find_and_add_library LIB_NAME SEARCH_PATHS OUT_LIST) - foreach(SEARCH_PATH ${SEARCH_PATHS}) - # Look for the versioned .so file (e.g., libwpe-1.0.so.1.10.0) - file(GLOB LIB_FILES "${SEARCH_PATH}/${LIB_NAME}.so.*.*.*") - if(NOT LIB_FILES) - # Try less specific pattern (e.g., libwpe-1.0.so.1) - file(GLOB LIB_FILES "${SEARCH_PATH}/${LIB_NAME}.so.*") - endif() - if(LIB_FILES) - # Get the first matching file - list(GET LIB_FILES 0 LIB_FILE) - # Resolve symlinks to get the real file - get_filename_component(REAL_LIB "${LIB_FILE}" REALPATH) - if(EXISTS "${REAL_LIB}") - list(APPEND ${OUT_LIST} "${REAL_LIB}") - set(${OUT_LIST} ${${OUT_LIST}} PARENT_SCOPE) - message(STATUS "flutter_inappwebview_linux: Will bundle ${REAL_LIB}") - return() - endif() - endif() - endforeach() - message(WARNING "flutter_inappwebview_linux: Could not find ${LIB_NAME} to bundle") -endfunction() - -# Get library directories from pkg-config -set(WPE_LIB_DIRS "") -if(WPE_WEBKIT_LIBRARY_DIRS) - list(APPEND WPE_LIB_DIRS ${WPE_WEBKIT_LIBRARY_DIRS}) -endif() -if(LIBWPE_LIBRARY_DIRS) - list(APPEND WPE_LIB_DIRS ${LIBWPE_LIBRARY_DIRS}) -endif() -if(HAVE_WPE_FDO AND WPE_FDO_LIBRARY_DIRS) - list(APPEND WPE_LIB_DIRS ${WPE_FDO_LIBRARY_DIRS}) -endif() -# Add common paths as fallback -list(APPEND WPE_LIB_DIRS - "/usr/local/lib" - "/usr/local/lib/${CMAKE_LIBRARY_ARCHITECTURE}" - "/usr/lib" - "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}" -) -list(REMOVE_DUPLICATES WPE_LIB_DIRS) - -# Find WPE WebKit library -find_and_add_library("libWPEWebKit-2.0" "${WPE_LIB_DIRS}" WPE_BUNDLED_LIBS) - -# Find libwpe library -find_and_add_library("libwpe-1.0" "${WPE_LIB_DIRS}" WPE_BUNDLED_LIBS) - -# WPEPlatform is built into libWPEWebKit-2.0 on modern builds, so there are -# no separate libWPEPlatform*.so files to bundle. - -# Find WPE Backend FDO library (legacy fallback) -if(HAVE_WPE_FDO) - find_and_add_library("libWPEBackend-fdo-1.0" "${WPE_LIB_DIRS}" WPE_BUNDLED_LIBS) -endif() - -# Also need to create symlinks for the sonames that the libraries expect -# This will be handled at install time in the example CMakeLists.txt - -set(flutter_inappwebview_linux_bundled_libraries - ${WPE_BUNDLED_LIBS} - PARENT_SCOPE -) - -# Export library info for downstream use -set(FLUTTER_INAPPWEBVIEW_WPE_LIBS ${WPE_BUNDLED_LIBS} CACHE INTERNAL "WPE libraries to bundle") - -# === Tests === -# These unit tests can be run from a terminal after building the example. - -# Only enable test builds when building the example (which sets this variable) -# so that plugin clients aren't building the tests. -if (${include_${PROJECT_NAME}_tests}) -if(${CMAKE_VERSION} VERSION_LESS "3.11.0") -message("Unit tests require CMake 3.11.0 or later") -else() -set(TEST_RUNNER "${PROJECT_NAME}_test") -enable_testing() - -# Add the Google Test dependency. -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/release-1.11.0.zip - DOWNLOAD_EXTRACT_TIMESTAMP TRUE -) -# Prevent overriding the parent project's compiler/linker settings -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -# Disable install commands for gtest so it doesn't end up in the bundle. -set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE) - -FetchContent_MakeAvailable(googletest) - -# The plugin's exported API is not very useful for unit testing, so build the -# sources directly into the test binary rather than using the shared library. -add_executable(${TEST_RUNNER} - test/flutter_inappwebview_linux_plugin_test.cc - ${PLUGIN_SOURCES} -) -apply_standard_settings(${TEST_RUNNER}) -target_include_directories(${TEST_RUNNER} PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}" - ${EPOXY_INCLUDE_DIRS} - ${WPE_WEBKIT_INCLUDE_DIRS}) -target_link_libraries(${TEST_RUNNER} PRIVATE flutter) -target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::GTK) -target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::EPOXY) -target_link_libraries(${TEST_RUNNER} PRIVATE nlohmann_json::nlohmann_json) -target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::WPE_WEBKIT) -target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::LIBWPE) -target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::WAYLAND_SERVER) -target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::LIBSECRET) -if(HAVE_WPE_PLATFORM) - target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::WPE_PLATFORM) - target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::WPE_PLATFORM_HEADLESS) -endif() -if(HAVE_WPE_FDO) - target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::WPE_FDO) -endif() -target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock) - -# Enable automatic test discovery. -include(GoogleTest) -gtest_discover_tests(${TEST_RUNNER}) - -endif() # CMake version check -endif() # include_${PROJECT_NAME}_tests diff --git a/flutter_inappwebview_linux/linux/content_blocker/content_blocker_handler.cc b/flutter_inappwebview_linux/linux/content_blocker/content_blocker_handler.cc deleted file mode 100644 index 28101610af..0000000000 --- a/flutter_inappwebview_linux/linux/content_blocker/content_blocker_handler.cc +++ /dev/null @@ -1,352 +0,0 @@ -#include "content_blocker_handler.h" - -#include - -#include -#include -#include - -#include "../utils/log.h" -#include "../utils/util.h" - -using json = nlohmann::json; - -namespace flutter_inappwebview_plugin { - -ContentBlockerHandler::ContentBlockerHandler(WebKitUserContentManager* content_manager) - : content_manager_(content_manager), - filter_store_(nullptr), - filter_identifier_("flutter_inappwebview_content_rules") { - if (content_manager_ == nullptr) { - errorLog("ContentBlockerHandler: content_manager is null"); - return; - } - - // Get app-specific ID for isolated storage - std::string app_id = resolve_application_id_sanitized(); - - // Create filter store in a cache directory - // Use XDG cache directory or fallback to /tmp - const char* xdg_cache = g_get_user_cache_dir(); - if (xdg_cache != nullptr) { - store_path_ = std::string(xdg_cache) + "/flutter_inappwebview/" + app_id + "/content_filters"; - } else { - store_path_ = "/tmp/flutter_inappwebview/" + app_id + "/content_filters"; - } - - // Ensure directory exists - std::error_code ec; - std::filesystem::create_directories(store_path_, ec); - if (ec) { - errorLog("ContentBlockerHandler: Failed to create filter store directory: " + ec.message()); - } - - // Create the filter store - filter_store_ = webkit_user_content_filter_store_new(store_path_.c_str()); - if (filter_store_ == nullptr) { - errorLog("ContentBlockerHandler: Failed to create WebKitUserContentFilterStore"); - } -} - -ContentBlockerHandler::~ContentBlockerHandler() { - removeAllFilters(); - - if (filter_store_ != nullptr) { - g_object_unref(filter_store_); - filter_store_ = nullptr; - } -} - -void ContentBlockerHandler::setContentBlockers(FlValue* contentBlockers, - std::function callback) { - if (filter_store_ == nullptr || content_manager_ == nullptr) { - errorLog("ContentBlockerHandler: filter_store or content_manager is null"); - if (callback) callback(false); - return; - } - - // First remove existing filters - removeAllFilters(); - - // Check if there are any content blockers to apply - if (contentBlockers == nullptr || - fl_value_get_type(contentBlockers) != FL_VALUE_TYPE_LIST || - fl_value_get_length(contentBlockers) == 0) { - // No blockers - this is success (empty set) - if (callback) callback(true); - return; - } - - // Convert to JSON string - std::string jsonSource = convertToJsonString(contentBlockers); - - if (jsonSource.empty()) { - errorLog("ContentBlockerHandler: Failed to convert content blockers to JSON"); - if (callback) callback(false); - return; - } - - // Compile the content blockers - compileContentBlockers(jsonSource, callback); -} - -void ContentBlockerHandler::removeAllFilters() { - // Check if content_manager is still valid before calling WebKit API - // The content_manager becomes invalid when the webview is destroyed - if (content_manager_ != nullptr && WEBKIT_IS_USER_CONTENT_MANAGER(content_manager_)) { - webkit_user_content_manager_remove_all_filters(content_manager_); - } -} - -std::string ContentBlockerHandler::convertToJsonString(FlValue* contentBlockers) { - if (contentBlockers == nullptr || - fl_value_get_type(contentBlockers) != FL_VALUE_TYPE_LIST) { - return ""; - } - - json jsonArray = json::array(); - - size_t count = fl_value_get_length(contentBlockers); - for (size_t i = 0; i < count; i++) { - FlValue* blocker = fl_value_get_list_value(contentBlockers, i); - if (fl_value_get_type(blocker) != FL_VALUE_TYPE_MAP) { - continue; - } - - json rule; - - // Parse trigger - FlValue* triggerValue = fl_value_lookup_string(blocker, "trigger"); - if (triggerValue != nullptr && fl_value_get_type(triggerValue) == FL_VALUE_TYPE_MAP) { - json trigger; - - // url-filter (required) - FlValue* urlFilter = fl_value_lookup_string(triggerValue, "url-filter"); - if (urlFilter != nullptr && fl_value_get_type(urlFilter) == FL_VALUE_TYPE_STRING) { - trigger["url-filter"] = fl_value_get_string(urlFilter); - } else { - // Skip this rule - url-filter is required - continue; - } - - // url-filter-is-case-sensitive - FlValue* caseSensitive = fl_value_lookup_string(triggerValue, "url-filter-is-case-sensitive"); - if (caseSensitive != nullptr && fl_value_get_type(caseSensitive) == FL_VALUE_TYPE_BOOL) { - if (fl_value_get_bool(caseSensitive)) { - trigger["url-filter-is-case-sensitive"] = true; - } - } - - // resource-type (array) - FlValue* resourceType = fl_value_lookup_string(triggerValue, "resource-type"); - if (resourceType != nullptr && fl_value_get_type(resourceType) == FL_VALUE_TYPE_LIST) { - json types = json::array(); - for (size_t j = 0; j < fl_value_get_length(resourceType); j++) { - FlValue* type = fl_value_get_list_value(resourceType, j); - if (fl_value_get_type(type) == FL_VALUE_TYPE_STRING) { - types.push_back(fl_value_get_string(type)); - } - } - if (!types.empty()) { - trigger["resource-type"] = types; - } - } - - // if-domain (array) - FlValue* ifDomain = fl_value_lookup_string(triggerValue, "if-domain"); - if (ifDomain != nullptr && fl_value_get_type(ifDomain) == FL_VALUE_TYPE_LIST) { - json domains = json::array(); - for (size_t j = 0; j < fl_value_get_length(ifDomain); j++) { - FlValue* domain = fl_value_get_list_value(ifDomain, j); - if (fl_value_get_type(domain) == FL_VALUE_TYPE_STRING) { - domains.push_back(fl_value_get_string(domain)); - } - } - if (!domains.empty()) { - trigger["if-domain"] = domains; - } - } - - // unless-domain (array) - FlValue* unlessDomain = fl_value_lookup_string(triggerValue, "unless-domain"); - if (unlessDomain != nullptr && fl_value_get_type(unlessDomain) == FL_VALUE_TYPE_LIST) { - json domains = json::array(); - for (size_t j = 0; j < fl_value_get_length(unlessDomain); j++) { - FlValue* domain = fl_value_get_list_value(unlessDomain, j); - if (fl_value_get_type(domain) == FL_VALUE_TYPE_STRING) { - domains.push_back(fl_value_get_string(domain)); - } - } - if (!domains.empty()) { - trigger["unless-domain"] = domains; - } - } - - // load-type (array) - FlValue* loadType = fl_value_lookup_string(triggerValue, "load-type"); - if (loadType != nullptr && fl_value_get_type(loadType) == FL_VALUE_TYPE_LIST) { - json types = json::array(); - for (size_t j = 0; j < fl_value_get_length(loadType); j++) { - FlValue* type = fl_value_get_list_value(loadType, j); - if (fl_value_get_type(type) == FL_VALUE_TYPE_STRING) { - types.push_back(fl_value_get_string(type)); - } - } - if (!types.empty()) { - trigger["load-type"] = types; - } - } - - // if-top-url (array) - FlValue* ifTopUrl = fl_value_lookup_string(triggerValue, "if-top-url"); - if (ifTopUrl != nullptr && fl_value_get_type(ifTopUrl) == FL_VALUE_TYPE_LIST) { - json urls = json::array(); - for (size_t j = 0; j < fl_value_get_length(ifTopUrl); j++) { - FlValue* url = fl_value_get_list_value(ifTopUrl, j); - if (fl_value_get_type(url) == FL_VALUE_TYPE_STRING) { - urls.push_back(fl_value_get_string(url)); - } - } - if (!urls.empty()) { - trigger["if-top-url"] = urls; - } - } - - // unless-top-url (array) - FlValue* unlessTopUrl = fl_value_lookup_string(triggerValue, "unless-top-url"); - if (unlessTopUrl != nullptr && fl_value_get_type(unlessTopUrl) == FL_VALUE_TYPE_LIST) { - json urls = json::array(); - for (size_t j = 0; j < fl_value_get_length(unlessTopUrl); j++) { - FlValue* url = fl_value_get_list_value(unlessTopUrl, j); - if (fl_value_get_type(url) == FL_VALUE_TYPE_STRING) { - urls.push_back(fl_value_get_string(url)); - } - } - if (!urls.empty()) { - trigger["unless-top-url"] = urls; - } - } - - // if-frame-url (array) - WPE WebKit supports this - FlValue* ifFrameUrl = fl_value_lookup_string(triggerValue, "if-frame-url"); - if (ifFrameUrl != nullptr && fl_value_get_type(ifFrameUrl) == FL_VALUE_TYPE_LIST) { - json urls = json::array(); - for (size_t j = 0; j < fl_value_get_length(ifFrameUrl); j++) { - FlValue* url = fl_value_get_list_value(ifFrameUrl, j); - if (fl_value_get_type(url) == FL_VALUE_TYPE_STRING) { - urls.push_back(fl_value_get_string(url)); - } - } - if (!urls.empty()) { - trigger["if-frame-url"] = urls; - } - } - - rule["trigger"] = trigger; - } - - // Parse action - FlValue* actionValue = fl_value_lookup_string(blocker, "action"); - if (actionValue != nullptr && fl_value_get_type(actionValue) == FL_VALUE_TYPE_MAP) { - json action; - - // type (required) - FlValue* type = fl_value_lookup_string(actionValue, "type"); - if (type != nullptr && fl_value_get_type(type) == FL_VALUE_TYPE_STRING) { - std::string typeStr = fl_value_get_string(type); - - // WPE WebKit supports: block, block-cookies, css-display-none, - // ignore-previous-rules, make-https - action["type"] = typeStr; - } else { - // Skip this rule - type is required - continue; - } - - // selector (for css-display-none) - FlValue* selector = fl_value_lookup_string(actionValue, "selector"); - if (selector != nullptr && fl_value_get_type(selector) == FL_VALUE_TYPE_STRING) { - action["selector"] = fl_value_get_string(selector); - } - - rule["action"] = action; - } - - if (rule.contains("trigger") && rule.contains("action")) { - jsonArray.push_back(rule); - } - } - - if (jsonArray.empty()) { - return ""; - } - - return jsonArray.dump(); -} - -void ContentBlockerHandler::compileContentBlockers(const std::string& jsonSource, - std::function callback) { - if (filter_store_ == nullptr) { - if (callback) callback(false); - return; - } - - // Create GBytes from JSON source - GBytes* sourceBytes = g_bytes_new(jsonSource.c_str(), jsonSource.length()); - - // Create context for async callback - auto* context = new CompileContext{this, std::move(callback)}; - - // Start async compilation - webkit_user_content_filter_store_save(filter_store_, filter_identifier_.c_str(), sourceBytes, - nullptr, // cancellable - onFilterCompiled, context); - - g_bytes_unref(sourceBytes); -} - -void ContentBlockerHandler::onFilterCompiled(GObject* source, GAsyncResult* result, - gpointer user_data) { - auto* context = static_cast(user_data); - if (context == nullptr) { - return; - } - - auto* handler = context->handler; - auto callback = std::move(context->callback); - delete context; - - if (handler == nullptr || handler->filter_store_ == nullptr) { - if (callback) callback(false); - return; - } - - GError* error = nullptr; - WebKitUserContentFilter* filter = - webkit_user_content_filter_store_save_finish(handler->filter_store_, result, &error); - - if (error != nullptr) { - errorLog("ContentBlockerHandler: Failed to compile content blockers: " + - std::string(error->message)); - g_error_free(error); - if (callback) callback(false); - return; - } - - if (filter == nullptr) { - errorLog("ContentBlockerHandler: Compiled filter is null"); - if (callback) callback(false); - return; - } - - // Add the compiled filter to the content manager - if (handler->content_manager_ != nullptr) { - webkit_user_content_manager_add_filter(handler->content_manager_, filter); - } - - webkit_user_content_filter_unref(filter); - - if (callback) callback(true); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/content_blocker/content_blocker_handler.h b/flutter_inappwebview_linux/linux/content_blocker/content_blocker_handler.h deleted file mode 100644 index 5e74782731..0000000000 --- a/flutter_inappwebview_linux/linux/content_blocker/content_blocker_handler.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CONTENT_BLOCKER_HANDLER_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_CONTENT_BLOCKER_HANDLER_H_ - -#include -#include - -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -class InAppWebView; - -/** - * ContentBlockerHandler manages WebKit content filters for content blocking. - * - * Uses WebKitUserContentFilterStore to compile Safari-compatible content blocker - * JSON rules into native WebKit filters. This is the same mechanism used by - * iOS/macOS (WKContentRuleListStore). - * - * WPE WebKit uses the Safari content blocker JSON format: - * [ - * { - * "trigger": { "url-filter": ".*ads.*" }, - * "action": { "type": "block" } - * } - * ] - * - * Supported action types: - * - block: Block the resource from loading - * - css-display-none: Hide matching elements with CSS - * - make-https: Upgrade HTTP URLs to HTTPS - */ -class ContentBlockerHandler { - public: - explicit ContentBlockerHandler(WebKitUserContentManager* content_manager); - ~ContentBlockerHandler(); - - /** - * Compile and apply content blockers from FlValue list. - * - * The FlValue should be a list of content blocker maps, each with: - * - "trigger": map with "url-filter" and optional other trigger properties - * - "action": map with "type" and optional "selector" (for css-display-none) - * - * @param contentBlockers FlValue list of content blocker maps - * @param callback Called when compilation is complete (success or failure) - */ - void setContentBlockers(FlValue* contentBlockers, - std::function callback); - - /** - * Remove all content filters from the content manager. - */ - void removeAllFilters(); - - /** - * Get the current filter identifier. - */ - std::string getFilterIdentifier() const { return filter_identifier_; } - - private: - /** - * Convert FlValue content blockers to Safari-format JSON string. - * - * @param contentBlockers FlValue list of content blocker maps - * @return JSON string in Safari content blocker format, or empty string on error - */ - std::string convertToJsonString(FlValue* contentBlockers); - - /** - * Compile JSON to WebKit filter (async). - * - * @param jsonSource JSON string in Safari format - * @param callback Called when compilation is complete - */ - void compileContentBlockers(const std::string& jsonSource, - std::function callback); - - /** - * Callback when filter store save completes. - */ - static void onFilterCompiled(GObject* source, GAsyncResult* result, gpointer user_data); - - WebKitUserContentManager* content_manager_; // Not owned (from webview) - WebKitUserContentFilterStore* filter_store_; // Owned - std::string filter_identifier_; - std::string store_path_; - - /** - * Context for async filter compilation callback. - */ - struct CompileContext { - ContentBlockerHandler* handler; - std::function callback; - }; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_CONTENT_BLOCKER_HANDLER_H_ diff --git a/flutter_inappwebview_linux/linux/cookie_manager.cc b/flutter_inappwebview_linux/linux/cookie_manager.cc deleted file mode 100644 index 0fe3bd7152..0000000000 --- a/flutter_inappwebview_linux/linux/cookie_manager.cc +++ /dev/null @@ -1,607 +0,0 @@ -#include "cookie_manager.h" - -#include -#include -#include - -#include "plugin_instance.h" -#include "utils/flutter.h" -#include "utils/log.h" - -namespace flutter_inappwebview_plugin { - -namespace { -// Helper to compare method names -bool string_equals(const gchar* a, const char* b) { - return strcmp(a, b) == 0; -} - -// Parse SameSite attribute from string -SoupSameSitePolicy parseSameSite(const std::string& sameSite) { - if (sameSite == "Strict") { - return SOUP_SAME_SITE_POLICY_STRICT; - } else if (sameSite == "Lax") { - return SOUP_SAME_SITE_POLICY_LAX; - } - return SOUP_SAME_SITE_POLICY_NONE; -} - -// Convert SameSite policy to string -std::string sameSiteToString(SoupSameSitePolicy policy) { - switch (policy) { - case SOUP_SAME_SITE_POLICY_STRICT: - return "Strict"; - case SOUP_SAME_SITE_POLICY_LAX: - return "Lax"; - case SOUP_SAME_SITE_POLICY_NONE: - default: - return "None"; - } -} -} // namespace - -// === Cookie === - -Cookie::Cookie() : isSecure(false), isHttpOnly(false) {} - -Cookie::Cookie(const std::string& name, const std::string& value) - : name(name), value(value), isSecure(false), isHttpOnly(false) {} - -Cookie::Cookie(SoupCookie* soupCookie) : isSecure(false), isHttpOnly(false) { - if (soupCookie == nullptr) { - return; - } - - const char* n = soup_cookie_get_name(soupCookie); - const char* v = soup_cookie_get_value(soupCookie); - const char* d = soup_cookie_get_domain(soupCookie); - const char* p = soup_cookie_get_path(soupCookie); - - if (n != nullptr) - name = std::string(n); - if (v != nullptr) - value = std::string(v); - if (d != nullptr) - domain = std::string(d); - if (p != nullptr) - path = std::string(p); - - GDateTime* expires = soup_cookie_get_expires(soupCookie); - if (expires != nullptr) { - gint64 unix_time = g_date_time_to_unix(expires); - expiresDate = unix_time * 1000; // Convert to milliseconds - } - - isSecure = soup_cookie_get_secure(soupCookie); - isHttpOnly = soup_cookie_get_http_only(soupCookie); - sameSite = sameSiteToString(soup_cookie_get_same_site_policy(soupCookie)); -} - -Cookie::Cookie(FlValue* map) : isSecure(false), isHttpOnly(false) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - name = get_fl_map_value(map, "name", ""); - value = get_fl_map_value(map, "value", ""); - domain = get_optional_fl_map_value(map, "domain"); - path = get_optional_fl_map_value(map, "path"); - - FlValue* expiresValue = fl_value_lookup_string(map, "expiresDate"); - if (expiresValue != nullptr && fl_value_get_type(expiresValue) == FL_VALUE_TYPE_INT) { - expiresDate = fl_value_get_int(expiresValue); - } - - isSecure = get_fl_map_value(map, "isSecure", false); - isHttpOnly = get_fl_map_value(map, "isHttpOnly", false); - sameSite = get_optional_fl_map_value(map, "sameSite"); -} - -SoupCookie* Cookie::toSoupCookie(const std::string& url) const { - // Parse URL to get domain if not provided - GUri* guri = g_uri_parse(url.c_str(), G_URI_FLAGS_NONE, nullptr); - const char* host = nullptr; - if (guri != nullptr) { - host = g_uri_get_host(guri); - } - - std::string cookieDomain = domain.value_or(host ? std::string(host) : ""); - std::string cookiePath = path.value_or("/"); - - SoupCookie* cookie = - soup_cookie_new(name.c_str(), value.c_str(), cookieDomain.c_str(), cookiePath.c_str(), - -1 // maxAge (-1 = session cookie) - ); - - if (cookie != nullptr) { - if (expiresDate.has_value()) { - gint64 unix_time = expiresDate.value() / 1000; // Convert from milliseconds - GDateTime* expires = g_date_time_new_from_unix_utc(unix_time); - if (expires != nullptr) { - soup_cookie_set_expires(cookie, expires); - g_date_time_unref(expires); - } - } - - soup_cookie_set_secure(cookie, isSecure); - soup_cookie_set_http_only(cookie, isHttpOnly); - - if (sameSite.has_value()) { - soup_cookie_set_same_site_policy(cookie, parseSameSite(sameSite.value())); - } - } - - if (guri != nullptr) { - g_uri_unref(guri); - } - - return cookie; -} - -FlValue* Cookie::toFlValue() const { - return to_fl_map({ - {"name", make_fl_value(name)}, - {"value", make_fl_value(value)}, - {"domain", make_fl_value(domain)}, - {"path", make_fl_value(path)}, - {"expiresDate", make_fl_value(expiresDate)}, - {"isSecure", make_fl_value(isSecure)}, - {"isHttpOnly", make_fl_value(isHttpOnly)}, - {"sameSite", make_fl_value(sameSite)}, - }); -} - -// === CookieManager === - -CookieManager::CookieManager(PluginInstance* plugin) - : ChannelDelegate(plugin->messenger(), METHOD_CHANNEL_NAME), - plugin_(plugin), - cookie_manager_(nullptr) {} - -CookieManager::~CookieManager() { - debugLog("dealloc CookieManager"); - plugin_ = nullptr; -} - -WebKitCookieManager* CookieManager::getCookieManager() { - if (cookie_manager_ == nullptr) { - // WPE WebKit 2.x uses NetworkSession API instead of WebContext - WebKitNetworkSession* session = webkit_network_session_get_default(); - if (session != nullptr) { - cookie_manager_ = webkit_network_session_get_cookie_manager(session); - } - } - return cookie_manager_; -} - -void CookieManager::HandleMethodCall(FlMethodCall* method_call) { - const gchar* method = fl_method_call_get_name(method_call); - FlValue* args = fl_method_call_get_args(method_call); - - if (string_equals(method, "setCookie")) { - std::string url = get_fl_map_value(args, "url", ""); - FlValue* cookieMap = fl_value_lookup_string(args, "cookie"); - - if (url.empty() || cookieMap == nullptr) { - fl_method_call_respond_success(method_call, fl_value_new_bool(FALSE), nullptr); - return; - } - - Cookie cookie(cookieMap); - - g_object_ref(method_call); - setCookie(url, cookie, [method_call](bool success) { - fl_method_call_respond_success(method_call, fl_value_new_bool(success), nullptr); - g_object_unref(method_call); - }); - } else if (string_equals(method, "getCookies")) { - std::string url = get_fl_map_value(args, "url", ""); - - if (url.empty()) { - fl_method_call_respond_success(method_call, fl_value_new_list(), nullptr); - return; - } - - g_object_ref(method_call); - getCookies(url, [method_call](std::vector cookies) { - g_autoptr(FlValue) result = fl_value_new_list(); - for (const auto& cookie : cookies) { - fl_value_append_take(result, cookie.toFlValue()); - } - fl_method_call_respond_success(method_call, result, nullptr); - g_object_unref(method_call); - }); - } else if (string_equals(method, "getCookie")) { - std::string url = get_fl_map_value(args, "url", ""); - std::string name = get_fl_map_value(args, "name", ""); - - if (url.empty() || name.empty()) { - fl_method_call_respond_success(method_call, fl_value_new_null(), nullptr); - return; - } - - g_object_ref(method_call); - getCookie(url, name, [method_call](std::optional cookie) { - if (cookie.has_value()) { - fl_method_call_respond_success(method_call, cookie.value().toFlValue(), nullptr); - } else { - fl_method_call_respond_success(method_call, fl_value_new_null(), nullptr); - } - g_object_unref(method_call); - }); - } else if (string_equals(method, "deleteCookie")) { - std::string url = get_fl_map_value(args, "url", ""); - std::string name = get_fl_map_value(args, "name", ""); - std::string domain = get_fl_map_value(args, "domain", ""); - std::string path = get_fl_map_value(args, "path", "/"); - - g_object_ref(method_call); - deleteCookie(url, name, domain, path, [method_call](bool success) { - fl_method_call_respond_success(method_call, fl_value_new_bool(success), nullptr); - g_object_unref(method_call); - }); - } else if (string_equals(method, "deleteCookies")) { - std::string url = get_fl_map_value(args, "url", ""); - std::string domain = get_fl_map_value(args, "domain", ""); - std::string path = get_fl_map_value(args, "path", "/"); - - g_object_ref(method_call); - deleteCookies(url, domain, path, [method_call](bool success) { - fl_method_call_respond_success(method_call, fl_value_new_bool(success), nullptr); - g_object_unref(method_call); - }); - } else if (string_equals(method, "deleteAllCookies")) { - g_object_ref(method_call); - deleteAllCookies([method_call](bool success) { - fl_method_call_respond_success(method_call, fl_value_new_bool(success), nullptr); - g_object_unref(method_call); - }); - } else if (string_equals(method, "getAllCookies")) { - g_object_ref(method_call); - getAllCookies([method_call](std::vector cookies) { - g_autoptr(FlValue) result = fl_value_new_list(); - for (const auto& cookie : cookies) { - fl_value_append_take(result, cookie.toFlValue()); - } - fl_method_call_respond_success(method_call, result, nullptr); - g_object_unref(method_call); - }); - } else { - fl_method_call_respond_not_implemented(method_call, nullptr); - } -} - -void CookieManager::setCookie(const std::string& url, const Cookie& cookie, - std::function callback) { - WebKitCookieManager* manager = getCookieManager(); - if (manager == nullptr) { - callback(false); - return; - } - - SoupCookie* soupCookie = cookie.toSoupCookie(url); - if (soupCookie == nullptr) { - callback(false); - return; - } - - // Store callback in a closure - auto* callbackPtr = new std::function(std::move(callback)); - - webkit_cookie_manager_add_cookie( - manager, soupCookie, - nullptr, // cancellable - [](GObject* source, GAsyncResult* result, gpointer user_data) { - auto* cb = static_cast*>(user_data); - - GError* error = nullptr; - gboolean success = - webkit_cookie_manager_add_cookie_finish(WEBKIT_COOKIE_MANAGER(source), result, &error); - - if (error != nullptr) { - errorLog(std::string("CookieManager: setCookie failed: ") + error->message); - g_error_free(error); - } - - (*cb)(success); - delete cb; - }, - callbackPtr); - - soup_cookie_free(soupCookie); -} - -void CookieManager::getCookies(const std::string& url, - std::function)> callback) { - WebKitCookieManager* manager = getCookieManager(); - if (manager == nullptr) { - callback({}); - return; - } - - auto* callbackPtr = new std::function)>(std::move(callback)); - - webkit_cookie_manager_get_cookies( - manager, url.c_str(), - nullptr, // cancellable - [](GObject* source, GAsyncResult* result, gpointer user_data) { - auto* cb = static_cast)>*>(user_data); - - GError* error = nullptr; - GList* cookies = - webkit_cookie_manager_get_cookies_finish(WEBKIT_COOKIE_MANAGER(source), result, &error); - - std::vector cookieList; - - if (error != nullptr) { - errorLog(std::string("CookieManager: getCookies failed: ") + error->message); - g_error_free(error); - } else if (cookies != nullptr) { - for (GList* l = cookies; l != nullptr; l = l->next) { - SoupCookie* soupCookie = static_cast(l->data); - cookieList.emplace_back(soupCookie); - } - g_list_free_full(cookies, reinterpret_cast(soup_cookie_free)); - } - - (*cb)(cookieList); - delete cb; - }, - callbackPtr); -} - -void CookieManager::getCookie(const std::string& url, const std::string& name, - std::function)> callback) { - getCookies(url, [name, callback = std::move(callback)](std::vector cookies) { - for (const auto& cookie : cookies) { - if (cookie.name == name) { - callback(cookie); - return; - } - } - callback(std::nullopt); - }); -} - -void CookieManager::deleteCookie(const std::string& url, const std::string& name, - const std::string& domain, const std::string& path, - std::function callback) { - WebKitCookieManager* manager = getCookieManager(); - if (manager == nullptr) { - callback(false); - return; - } - - // Determine the domain to use for fetching cookies - std::string cookieDomain = domain; - if (cookieDomain.empty() && !url.empty()) { - GUri* guri = g_uri_parse(url.c_str(), G_URI_FLAGS_NONE, nullptr); - if (guri != nullptr) { - const char* host = g_uri_get_host(guri); - if (host != nullptr) { - cookieDomain = std::string(host); - } - g_uri_unref(guri); - } - } - - // WPE WebKit requires the EXACT SoupCookie object to delete, not a minimal one. - // We must first fetch all cookies and find the matching one with all its attributes. - auto* callbackPtr = new std::function(std::move(callback)); - - // Capture parameters for the callback - struct DeleteContext { - WebKitCookieManager* manager; - std::string name; - std::string domain; - std::string path; - std::function* callback; - }; - - auto* ctx = new DeleteContext{manager, name, cookieDomain, path, callbackPtr}; - - webkit_cookie_manager_get_all_cookies( - manager, - nullptr, // cancellable - [](GObject* source, GAsyncResult* result, gpointer user_data) { - auto* ctx = static_cast(user_data); - - GError* error = nullptr; - GList* cookies = webkit_cookie_manager_get_all_cookies_finish( - WEBKIT_COOKIE_MANAGER(source), result, &error); - - if (error != nullptr) { - errorLog(std::string("CookieManager: deleteCookie fetch failed: ") + error->message); - g_error_free(error); - (*(ctx->callback))(false); - delete ctx->callback; - delete ctx; - return; - } - - // Find the matching cookie - SoupCookie* matchingCookie = nullptr; - for (GList* l = cookies; l != nullptr; l = l->next) { - SoupCookie* soupCookie = static_cast(l->data); - const char* cookieName = soup_cookie_get_name(soupCookie); - const char* cookieDomain = soup_cookie_get_domain(soupCookie); - const char* cookiePath = soup_cookie_get_path(soupCookie); - - if (cookieName != nullptr && strcmp(cookieName, ctx->name.c_str()) == 0) { - // Check domain match (if specified) - bool domainMatch = ctx->domain.empty() || - (cookieDomain != nullptr && - (strcmp(cookieDomain, ctx->domain.c_str()) == 0 || - // Also match with leading dot (e.g., ".example.com" matches "example.com") - (cookieDomain[0] == '.' && strcmp(cookieDomain + 1, ctx->domain.c_str()) == 0) || - (ctx->domain[0] == '.' && strcmp(cookieDomain, ctx->domain.c_str() + 1) == 0))); - - // Check path match (if not default) - bool pathMatch = ctx->path == "/" || - (cookiePath != nullptr && strcmp(cookiePath, ctx->path.c_str()) == 0); - - if (domainMatch && pathMatch) { - matchingCookie = soup_cookie_copy(soupCookie); - break; - } - } - } - - g_list_free_full(cookies, reinterpret_cast(soup_cookie_free)); - - if (matchingCookie == nullptr) { - // Cookie not found - consider this a success (nothing to delete) - (*(ctx->callback))(true); - delete ctx->callback; - delete ctx; - return; - } - - // Now delete the actual cookie with all its attributes - webkit_cookie_manager_delete_cookie( - ctx->manager, matchingCookie, - nullptr, // cancellable - [](GObject* source, GAsyncResult* result, gpointer user_data) { - auto* ctx = static_cast(user_data); - - GError* error = nullptr; - gboolean success = webkit_cookie_manager_delete_cookie_finish( - WEBKIT_COOKIE_MANAGER(source), result, &error); - - if (error != nullptr) { - errorLog(std::string("CookieManager: deleteCookie failed: ") + error->message); - g_error_free(error); - } - - (*(ctx->callback))(success); - delete ctx->callback; - delete ctx; - }, - ctx); - - soup_cookie_free(matchingCookie); - }, - ctx); -} - -void CookieManager::deleteCookies(const std::string& url, const std::string& domain, - const std::string& path, std::function callback) { - // Get all cookies for the URL and delete them - getCookies(url, - [this, domain, path, callback = std::move(callback)](std::vector cookies) { - if (cookies.empty()) { - callback(true); - return; - } - - auto* remaining = new std::atomic(cookies.size()); - auto* anyFailed = new std::atomic(false); - auto* sharedCallback = new std::function(callback); - - for (const auto& cookie : cookies) { - std::string cookieDomain = cookie.domain.value_or(""); - std::string cookiePath = cookie.path.value_or("/"); - - // Filter by domain if specified - if (!domain.empty() && cookieDomain != domain) { - size_t prev = remaining->fetch_sub(1); - if (prev == 1) { - (*sharedCallback)(!(*anyFailed)); - delete remaining; - delete anyFailed; - delete sharedCallback; - } - continue; - } - - deleteCookie("", cookie.name, cookieDomain, cookiePath, - [remaining, anyFailed, sharedCallback](bool success) { - if (!success) { - anyFailed->store(true); - } - size_t prev = remaining->fetch_sub(1); - if (prev == 1) { - (*sharedCallback)(!(*anyFailed)); - delete remaining; - delete anyFailed; - delete sharedCallback; - } - }); - } - }); -} - -void CookieManager::deleteAllCookies(std::function callback) { - // WPE WebKit 2.x uses NetworkSession API - WebKitNetworkSession* session = webkit_network_session_get_default(); - WebKitWebsiteDataManager* manager = - session != nullptr ? webkit_network_session_get_website_data_manager(session) : nullptr; - - if (manager == nullptr) { - callback(false); - return; - } - - auto* callbackPtr = new std::function(std::move(callback)); - - webkit_website_data_manager_clear( - manager, WEBKIT_WEBSITE_DATA_COOKIES, - 0, // timespan (0 = all) - nullptr, // cancellable - [](GObject* source, GAsyncResult* result, gpointer user_data) { - auto* cb = static_cast*>(user_data); - - GError* error = nullptr; - gboolean success = webkit_website_data_manager_clear_finish( - WEBKIT_WEBSITE_DATA_MANAGER(source), result, &error); - - if (error != nullptr) { - errorLog(std::string("CookieManager: deleteAllCookies failed: ") + error->message); - g_error_free(error); - } - - (*cb)(success); - delete cb; - }, - callbackPtr); -} - -void CookieManager::getAllCookies(std::function)> callback) { - WebKitCookieManager* manager = getCookieManager(); - if (manager == nullptr) { - callback({}); - return; - } - - auto* callbackPtr = new std::function)>(std::move(callback)); - - webkit_cookie_manager_get_all_cookies( - manager, - nullptr, // cancellable - [](GObject* source, GAsyncResult* result, gpointer user_data) { - auto* cb = static_cast)>*>(user_data); - - GError* error = nullptr; - GList* cookies = webkit_cookie_manager_get_all_cookies_finish( - WEBKIT_COOKIE_MANAGER(source), result, &error); - - std::vector cookieList; - - if (error != nullptr) { - errorLog(std::string("CookieManager: getAllCookies failed: ") + error->message); - g_error_free(error); - } else if (cookies != nullptr) { - for (GList* l = cookies; l != nullptr; l = l->next) { - SoupCookie* soupCookie = static_cast(l->data); - cookieList.emplace_back(soupCookie); - } - g_list_free_full(cookies, reinterpret_cast(soup_cookie_free)); - } - - (*cb)(cookieList); - delete cb; - }, - callbackPtr); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/cookie_manager.h b/flutter_inappwebview_linux/linux/cookie_manager.h deleted file mode 100644 index dfe579fd6d..0000000000 --- a/flutter_inappwebview_linux/linux/cookie_manager.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_COOKIE_MANAGER_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_COOKIE_MANAGER_H_ - -#include -#include - -#include -#include -#include -#include -#include - -#include "types/channel_delegate.h" - -namespace flutter_inappwebview_plugin { - -class PluginInstance; - -/** - * Represents a cookie. - */ -class Cookie { - public: - std::string name; - std::string value; - std::optional domain; - std::optional path; - std::optional expiresDate; // Unix timestamp in milliseconds - bool isSecure; - bool isHttpOnly; - std::optional sameSite; - - Cookie(); - Cookie(const std::string& name, const std::string& value); - Cookie(SoupCookie* soupCookie); - Cookie(FlValue* map); - ~Cookie() = default; - - SoupCookie* toSoupCookie(const std::string& url) const; - FlValue* toFlValue() const; -}; - -/** - * Manages cookies for WebKitGTK. - * Uses WebKitCookieManager and libsoup for cookie operations. - */ -class CookieManager : public ChannelDelegate { - public: - static constexpr const char* METHOD_CHANNEL_NAME = - "com.pichillilorenzo/flutter_inappwebview_cookiemanager"; - - CookieManager(PluginInstance* plugin); - ~CookieManager() override; - - /// Get the plugin instance - PluginInstance* plugin() const { return plugin_; } - - void HandleMethodCall(FlMethodCall* method_call) override; - - // Cookie operations - void setCookie(const std::string& url, const Cookie& cookie, std::function callback); - - void getCookies(const std::string& url, std::function)> callback); - - void getCookie(const std::string& url, const std::string& name, - std::function)> callback); - - void deleteCookie(const std::string& url, const std::string& name, const std::string& domain, - const std::string& path, std::function callback); - - void deleteCookies(const std::string& url, const std::string& domain, const std::string& path, - std::function callback); - - void deleteAllCookies(std::function callback); - - void getAllCookies(std::function)> callback); - - private: - PluginInstance* plugin_ = nullptr; - WebKitCookieManager* cookie_manager_; - - WebKitCookieManager* getCookieManager(); -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_COOKIE_MANAGER_H_ diff --git a/flutter_inappwebview_linux/linux/credential_database.cc b/flutter_inappwebview_linux/linux/credential_database.cc deleted file mode 100644 index ead9cdcf92..0000000000 --- a/flutter_inappwebview_linux/linux/credential_database.cc +++ /dev/null @@ -1,594 +0,0 @@ -#include "credential_database.h" - -#include -#include - -#include -#include -#include -#include - -#include - -#include "plugin_instance.h" -#include "utils/flutter.h" -#include "utils/log.h" -#include "utils/util.h" - -namespace flutter_inappwebview_plugin { - -using json = nlohmann::json; - -namespace { -bool string_equals(const gchar* a, const char* b) { - return strcmp(a, b) == 0; -} -} // namespace - -// === Schema Definition === - -const SecretSchema* CredentialDatabase::getSchema() { - static const SecretSchema schema = { - "com.pichillilorenzo.flutter_inappwebview.HttpAuth", - SECRET_SCHEMA_NONE, - { - {"appId", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"host", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"port", SECRET_SCHEMA_ATTRIBUTE_INTEGER}, - {"protocol", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"realm", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"username", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {NULL, (SecretSchemaAttributeType)0} - } - }; - return &schema; -} - -// === ProtectionSpace === - -ProtectionSpace::ProtectionSpace(FlValue* map) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - host = get_fl_map_value(map, "host", ""); - port = get_fl_map_value(map, "port", 0); - protocol = get_optional_fl_map_value(map, "protocol"); - realm = get_optional_fl_map_value(map, "realm"); -} - -FlValue* ProtectionSpace::toFlValue() const { - return to_fl_map({ - {"host", make_fl_value(host)}, - {"port", make_fl_value(port)}, - {"protocol", make_fl_value(protocol)}, - {"realm", make_fl_value(realm)}, - }); -} - -bool ProtectionSpace::operator==(const ProtectionSpace& other) const { - return host == other.host && port == other.port && - protocol == other.protocol && realm == other.realm; -} - -// === Credential === - -Credential::Credential(const std::string& username, const std::string& password) - : username(username), password(password) {} - -Credential::Credential(FlValue* map) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - username = get_fl_map_value(map, "username", ""); - password = get_fl_map_value(map, "password", ""); -} - -FlValue* Credential::toFlValue() const { - return to_fl_map({ - {"username", make_fl_value(username)}, - {"password", make_fl_value(password)}, - }); -} - -// === CredentialDatabase === - -std::string CredentialDatabase::makeKey(const ProtectionSpace& ps) { - std::ostringstream oss; - oss << ps.host << ":" << ps.port << ":" - << ps.protocol.value_or("") << ":" - << ps.realm.value_or(""); - return oss.str(); -} - -std::string CredentialDatabase::makeLabel(const ProtectionSpace& ps, const std::string& username) { - std::ostringstream oss; - oss << "InAppWebView: " << username << "@" << ps.host; - if (ps.port != 0 && ps.port != 80 && ps.port != 443) { - oss << ":" << ps.port; - } - if (ps.realm.has_value() && !ps.realm->empty()) { - oss << " (" << ps.realm.value() << ")"; - } - return oss.str(); -} - -ProtectionSpace CredentialDatabase::fromKey(const std::string& key) { - ProtectionSpace ps; - std::vector parts; - std::istringstream iss(key); - std::string part; - - // Split by ':' - while (std::getline(iss, part, ':')) { - parts.push_back(part); - } - - // Handle case where key ends with colons (empty parts at end) - size_t colonCount = std::count(key.begin(), key.end(), ':'); - while (parts.size() <= colonCount) { - parts.push_back(""); - } - - if (parts.size() > 0) { - ps.host = parts[0]; - } - if (parts.size() > 1 && !parts[1].empty()) { - try { - ps.port = std::stoi(parts[1]); - } catch (...) { - ps.port = 0; - } - } - if (parts.size() > 2 && !parts[2].empty()) { - ps.protocol = parts[2]; - } - if (parts.size() > 3 && !parts[3].empty()) { - ps.realm = parts[3]; - } - - return ps; -} - -std::string CredentialDatabase::getIndexPath(const std::string& app_id) { - const char* xdg_data_home = getenv("XDG_DATA_HOME"); - std::string base_dir; - - if (xdg_data_home != nullptr && strlen(xdg_data_home) > 0) { - base_dir = xdg_data_home; - } else { - const char* home = getenv("HOME"); - if (home != nullptr) { - base_dir = std::string(home) + "/.local/share"; - } else { - base_dir = "/tmp"; - } - } - - std::string dir = base_dir + "/flutter_inappwebview"; - mkdir(dir.c_str(), 0700); - - std::string app_dir = dir + "/" + app_id; - mkdir(app_dir.c_str(), 0700); - - return app_dir + "/credential_index.json"; -} - -void CredentialDatabase::loadIndex() { - credentials_index_.clear(); - - std::ifstream file(index_path_); - if (!file.is_open()) { - return; - } - - try { - json j; - file >> j; - - if (j.is_object()) { - for (auto& [key, usernames] : j.items()) { - std::vector users; - if (usernames.is_array()) { - for (auto& u : usernames) { - if (u.is_string()) { - users.push_back(u.get()); - } - } - } - credentials_index_[key] = users; - } - } - } catch (const std::exception& e) { - errorLog(std::string("CredentialDatabase: Failed to load index: ") + e.what()); - credentials_index_.clear(); - } -} - -void CredentialDatabase::saveIndex() { - json j = json::object(); - - for (const auto& [key, usernames] : credentials_index_) { - j[key] = usernames; - } - - std::ofstream file(index_path_); - if (file.is_open()) { - file << j.dump(2); - file.close(); - chmod(index_path_.c_str(), 0600); - } -} - -CredentialDatabase::CredentialDatabase(PluginInstance* plugin) - : ChannelDelegate(plugin->messenger(), METHOD_CHANNEL_NAME), - plugin_(plugin) { - app_id_ = resolve_application_id_sanitized(); - index_path_ = getIndexPath(app_id_); - loadIndex(); -} - -CredentialDatabase::~CredentialDatabase() { - debugLog("dealloc CredentialDatabase"); - plugin_ = nullptr; -} - -void CredentialDatabase::HandleMethodCall(FlMethodCall* method_call) { - const gchar* method = fl_method_call_get_name(method_call); - FlValue* args = fl_method_call_get_args(method_call); - - if (string_equals(method, "getAllAuthCredentials")) { - auto all = getAllAuthCredentials(); - - g_autoptr(FlValue) result = fl_value_new_list(); - - for (const auto& [ps, creds] : all) { - FlValue* creds_list = fl_value_new_list(); - for (const auto& cred : creds) { - fl_value_append_take(creds_list, cred.toFlValue()); - } - - FlValue* entry = to_fl_map({ - {"protectionSpace", ps.toFlValue()}, - {"credentials", creds_list}, - }); - - fl_value_append_take(result, entry); - } - - fl_method_call_respond_success(method_call, result, nullptr); - - } else if (string_equals(method, "getHttpAuthCredentials")) { - std::string host = get_fl_map_value(args, "host", ""); - int port = get_fl_map_value(args, "port", 0); - auto protocol = get_optional_fl_map_value(args, "protocol"); - auto realm = get_optional_fl_map_value(args, "realm"); - - ProtectionSpace ps; - ps.host = host; - ps.port = port; - ps.protocol = protocol; - ps.realm = realm; - - auto credentials = getHttpAuthCredentials(ps); - - g_autoptr(FlValue) result = fl_value_new_list(); - for (const auto& cred : credentials) { - fl_value_append_take(result, cred.toFlValue()); - } - - fl_method_call_respond_success(method_call, result, nullptr); - - } else if (string_equals(method, "setHttpAuthCredential")) { - std::string host = get_fl_map_value(args, "host", ""); - int port = get_fl_map_value(args, "port", 0); - auto protocol = get_optional_fl_map_value(args, "protocol"); - auto realm = get_optional_fl_map_value(args, "realm"); - std::string username = get_fl_map_value(args, "username", ""); - std::string password = get_fl_map_value(args, "password", ""); - - ProtectionSpace ps; - ps.host = host; - ps.port = port; - ps.protocol = protocol; - ps.realm = realm; - - Credential cred(username, password); - - setHttpAuthCredential(ps, cred); - - fl_method_call_respond_success(method_call, fl_value_new_bool(TRUE), nullptr); - - } else if (string_equals(method, "removeHttpAuthCredential")) { - std::string host = get_fl_map_value(args, "host", ""); - int port = get_fl_map_value(args, "port", 0); - auto protocol = get_optional_fl_map_value(args, "protocol"); - auto realm = get_optional_fl_map_value(args, "realm"); - std::string username = get_fl_map_value(args, "username", ""); - std::string password = get_fl_map_value(args, "password", ""); - - ProtectionSpace ps; - ps.host = host; - ps.port = port; - ps.protocol = protocol; - ps.realm = realm; - - Credential cred(username, password); - - removeHttpAuthCredential(ps, cred); - - fl_method_call_respond_success(method_call, fl_value_new_bool(TRUE), nullptr); - - } else if (string_equals(method, "removeHttpAuthCredentials")) { - std::string host = get_fl_map_value(args, "host", ""); - int port = get_fl_map_value(args, "port", 0); - auto protocol = get_optional_fl_map_value(args, "protocol"); - auto realm = get_optional_fl_map_value(args, "realm"); - - ProtectionSpace ps; - ps.host = host; - ps.port = port; - ps.protocol = protocol; - ps.realm = realm; - - removeHttpAuthCredentials(ps); - - fl_method_call_respond_success(method_call, fl_value_new_bool(TRUE), nullptr); - - } else if (string_equals(method, "clearAllAuthCredentials")) { - clearAllAuthCredentials(); - - fl_method_call_respond_success(method_call, fl_value_new_bool(TRUE), nullptr); - - } else { - fl_method_call_respond_not_implemented(method_call, nullptr); - } -} - -std::vector>> -CredentialDatabase::getAllAuthCredentials() { - std::vector>> result; - - for (const auto& [key, usernames] : credentials_index_) { - // Parse key back to ProtectionSpace - ProtectionSpace ps = fromKey(key); - - // Lookup each credential from libsecret - std::vector creds; - for (const auto& username : usernames) { - auto cred = lookupCredential(ps, username); - if (cred.has_value()) { - creds.push_back(cred.value()); - } - } - - if (!creds.empty()) { - result.push_back({ps, creds}); - } - } - - return result; -} - -std::vector CredentialDatabase::getHttpAuthCredentials( - const ProtectionSpace& protectionSpace) { - std::string key = makeKey(protectionSpace); - - auto it = credentials_index_.find(key); - if (it == credentials_index_.end()) { - return {}; - } - - std::vector creds; - for (const auto& username : it->second) { - auto cred = lookupCredential(protectionSpace, username); - if (cred.has_value()) { - creds.push_back(cred.value()); - } - } - - return creds; -} - -std::optional CredentialDatabase::lookupCredential( - const ProtectionSpace& protectionSpace, const std::string& username) { - GError* error = nullptr; - - gchar* password = secret_password_lookup_sync( - getSchema(), - nullptr, - &error, - "appId", app_id_.c_str(), - "host", protectionSpace.host.c_str(), - "port", protectionSpace.port, - "protocol", protectionSpace.protocol.value_or("").c_str(), - "realm", protectionSpace.realm.value_or("").c_str(), - "username", username.c_str(), - NULL); - - if (error != nullptr) { - errorLog(std::string("CredentialDatabase: Failed to lookup credential: ") + error->message); - g_error_free(error); - return std::nullopt; - } - - if (password == nullptr) { - return std::nullopt; - } - - Credential cred(username, password); - secret_password_free(password); - - return cred; -} - -std::optional CredentialDatabase::lookupFirstCredential( - const ProtectionSpace& protectionSpace) { - std::string key = makeKey(protectionSpace); - - auto it = credentials_index_.find(key); - if (it == credentials_index_.end() || it->second.empty()) { - return std::nullopt; - } - - // Return the first available credential - for (const auto& username : it->second) { - auto cred = lookupCredential(protectionSpace, username); - if (cred.has_value()) { - return cred; - } - } - - return std::nullopt; -} - -void CredentialDatabase::setHttpAuthCredential(const ProtectionSpace& protectionSpace, - const Credential& credential) { - GError* error = nullptr; - - std::string label = makeLabel(protectionSpace, credential.username); - - gboolean stored = secret_password_store_sync( - getSchema(), - SECRET_COLLECTION_DEFAULT, - label.c_str(), - credential.password.c_str(), - nullptr, - &error, - "appId", app_id_.c_str(), - "host", protectionSpace.host.c_str(), - "port", protectionSpace.port, - "protocol", protectionSpace.protocol.value_or("").c_str(), - "realm", protectionSpace.realm.value_or("").c_str(), - "username", credential.username.c_str(), - NULL); - - if (error != nullptr) { - errorLog(std::string("CredentialDatabase: Failed to store credential: ") + error->message); - g_error_free(error); - return; - } - - if (!stored) { - errorLog("CredentialDatabase: Failed to store credential (unknown error)"); - return; - } - - // Update index - std::string key = makeKey(protectionSpace); - auto& usernames = credentials_index_[key]; - - // Add username if not already present - if (std::find(usernames.begin(), usernames.end(), credential.username) == usernames.end()) { - usernames.push_back(credential.username); - } - - saveIndex(); -} - -void CredentialDatabase::removeHttpAuthCredential(const ProtectionSpace& protectionSpace, - const Credential& credential) { - GError* error = nullptr; - - secret_password_clear_sync( - getSchema(), - nullptr, - &error, - "appId", app_id_.c_str(), - "host", protectionSpace.host.c_str(), - "port", protectionSpace.port, - "protocol", protectionSpace.protocol.value_or("").c_str(), - "realm", protectionSpace.realm.value_or("").c_str(), - "username", credential.username.c_str(), - NULL); - - if (error != nullptr) { - errorLog(std::string("CredentialDatabase: Failed to remove credential: ") + error->message); - g_error_free(error); - return; - } - - // Update index - std::string key = makeKey(protectionSpace); - auto it = credentials_index_.find(key); - if (it != credentials_index_.end()) { - auto& usernames = it->second; - usernames.erase( - std::remove(usernames.begin(), usernames.end(), credential.username), - usernames.end()); - if (usernames.empty()) { - credentials_index_.erase(it); - } - } - - saveIndex(); -} - -void CredentialDatabase::removeHttpAuthCredentials(const ProtectionSpace& protectionSpace) { - std::string key = makeKey(protectionSpace); - - auto it = credentials_index_.find(key); - if (it == credentials_index_.end()) { - return; - } - - // Remove all credentials for this protection space - for (const auto& username : it->second) { - GError* error = nullptr; - - secret_password_clear_sync( - getSchema(), - nullptr, - &error, - "appId", app_id_.c_str(), - "host", protectionSpace.host.c_str(), - "port", protectionSpace.port, - "protocol", protectionSpace.protocol.value_or("").c_str(), - "realm", protectionSpace.realm.value_or("").c_str(), - "username", username.c_str(), - NULL); - - if (error != nullptr) { - errorLog(std::string("CredentialDatabase: Failed to remove credential: ") + error->message); - g_error_free(error); - } - } - - credentials_index_.erase(it); - saveIndex(); -} - -void CredentialDatabase::clearAllAuthCredentials() { - // Remove all credentials from libsecret - for (const auto& [key, usernames] : credentials_index_) { - ProtectionSpace ps = fromKey(key); - - for (const auto& username : usernames) { - GError* error = nullptr; - - secret_password_clear_sync( - getSchema(), - nullptr, - &error, - "appId", app_id_.c_str(), - "host", ps.host.c_str(), - "port", ps.port, - "protocol", ps.protocol.value_or("").c_str(), - "realm", ps.realm.value_or("").c_str(), - "username", username.c_str(), - NULL); - - if (error != nullptr) { - g_error_free(error); - } - } - } - - credentials_index_.clear(); - - // Remove the index file - unlink(index_path_.c_str()); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/credential_database.h b/flutter_inappwebview_linux/linux/credential_database.h deleted file mode 100644 index 4a0826e760..0000000000 --- a/flutter_inappwebview_linux/linux/credential_database.h +++ /dev/null @@ -1,129 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CREDENTIAL_DATABASE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_CREDENTIAL_DATABASE_H_ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "types/channel_delegate.h" - -namespace flutter_inappwebview_plugin { - -class PluginInstance; - -/** - * Represents a URL protection space for HTTP authentication. - */ -struct ProtectionSpace { - std::string host; - int port = 0; - std::optional protocol; - std::optional realm; - - ProtectionSpace() = default; - ProtectionSpace(FlValue* map); - - FlValue* toFlValue() const; - - // Comparison for map usage - bool operator==(const ProtectionSpace& other) const; -}; - -/** - * Represents a URL credential (username/password pair). - */ -struct Credential { - std::string username; - std::string password; - - Credential() = default; - Credential(const std::string& username, const std::string& password); - Credential(FlValue* map); - - FlValue* toFlValue() const; -}; - -/** - * Manages HTTP authentication credentials using libsecret for secure storage. - * - * Credentials are stored in the system keyring (gnome-keyring, KDE Wallet, etc.) - * using the Secret Service D-Bus API. - * - * Schema: com.pichillilorenzo.flutter_inappwebview.HttpAuth - * Attributes: appId, host, port, protocol, realm, username - */ -class CredentialDatabase : public ChannelDelegate { - public: - static constexpr const char* METHOD_CHANNEL_NAME = - "com.pichillilorenzo/flutter_inappwebview_credential_database"; - - explicit CredentialDatabase(PluginInstance* plugin); - ~CredentialDatabase() override; - - /// Get the plugin instance - PluginInstance* plugin() const { return plugin_; } - - void HandleMethodCall(FlMethodCall* method_call) override; - - // Credential operations - std::vector>> getAllAuthCredentials(); - - std::vector getHttpAuthCredentials(const ProtectionSpace& protectionSpace); - - /** - * Lookup a single credential by username. - * Used for USE_SAVED_CREDENTIAL action. - */ - std::optional lookupCredential(const ProtectionSpace& protectionSpace, - const std::string& username); - - /** - * Lookup the first available credential for a protection space. - * Used when username is not specified. - */ - std::optional lookupFirstCredential(const ProtectionSpace& protectionSpace); - - void setHttpAuthCredential(const ProtectionSpace& protectionSpace, const Credential& credential); - - void removeHttpAuthCredential(const ProtectionSpace& protectionSpace, - const Credential& credential); - - void removeHttpAuthCredentials(const ProtectionSpace& protectionSpace); - - void clearAllAuthCredentials(); - - private: - PluginInstance* plugin_ = nullptr; - - // The libsecret schema for HTTP auth credentials - static const SecretSchema* getSchema(); - - // In-memory index of stored credentials (for getAllAuthCredentials) - // Key: "host:port:protocol:realm", Value: list of usernames - std::map> credentials_index_; - std::string index_path_; - - // Load/save the credential index (just usernames, not passwords) - void loadIndex(); - void saveIndex(); - static std::string getIndexPath(const std::string& app_id); - static std::string makeKey(const ProtectionSpace& ps); - - // Generate a human-readable label for the credential - static std::string makeLabel(const ProtectionSpace& ps, const std::string& username); - - // Parse key back to ProtectionSpace - static ProtectionSpace fromKey(const std::string& key); - - std::string app_id_; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_CREDENTIAL_DATABASE_H_ diff --git a/flutter_inappwebview_linux/linux/find_interaction/find_interaction_channel_delegate.cc b/flutter_inappwebview_linux/linux/find_interaction/find_interaction_channel_delegate.cc deleted file mode 100644 index 07bc30668c..0000000000 --- a/flutter_inappwebview_linux/linux/find_interaction/find_interaction_channel_delegate.cc +++ /dev/null @@ -1,114 +0,0 @@ -#include "find_interaction_channel_delegate.h" - -#include - -#include "find_interaction_controller.h" -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -FindInteractionChannelDelegate::FindInteractionChannelDelegate( - FindInteractionController* controller, FlBinaryMessenger* messenger, - const std::string& channelName) - : ChannelDelegate(messenger, channelName), - findInteractionController_(controller) {} - -FindInteractionChannelDelegate::~FindInteractionChannelDelegate() { - findInteractionController_ = nullptr; -} - -void FindInteractionChannelDelegate::HandleMethodCall( - FlMethodCall* method_call) { - const gchar* methodName = fl_method_call_get_name(method_call); - FlValue* args = fl_method_call_get_args(method_call); - - if (strcmp(methodName, "findAll") == 0) { - if (findInteractionController_) { - std::string find = get_fl_map_value(args, "find", ""); - if (!find.empty()) { - findInteractionController_->findAll(find); - } - } - g_autoptr(FlValue) result = fl_value_new_bool(true); - fl_method_call_respond_success(method_call, result, nullptr); - return; - } - - if (strcmp(methodName, "findNext") == 0) { - if (findInteractionController_) { - bool forward = get_fl_map_value(args, "forward", true); - findInteractionController_->findNext(forward); - } - g_autoptr(FlValue) result = fl_value_new_bool(true); - fl_method_call_respond_success(method_call, result, nullptr); - return; - } - - if (strcmp(methodName, "clearMatches") == 0) { - if (findInteractionController_) { - findInteractionController_->clearMatches(); - } - g_autoptr(FlValue) result = fl_value_new_bool(true); - fl_method_call_respond_success(method_call, result, nullptr); - return; - } - - if (strcmp(methodName, "setSearchText") == 0) { - if (findInteractionController_) { - std::string searchText = - get_fl_map_value(args, "searchText", ""); - findInteractionController_->setSearchText(searchText); - } - g_autoptr(FlValue) result = fl_value_new_bool(true); - fl_method_call_respond_success(method_call, result, nullptr); - return; - } - - if (strcmp(methodName, "getSearchText") == 0) { - if (findInteractionController_) { - auto searchText = findInteractionController_->getSearchText(); - if (searchText.has_value()) { - g_autoptr(FlValue) result = fl_value_new_string(searchText->c_str()); - fl_method_call_respond_success(method_call, result, nullptr); - } else { - fl_method_call_respond_success(method_call, nullptr, nullptr); - } - } else { - fl_method_call_respond_success(method_call, nullptr, nullptr); - } - return; - } - - if (strcmp(methodName, "getActiveFindSession") == 0) { - if (findInteractionController_) { - auto findSession = findInteractionController_->getActiveFindSession(); - if (findSession.has_value()) { - g_autoptr(FlValue) result = findSession->toFlValue(); - fl_method_call_respond_success(method_call, result, nullptr); - } else { - fl_method_call_respond_success(method_call, nullptr, nullptr); - } - } else { - fl_method_call_respond_success(method_call, nullptr, nullptr); - } - return; - } - - fl_method_call_respond_not_implemented(method_call, nullptr); -} - -void FindInteractionChannelDelegate::onFindResultReceived( - int32_t activeMatchOrdinal, int32_t numberOfMatches, - bool isDoneCounting) const { - if (channel_ == nullptr) return; - - g_autoptr(FlValue) args = to_fl_map({ - {"activeMatchOrdinal", make_fl_value(activeMatchOrdinal)}, - {"numberOfMatches", make_fl_value(numberOfMatches)}, - {"isDoneCounting", make_fl_value(isDoneCounting)}, - }); - - invokeMethod("onFindResultReceived", args); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/find_interaction/find_interaction_channel_delegate.h b/flutter_inappwebview_linux/linux/find_interaction/find_interaction_channel_delegate.h deleted file mode 100644 index 3353d8e377..0000000000 --- a/flutter_inappwebview_linux/linux/find_interaction/find_interaction_channel_delegate.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_FIND_INTERACTION_CHANNEL_DELEGATE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_FIND_INTERACTION_CHANNEL_DELEGATE_H_ - -#include - -#include -#include - -#include "../types/channel_delegate.h" - -namespace flutter_inappwebview_plugin { - -class FindInteractionController; - -class FindInteractionChannelDelegate : public ChannelDelegate { - public: - FindInteractionChannelDelegate(FindInteractionController* controller, - FlBinaryMessenger* messenger, - const std::string& channelName); - ~FindInteractionChannelDelegate() override; - - void HandleMethodCall(FlMethodCall* method_call) override; - - void onFindResultReceived(int32_t activeMatchOrdinal, - int32_t numberOfMatches, - bool isDoneCounting) const; - - private: - FindInteractionController* findInteractionController_; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_FIND_INTERACTION_CHANNEL_DELEGATE_H_ diff --git a/flutter_inappwebview_linux/linux/find_interaction/find_interaction_controller.cc b/flutter_inappwebview_linux/linux/find_interaction/find_interaction_controller.cc deleted file mode 100644 index 6e9010b03a..0000000000 --- a/flutter_inappwebview_linux/linux/find_interaction/find_interaction_controller.cc +++ /dev/null @@ -1,153 +0,0 @@ -#include "find_interaction_controller.h" - -#include "find_interaction_channel_delegate.h" -#include "../in_app_webview/in_app_webview.h" -#include "../utils/log.h" - -namespace flutter_inappwebview_plugin { - -FindInteractionController::FindInteractionController(InAppWebView* webView) - : webView_(webView) { - // Connect to find controller signals - if (webView_ && webView_->webview()) { - WebKitFindController* find_controller = - webkit_web_view_get_find_controller(webView_->webview()); - if (find_controller) { - counted_matches_handler_id_ = g_signal_connect( - find_controller, "counted-matches", - G_CALLBACK(FindInteractionController::OnCountedMatches), this); - found_text_handler_id_ = - g_signal_connect(find_controller, "found-text", - G_CALLBACK(FindInteractionController::OnFoundText), this); - failed_to_find_text_handler_id_ = g_signal_connect( - find_controller, "failed-to-find-text", - G_CALLBACK(FindInteractionController::OnFailedToFindText), this); - } - } -} - -void FindInteractionController::attachChannel(FlBinaryMessenger* messenger, - const std::string& id) { - std::string channelName = std::string(METHOD_CHANNEL_NAME_PREFIX) + id; - channelDelegate_ = std::make_unique( - this, messenger, channelName); -} - -FindInteractionController::~FindInteractionController() { - dispose(); -} - -void FindInteractionController::findAll(const std::string& find) { - if (!webView_ || !webView_->webview()) return; - - searchText_ = find; - WebKitFindController* find_controller = - webkit_web_view_get_find_controller(webView_->webview()); - webkit_find_controller_search(find_controller, find.c_str(), - WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE, G_MAXUINT); -} - -void FindInteractionController::findNext(bool forward) { - if (!webView_ || !webView_->webview()) return; - - WebKitFindController* find_controller = - webkit_web_view_get_find_controller(webView_->webview()); - if (forward) { - webkit_find_controller_search_next(find_controller); - } else { - webkit_find_controller_search_previous(find_controller); - } -} - -void FindInteractionController::clearMatches() { - if (!webView_ || !webView_->webview()) return; - - WebKitFindController* find_controller = - webkit_web_view_get_find_controller(webView_->webview()); - webkit_find_controller_search_finish(find_controller); - activeFindSession_ = std::nullopt; -} - -void FindInteractionController::setSearchText(const std::string& searchText) { - searchText_ = searchText; - // Note: WebKit doesn't have a separate "set search text" API, - // the search text is set when calling search() -} - -std::optional FindInteractionController::getSearchText() const { - if (!webView_ || !webView_->webview()) return std::nullopt; - - WebKitFindController* find_controller = - webkit_web_view_get_find_controller(webView_->webview()); - const gchar* text = webkit_find_controller_get_search_text(find_controller); - if (text) { - return std::string(text); - } - return searchText_; -} - -std::optional FindInteractionController::getActiveFindSession() const { - return activeFindSession_; -} - -void FindInteractionController::OnCountedMatches( - WebKitFindController* find_controller, guint match_count, - gpointer user_data) { - if (!user_data) return; - auto* controller = static_cast(user_data); - if (controller->channelDelegate_) { - controller->activeFindSession_ = FindSession(static_cast(match_count), -1); - controller->channelDelegate_->onFindResultReceived(-1, static_cast(match_count), true); - } -} - -void FindInteractionController::OnFoundText( - WebKitFindController* find_controller, guint match_count, - gpointer user_data) { - if (!user_data) return; - auto* controller = static_cast(user_data); - if (controller->channelDelegate_) { - controller->channelDelegate_->onFindResultReceived(-1, static_cast(match_count), false); - } -} - -void FindInteractionController::OnFailedToFindText( - WebKitFindController* find_controller, gpointer user_data) { - if (!user_data) return; - auto* controller = static_cast(user_data); - if (controller->channelDelegate_) { - controller->activeFindSession_ = FindSession(0, 0); - controller->channelDelegate_->onFindResultReceived(0, 0, true); - } -} - -void FindInteractionController::dispose() { - if (webView_ && webView_->webview()) { - WebKitFindController* find_controller = - webkit_web_view_get_find_controller(webView_->webview()); - if (find_controller) { - if (counted_matches_handler_id_ > 0) { - g_signal_handler_disconnect(find_controller, counted_matches_handler_id_); - counted_matches_handler_id_ = 0; - } - if (found_text_handler_id_ > 0) { - g_signal_handler_disconnect(find_controller, found_text_handler_id_); - found_text_handler_id_ = 0; - } - if (failed_to_find_text_handler_id_ > 0) { - g_signal_handler_disconnect(find_controller, failed_to_find_text_handler_id_); - failed_to_find_text_handler_id_ = 0; - } - } - } - - if (channelDelegate_) { - channelDelegate_.reset(); - } - - webView_ = nullptr; - activeFindSession_ = std::nullopt; - searchText_ = std::nullopt; -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/find_interaction/find_interaction_controller.h b/flutter_inappwebview_linux/linux/find_interaction/find_interaction_controller.h deleted file mode 100644 index 816cd582ea..0000000000 --- a/flutter_inappwebview_linux/linux/find_interaction/find_interaction_controller.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_FIND_INTERACTION_CONTROLLER_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_FIND_INTERACTION_CONTROLLER_H_ - -#include -#include - -#include -#include -#include - -#include "../types/find_session.h" - -namespace flutter_inappwebview_plugin { - -class InAppWebView; -class FindInteractionChannelDelegate; - -class FindInteractionController { - public: - static constexpr const char* METHOD_CHANNEL_NAME_PREFIX = - "com.pichillilorenzo/flutter_inappwebview_find_interaction_"; - - FindInteractionController(InAppWebView* webView); - ~FindInteractionController(); - - // Attach the method channel with the given ID (called after texture_id is known) - void attachChannel(FlBinaryMessenger* messenger, const std::string& id); - - void findAll(const std::string& find); - void findNext(bool forward); - void clearMatches(); - void setSearchText(const std::string& searchText); - std::optional getSearchText() const; - std::optional getActiveFindSession() const; - - void dispose(); - - // Signal handlers - static void OnCountedMatches(WebKitFindController* find_controller, - guint match_count, gpointer user_data); - static void OnFoundText(WebKitFindController* find_controller, - guint match_count, gpointer user_data); - static void OnFailedToFindText(WebKitFindController* find_controller, - gpointer user_data); - - InAppWebView* webView_; - std::unique_ptr channelDelegate_; - std::optional searchText_; - std::optional activeFindSession_; - - private: - gulong counted_matches_handler_id_ = 0; - gulong found_text_handler_id_ = 0; - gulong failed_to_find_text_handler_id_ = 0; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_FIND_INTERACTION_CONTROLLER_H_ diff --git a/flutter_inappwebview_linux/linux/flutter_inappwebview_linux_plugin.cc b/flutter_inappwebview_linux/linux/flutter_inappwebview_linux_plugin.cc deleted file mode 100644 index b6c9cc5a93..0000000000 --- a/flutter_inappwebview_linux/linux/flutter_inappwebview_linux_plugin.cc +++ /dev/null @@ -1,182 +0,0 @@ -#include "include/flutter_inappwebview_linux/flutter_inappwebview_linux_plugin.h" - -#include "flutter_inappwebview_linux_plugin_private.h" -#include "plugin_instance.h" - -#include -#include -#include - -#include -#include - -#include "cookie_manager.h" -#include "credential_database.h" -#include "headless_in_app_webview/headless_in_app_webview_manager.h" -#include "in_app_browser/in_app_browser_manager.h" -#include "in_app_webview/in_app_webview_manager.h" -#include "proxy_manager.h" -#include "utils/software_rendering.h" -#include "web_storage_manager.h" -#include "webview_environment.h" - -#define FLUTTER_INAPPWEBVIEW_LINUX_PLUGIN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), flutter_inappwebview_linux_plugin_get_type(), \ - FlutterInappwebviewLinuxPlugin)) - -struct _FlutterInappwebviewLinuxPlugin { - GObject parent_instance; - FlPluginRegistrar* registrar; - - // C++ plugin instance for passing to managers - std::unique_ptr plugin_instance; - - // Managers are owned by the GObject - std::unique_ptr in_app_webview_manager; - std::unique_ptr headless_in_app_webview_manager; - std::unique_ptr in_app_browser_manager; - std::unique_ptr cookie_manager; - std::unique_ptr credential_database; - std::unique_ptr proxy_manager; - std::unique_ptr web_storage_manager; - std::unique_ptr webview_environment; -}; - -G_DEFINE_TYPE(FlutterInappwebviewLinuxPlugin, flutter_inappwebview_linux_plugin, - g_object_get_type()) - -static void flutter_inappwebview_linux_plugin_dispose(GObject* object) { - FlutterInappwebviewLinuxPlugin* self = FLUTTER_INAPPWEBVIEW_LINUX_PLUGIN(object); - - // Clean up the managers - self->in_app_webview_manager.reset(); - self->headless_in_app_webview_manager.reset(); - self->in_app_browser_manager.reset(); - self->cookie_manager.reset(); - self->credential_database.reset(); - self->proxy_manager.reset(); - self->web_storage_manager.reset(); - self->webview_environment.reset(); - - // Clean up the plugin instance last (after managers are gone) - self->plugin_instance.reset(); - - G_OBJECT_CLASS(flutter_inappwebview_linux_plugin_parent_class)->dispose(object); -} - -static void flutter_inappwebview_linux_plugin_class_init( - FlutterInappwebviewLinuxPluginClass* klass) { - G_OBJECT_CLASS(klass)->dispose = flutter_inappwebview_linux_plugin_dispose; -} - -static void flutter_inappwebview_linux_plugin_init(FlutterInappwebviewLinuxPlugin* self) { - self->registrar = nullptr; - // Note: in_app_webview_manager is initialized by its default constructor -} - -void flutter_inappwebview_linux_plugin_register_with_registrar(FlPluginRegistrar* registrar) { - // === CRITICAL: Check for VM/problematic GPU BEFORE any WebKit initialization === - // This must happen before any WPEDisplay is created, because WebKit's WebProcess - // inherits environment variables at spawn time. Setting LIBGL_ALWAYS_SOFTWARE - // after WebProcess starts has no effect. - flutter_inappwebview_plugin::ApplySoftwareRenderingIfNeeded(); - - FlutterInappwebviewLinuxPlugin* plugin = FLUTTER_INAPPWEBVIEW_LINUX_PLUGIN( - g_object_new(flutter_inappwebview_linux_plugin_get_type(), nullptr)); - - plugin->registrar = registrar; - - plugin->plugin_instance = std::make_unique(registrar); - auto* pluginInstance = plugin->plugin_instance.get(); - - plugin->in_app_webview_manager = - std::make_unique(pluginInstance); - pluginInstance->inAppWebViewManager = plugin->in_app_webview_manager.get(); - - plugin->headless_in_app_webview_manager = - std::make_unique(pluginInstance); - pluginInstance->headlessInAppWebViewManager = plugin->headless_in_app_webview_manager.get(); - - plugin->in_app_browser_manager = - std::make_unique(pluginInstance); - pluginInstance->inAppBrowserManager = plugin->in_app_browser_manager.get(); - - plugin->cookie_manager = std::make_unique(pluginInstance); - pluginInstance->cookieManager = plugin->cookie_manager.get(); - - plugin->credential_database = - std::make_unique(pluginInstance); - pluginInstance->credentialDatabase = plugin->credential_database.get(); - - plugin->proxy_manager = std::make_unique(pluginInstance); - pluginInstance->proxyManager = plugin->proxy_manager.get(); - - plugin->web_storage_manager = std::make_unique(pluginInstance); - pluginInstance->webStorageManager = plugin->web_storage_manager.get(); - - plugin->webview_environment = std::make_unique(pluginInstance); - pluginInstance->webViewEnvironment = plugin->webview_environment.get(); - - // Note: We don't unref the plugin here as it needs to stay alive - // for the lifetime of the application - g_object_ref(plugin); -} - -// === Helper functions for accessing Flutter view and window === - -FlView* flutter_inappwebview_linux_plugin_get_view(FlPluginRegistrar* registrar) { - if (registrar == nullptr) { - return nullptr; - } - return fl_plugin_registrar_get_view(registrar); -} - -GtkWindow* flutter_inappwebview_linux_plugin_get_window(FlPluginRegistrar* registrar) { - FlView* view = flutter_inappwebview_linux_plugin_get_view(registrar); - if (view == nullptr) { - return nullptr; - } - - GtkWidget* widget = GTK_WIDGET(view); - if (widget == nullptr) { - return nullptr; - } - - GtkWidget* toplevel = gtk_widget_get_toplevel(widget); - if (toplevel == nullptr || !GTK_IS_WINDOW(toplevel)) { - return nullptr; - } - - return GTK_WINDOW(toplevel); -} - -int flutter_inappwebview_linux_plugin_get_monitor_refresh_rate(FlPluginRegistrar* registrar) { - GtkWindow* window = flutter_inappwebview_linux_plugin_get_window(registrar); - return flutter_inappwebview_linux_plugin_get_monitor_refresh_rate_for_window(window); -} - -int flutter_inappwebview_linux_plugin_get_monitor_refresh_rate_for_window(GtkWindow* window) { - if (window == nullptr) { - return 0; - } - - GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window)); - if (gdk_window == nullptr) { - return 0; - } - - GdkDisplay* display = gdk_display_get_default(); - if (display == nullptr) { - return 0; - } - - GdkMonitor* monitor = gdk_display_get_monitor_at_window(display, gdk_window); - if (monitor == nullptr) { - return 0; - } - - // gdk_monitor_get_refresh_rate returns the refresh rate in millihertz - // (e.g., 60000 for 60 Hz) - return gdk_monitor_get_refresh_rate(monitor); -} - diff --git a/flutter_inappwebview_linux/linux/flutter_inappwebview_linux_plugin_private.h b/flutter_inappwebview_linux/linux/flutter_inappwebview_linux_plugin_private.h deleted file mode 100644 index e7b792b5e5..0000000000 --- a/flutter_inappwebview_linux/linux/flutter_inappwebview_linux_plugin_private.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_LINUX_PLUGIN_PRIVATE_H_ -#define FLUTTER_INAPPWEBVIEW_LINUX_PLUGIN_PRIVATE_H_ - -#include -#include - -#include - -G_BEGIN_DECLS - -// Get the FlView from the plugin registrar -// Returns nullptr if not available -FlView* flutter_inappwebview_linux_plugin_get_view(FlPluginRegistrar* registrar); - -// Get the GtkWindow from the plugin registrar (via FlView) -// Returns nullptr if not available -GtkWindow* flutter_inappwebview_linux_plugin_get_window(FlPluginRegistrar* registrar); - -// Get the monitor refresh rate in millihertz for the window -// Returns 0 if not available or unknown -int flutter_inappwebview_linux_plugin_get_monitor_refresh_rate(FlPluginRegistrar* registrar); - -// Get the monitor refresh rate in millihertz for the given GtkWindow -// Returns 0 if not available or unknown -int flutter_inappwebview_linux_plugin_get_monitor_refresh_rate_for_window(GtkWindow* window); - -G_END_DECLS - -#endif // FLUTTER_INAPPWEBVIEW_LINUX_PLUGIN_PRIVATE_H_ diff --git a/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_in_app_webview.cc b/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_in_app_webview.cc deleted file mode 100644 index a5fcc4ff45..0000000000 --- a/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_in_app_webview.cc +++ /dev/null @@ -1,65 +0,0 @@ -#include "headless_in_app_webview.h" - -#include - -#include "../utils/flutter.h" -#include "../utils/log.h" -#include "headless_in_app_webview_manager.h" -#include "headless_webview_channel_delegate.h" - -namespace flutter_inappwebview_plugin { - -HeadlessInAppWebView::HeadlessInAppWebView(HeadlessInAppWebViewManager* manager, - const HeadlessInAppWebViewCreationParams& params, - const InAppWebViewCreationParams& webviewParams) - : manager_(manager), id_(params.id), width_(params.initialWidth), height_(params.initialHeight) { - debugLog("HeadlessInAppWebView::HeadlessInAppWebView id=" + id_); - - // Create the underlying InAppWebView - // Use 0 as the numeric ID since we use string ID for headless webviews - webview_ = std::make_shared(manager_->registrar(), manager_->messenger(), 0, - webviewParams); - - // CRITICAL: Attach the method channel to the InAppWebView using the string ID. - // This creates the channel at "com.pichillilorenzo/flutter_inappwebview_" - // which the Dart LinuxInAppWebViewController expects. - webview_->AttachChannel(manager_->messenger(), id_, false); - - // Set the initial size - webview_->setSize(static_cast(width_), static_cast(height_)); - - // Create the channel delegate for this headless webview - // This handles headless-specific methods like setSize, getSize, dispose - channelDelegate_ = std::make_unique( - this, manager_->messenger(), id_); -} - -HeadlessInAppWebView::~HeadlessInAppWebView() { - debugLog("HeadlessInAppWebView::~HeadlessInAppWebView id=" + id_); - - channelDelegate_.reset(); - webview_.reset(); -} - -void HeadlessInAppWebView::setSize(double width, double height) { - width_ = width; - height_ = height; - if (webview_) { - webview_->setSize(static_cast(width_), static_cast(height_)); - } -} - -void HeadlessInAppWebView::getSize(double* width, double* height) const { - if (width) *width = width_; - if (height) *height = height_; -} - -void HeadlessInAppWebView::dispose() { - // Remove this headless webview from the manager - // This will trigger the destructor - if (manager_) { - manager_->RemoveHeadlessWebView(id_); - } -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_in_app_webview.h b/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_in_app_webview.h deleted file mode 100644 index d63010c900..0000000000 --- a/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_in_app_webview.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_HEADLESS_IN_APP_WEBVIEW_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_HEADLESS_IN_APP_WEBVIEW_H_ - -#include - -#include -#include - -#include "../in_app_webview/in_app_webview.h" -#include "headless_webview_channel_delegate.h" - -namespace flutter_inappwebview_plugin { - -class HeadlessInAppWebViewManager; - -struct HeadlessInAppWebViewCreationParams { - std::string id; - double initialWidth = -1; - double initialHeight = -1; -}; - -/// HeadlessInAppWebView - A WebView without visual output -/// -/// This class wraps InAppWebView for headless operation. -/// Since WPE WebKit is inherently headless (it renders to offscreen buffers), -/// this is essentially InAppWebView without texture registration. -class HeadlessInAppWebView { - public: - - HeadlessInAppWebView(HeadlessInAppWebViewManager* manager, - const HeadlessInAppWebViewCreationParams& params, - const InAppWebViewCreationParams& webviewParams); - ~HeadlessInAppWebView(); - - const std::string& id() const { return id_; } - InAppWebView* webview() const { return webview_.get(); } - HeadlessInAppWebViewManager* manager() const { return manager_; } - - // Size management - void setSize(double width, double height); - void getSize(double* width, double* height) const; - - // Get the channel delegate - HeadlessWebViewChannelDelegate* channelDelegate() const { return channelDelegate_.get(); } - - // Dispose this headless webview (called by channel delegate) - void dispose(); - - private: - HeadlessInAppWebViewManager* manager_ = nullptr; - std::string id_; - double width_ = -1; - double height_ = -1; - - // The underlying InAppWebView - std::shared_ptr webview_; - - // Channel delegate for this headless webview - std::unique_ptr channelDelegate_; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_HEADLESS_IN_APP_WEBVIEW_H_ diff --git a/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_in_app_webview_manager.cc b/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_in_app_webview_manager.cc deleted file mode 100644 index b72967ca13..0000000000 --- a/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_in_app_webview_manager.cc +++ /dev/null @@ -1,190 +0,0 @@ -#include "headless_in_app_webview_manager.h" - -#include - -#include "../flutter_inappwebview_linux_plugin_private.h" -#include "../plugin_instance.h" -#include "../in_app_webview/in_app_webview_settings.h" -#include "../types/url_request.h" -#include "../utils/flutter.h" -#include "../utils/log.h" -#include "../webview_environment.h" - -namespace flutter_inappwebview_plugin { - -HeadlessInAppWebViewManager::HeadlessInAppWebViewManager(PluginInstance* plugin) - : plugin_(plugin), registrar_(plugin->registrar()) { - messenger_ = plugin->messenger(); - - // Cache the GTK window from the plugin instance - // This may return nullptr for headless scenarios, which is fine - gtk_window_ = plugin->gtkWindow(); - - // Create the method channel - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - method_channel_ = fl_method_channel_new(messenger_, METHOD_CHANNEL_NAME, FL_METHOD_CODEC(codec)); - - fl_method_channel_set_method_call_handler(method_channel_, HandleMethodCall, this, nullptr); -} - -FlPluginRegistrar* HeadlessInAppWebViewManager::registrar() const { - return registrar_; -} - -HeadlessInAppWebViewManager::~HeadlessInAppWebViewManager() { - debugLog("dealloc HeadlessInAppWebViewManager"); - - // Clean up all headless webviews - webviews_.clear(); - - if (method_channel_ != nullptr) { - fl_method_channel_set_method_call_handler(method_channel_, nullptr, nullptr, nullptr); - g_object_unref(method_channel_); - method_channel_ = nullptr; - } -} - -HeadlessInAppWebView* HeadlessInAppWebViewManager::GetHeadlessWebView( - const std::string& id) const { - auto it = webviews_.find(id); - if (it != webviews_.end()) { - return it->second.get(); - } - return nullptr; -} - -void HeadlessInAppWebViewManager::RemoveHeadlessWebView(const std::string& id) { - auto it = webviews_.find(id); - if (it != webviews_.end()) { - webviews_.erase(it); - } -} - -void HeadlessInAppWebViewManager::HandleMethodCall(FlMethodChannel* channel, - FlMethodCall* method_call, - gpointer user_data) { - auto* self = static_cast(user_data); - self->HandleMethodCallImpl(method_call); -} - -void HeadlessInAppWebViewManager::HandleMethodCallImpl(FlMethodCall* method_call) { - const gchar* method = fl_method_call_get_name(method_call); - - if (strcmp(method, "run") == 0) { - Run(method_call); - return; - } - - fl_method_call_respond_not_implemented(method_call, nullptr); -} - -void HeadlessInAppWebViewManager::Run(FlMethodCall* method_call) { - FlValue* args = fl_method_call_get_args(method_call); - - if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { - fl_method_call_respond_error(method_call, "INVALID_ARGUMENTS", "Arguments must be a map", - nullptr, nullptr); - return; - } - - // Get the ID from Flutter - auto idOpt = get_optional_fl_map_value(args, "id"); - if (!idOpt.has_value()) { - fl_method_call_respond_error(method_call, "INVALID_ARGUMENTS", "Missing id parameter", nullptr, - nullptr); - return; - } - std::string id = idOpt.value(); - - // Get the params map - FlValue* params = get_fl_map_value_raw(args, "params"); - if (params == nullptr || fl_value_get_type(params) != FL_VALUE_TYPE_MAP) { - fl_method_call_respond_error(method_call, "INVALID_ARGUMENTS", "Missing params parameter", - nullptr, nullptr); - return; - } - - // Parse initial size - double initialWidth = -1; - double initialHeight = -1; - FlValue* initial_size = get_fl_map_value_raw(params, "initialSize"); - if (initial_size != nullptr && fl_value_get_type(initial_size) == FL_VALUE_TYPE_MAP) { - initialWidth = get_fl_map_value(initial_size, "width", -1); - initialHeight = get_fl_map_value(initial_size, "height", -1); - } - - // Create headless params - HeadlessInAppWebViewCreationParams headlessParams; - headlessParams.id = id; - headlessParams.initialWidth = initialWidth >= 0 ? initialWidth : 800; - headlessParams.initialHeight = initialHeight >= 0 ? initialHeight : 600; - - // Create InAppWebView params - InAppWebViewCreationParams webviewParams; - webviewParams.id = 0; // Not used for headless - webviewParams.plugin = plugin_; // Pass plugin instance for accessing managers - webviewParams.gtkWindow = gtk_window_; // Use cached GTK window (may be nullptr for headless) - webviewParams.manager = nullptr; // Not needed for headless - - // Parse initial settings - FlValue* initial_settings = get_fl_map_value_raw(params, "initialSettings"); - if (initial_settings != nullptr && fl_value_get_type(initial_settings) == FL_VALUE_TYPE_MAP) { - webviewParams.initialSettings = std::make_shared(initial_settings); - } else { - webviewParams.initialSettings = std::make_shared(); - } - - // Parse initial URL request - FlValue* initial_url_request = get_fl_map_value_raw(params, "initialUrlRequest"); - if (initial_url_request != nullptr && - fl_value_get_type(initial_url_request) == FL_VALUE_TYPE_MAP) { - webviewParams.initialUrlRequest = std::make_shared(initial_url_request); - } - - // Parse initial data - FlValue* initial_data = get_fl_map_value_raw(params, "initialData"); - if (initial_data != nullptr && fl_value_get_type(initial_data) == FL_VALUE_TYPE_MAP) { - webviewParams.initialData = get_fl_map_value(initial_data, "data", ""); - webviewParams.initialDataBaseUrl = get_fl_map_value(initial_data, "baseUrl", ""); - webviewParams.initialDataMimeType = get_fl_map_value(initial_data, "mimeType", ""); - webviewParams.initialDataEncoding = get_fl_map_value(initial_data, "encoding", ""); - } - - // Parse initial file - auto initial_file = get_optional_fl_map_value(params, "initialFile"); - if (initial_file.has_value()) { - webviewParams.initialFile = initial_file.value(); - } - - // Parse webViewEnvironmentId and look up the custom WebKitWebContext - auto webViewEnvironmentIdOpt = get_optional_fl_map_value(params, "webViewEnvironmentId"); - if (webViewEnvironmentIdOpt.has_value() && !webViewEnvironmentIdOpt->empty()) { - WebViewEnvironment* webViewEnv = plugin_ ? plugin_->webViewEnvironment : nullptr; - WebKitWebContext* webContext = nullptr; - if (webViewEnv != nullptr) { - webContext = webViewEnv->getWebContext(webViewEnvironmentIdOpt.value()); - } - if (webContext != nullptr) { - webviewParams.webContext = webContext; - debugLog("HeadlessInAppWebViewManager: Using custom WebKitWebContext from WebViewEnvironment id=" + webViewEnvironmentIdOpt.value()); - } else { - debugLog("HeadlessInAppWebViewManager: WebViewEnvironment not found for id=" + webViewEnvironmentIdOpt.value()); - } - } - - // Create the headless webview - auto headlessWebView = - std::make_unique(this, headlessParams, webviewParams); - - // Store it - webviews_[id] = std::move(headlessWebView); - - // Notify Flutter that the webview is created - webviews_[id]->channelDelegate()->onWebViewCreated(); - - // Return success - g_autoptr(FlValue) result = make_fl_value(true); - fl_method_call_respond_success(method_call, result, nullptr); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_in_app_webview_manager.h b/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_in_app_webview_manager.h deleted file mode 100644 index 697cb4b58a..0000000000 --- a/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_in_app_webview_manager.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_HEADLESS_IN_APP_WEBVIEW_MANAGER_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_HEADLESS_IN_APP_WEBVIEW_MANAGER_H_ - -#include - -#include -#include -#include - -#include "headless_in_app_webview.h" - -namespace flutter_inappwebview_plugin { - -class PluginInstance; - -class HeadlessInAppWebViewManager { - public: - static constexpr const char* METHOD_CHANNEL_NAME = - "com.pichillilorenzo/flutter_headless_inappwebview"; - - HeadlessInAppWebViewManager(PluginInstance* plugin); - ~HeadlessInAppWebViewManager(); - - PluginInstance* plugin() const { return plugin_; } - FlPluginRegistrar* registrar() const; - FlBinaryMessenger* messenger() const { return messenger_; } - - // Get a headless webview by ID - HeadlessInAppWebView* GetHeadlessWebView(const std::string& id) const; - - // Remove a headless webview by ID (called during dispose) - void RemoveHeadlessWebView(const std::string& id); - - private: - PluginInstance* plugin_ = nullptr; - FlPluginRegistrar* registrar_ = nullptr; - FlBinaryMessenger* messenger_ = nullptr; - FlMethodChannel* method_channel_ = nullptr; - GtkWindow* gtk_window_ = nullptr; // Cached GTK window (can be null for headless) - - // Map of id to HeadlessInAppWebView instance - std::map> webviews_; - - // Handle method calls from Flutter - static void HandleMethodCall(FlMethodChannel* channel, FlMethodCall* method_call, - gpointer user_data); - void HandleMethodCallImpl(FlMethodCall* method_call); - void Run(FlMethodCall* method_call); -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_HEADLESS_IN_APP_WEBVIEW_MANAGER_H_ diff --git a/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_webview_channel_delegate.cc b/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_webview_channel_delegate.cc deleted file mode 100644 index ff2ae96a14..0000000000 --- a/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_webview_channel_delegate.cc +++ /dev/null @@ -1,85 +0,0 @@ -#include "headless_webview_channel_delegate.h" - -#include - -#include "../utils/flutter.h" -#include "../utils/log.h" -#include "headless_in_app_webview.h" - -namespace flutter_inappwebview_plugin { - -HeadlessWebViewChannelDelegate::HeadlessWebViewChannelDelegate( - HeadlessInAppWebView* headlessWebView, - FlBinaryMessenger* messenger, - const std::string& id) - : ChannelDelegate(messenger, std::string(METHOD_CHANNEL_NAME_PREFIX) + id), - headlessWebView_(headlessWebView) { -} - -HeadlessWebViewChannelDelegate::~HeadlessWebViewChannelDelegate() { - debugLog("dealloc HeadlessWebViewChannelDelegate"); - headlessWebView_ = nullptr; -} - -void HeadlessWebViewChannelDelegate::HandleMethodCall(FlMethodCall* method_call) { - const gchar* method = fl_method_call_get_name(method_call); - - if (strcmp(method, "dispose") == 0) { - if (headlessWebView_ != nullptr) { - headlessWebView_->dispose(); - g_autoptr(FlValue) result = fl_value_new_bool(true); - fl_method_call_respond_success(method_call, result, nullptr); - } else { - g_autoptr(FlValue) result = fl_value_new_bool(false); - fl_method_call_respond_success(method_call, result, nullptr); - } - return; - } - - if (strcmp(method, "setSize") == 0) { - if (headlessWebView_ != nullptr) { - FlValue* args = fl_method_call_get_args(method_call); - if (args != nullptr && fl_value_get_type(args) == FL_VALUE_TYPE_MAP) { - FlValue* size_value = fl_value_lookup_string(args, "size"); - if (size_value != nullptr && fl_value_get_type(size_value) == FL_VALUE_TYPE_MAP) { - double width = get_fl_map_value(size_value, "width", -1); - double height = get_fl_map_value(size_value, "height", -1); - if (width >= 0 && height >= 0) { - headlessWebView_->setSize(width, height); - } - } - } - g_autoptr(FlValue) result = fl_value_new_bool(true); - fl_method_call_respond_success(method_call, result, nullptr); - } else { - g_autoptr(FlValue) result = fl_value_new_bool(false); - fl_method_call_respond_success(method_call, result, nullptr); - } - return; - } - - if (strcmp(method, "getSize") == 0) { - if (headlessWebView_ != nullptr) { - double width, height; - headlessWebView_->getSize(&width, &height); - g_autoptr(FlValue) result = - to_fl_map({{"width", make_fl_value(width)}, {"height", make_fl_value(height)}}); - fl_method_call_respond_success(method_call, result, nullptr); - } else { - fl_method_call_respond_success(method_call, fl_value_new_null(), nullptr); - } - return; - } - - fl_method_call_respond_not_implemented(method_call, nullptr); -} - -void HeadlessWebViewChannelDelegate::onWebViewCreated() const { - if (channel_ == nullptr) { - return; - } - g_autoptr(FlValue) args = to_fl_map({}); - invokeMethod("onWebViewCreated", args); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_webview_channel_delegate.h b/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_webview_channel_delegate.h deleted file mode 100644 index 7298f40323..0000000000 --- a/flutter_inappwebview_linux/linux/headless_in_app_webview/headless_webview_channel_delegate.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_HEADLESS_WEBVIEW_CHANNEL_DELEGATE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_HEADLESS_WEBVIEW_CHANNEL_DELEGATE_H_ - -#include - -#include -#include - -#include "../types/channel_delegate.h" - -namespace flutter_inappwebview_plugin { - -class HeadlessInAppWebView; - -/** - * Channel delegate for HeadlessInAppWebView. - * Handles method calls specific to headless webview operations (dispose, setSize, getSize). - * This mirrors the iOS HeadlessWebViewChannelDelegate pattern. - */ -class HeadlessWebViewChannelDelegate : public ChannelDelegate { - public: - static constexpr const char* METHOD_CHANNEL_NAME_PREFIX = - "com.pichillilorenzo/flutter_headless_inappwebview_"; - - HeadlessWebViewChannelDelegate(HeadlessInAppWebView* headlessWebView, - FlBinaryMessenger* messenger, - const std::string& id); - ~HeadlessWebViewChannelDelegate() override; - - void HandleMethodCall(FlMethodCall* method_call) override; - - // === Events to send to Dart === - - /** - * Notify Dart that the headless webview has been created. - */ - void onWebViewCreated() const; - - private: - HeadlessInAppWebView* headlessWebView_ = nullptr; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_HEADLESS_WEBVIEW_CHANNEL_DELEGATE_H_ diff --git a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser.cc b/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser.cc deleted file mode 100644 index 70c71eda99..0000000000 --- a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser.cc +++ /dev/null @@ -1,1417 +0,0 @@ -#include "in_app_browser.h" - -#include -#include -#include - -#include "../plugin_instance.h" -#include "../utils/flutter.h" -#include "../utils/log.h" -#include "../webview_environment.h" -#include "in_app_browser_manager.h" - -namespace flutter_inappwebview_plugin { - -// Convert color from #AARRGGBB (Flutter format) to rgba(r,g,b,a) (GTK CSS format) -// Flutter uses #AARRGGBB, but GTK CSS expects #RRGGBB, #RRGGBBAA, or rgba() -static std::string ConvertColorToGtkCss(const std::string& color) { - if (color.empty()) { - return color; - } - - // Handle #AARRGGBB format (9 chars including #) - if (color.length() == 9 && color[0] == '#') { - // Extract components: #AARRGGBB - std::string aa = color.substr(1, 2); - std::string rr = color.substr(3, 2); - std::string gg = color.substr(5, 2); - std::string bb = color.substr(7, 2); - - // Parse hex values - int a = std::stoi(aa, nullptr, 16); - int r = std::stoi(rr, nullptr, 16); - int g = std::stoi(gg, nullptr, 16); - int b = std::stoi(bb, nullptr, 16); - - // Return rgba() format - char buffer[64]; - snprintf(buffer, sizeof(buffer), "rgba(%d, %d, %d, %.3f)", r, g, b, a / 255.0); - return std::string(buffer); - } - - // Return as-is for other formats (#RGB, #RRGGBB, rgb(), rgba(), etc.) - return color; -} - -// InAppBrowserMenuItem implementation - -InAppBrowserMenuItem::InAppBrowserMenuItem(FlValue* map) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - id = get_fl_map_value(map, "id", 0); - title = get_fl_map_value(map, "title", ""); - order = get_fl_map_value(map, "order", 0); -} - -// InAppBrowser implementation - -InAppBrowser::InAppBrowser(InAppBrowserManager* manager, FlBinaryMessenger* messenger, - GtkWindow* parentWindow, const InAppBrowserCreationParams& params) - : plugin_(params.plugin), - manager_(manager), - messenger_(messenger), - parentWindow_(parentWindow), - id_(params.id), - settings_(params.initialSettings), - menuItems_(params.menuItems) { - // Validate messenger - if (messenger_ == nullptr || !FL_IS_BINARY_MESSENGER(messenger_)) { - errorLog("InAppBrowser: Invalid messenger"); - return; - } - - // Create channel delegate - std::string channelName = std::string(METHOD_CHANNEL_NAME_PREFIX) + id_; - channelDelegate_ = std::make_unique(this, messenger_, channelName); - - // Setup the window and components - setupWindow(params); - setupToolbar(); - setupDrawingArea(); - setupWebView(params); - applySettings(); - - // Show window unless hidden - if (!settings_->hidden) { - gtk_widget_show_all(GTK_WIDGET(window_)); - // Apply toolbar visibility after show_all - if (settings_->hideToolbarTop) { - gtk_widget_hide(headerBar_); - } - } - - // Load initial content (async, WebView needs time to initialize) - g_idle_add( - [](gpointer user_data) -> gboolean { - auto* browser = static_cast(user_data); - if (browser && !browser->destroyed_) { - // Notify Dart that browser is created - if (browser->channelDelegate_) { - browser->channelDelegate_->onBrowserCreated(); - } - } - return G_SOURCE_REMOVE; - }, - this); -} - -InAppBrowser::~InAppBrowser() { - debugLog("dealloc InAppBrowser"); - cleanup(); -} - -void InAppBrowser::cleanup() { - if (destroyed_) { - return; - } - destroyed_ = true; - - // Cancel frame callback - if (frameSourceId_ != 0) { - g_source_remove(frameSourceId_); - frameSourceId_ = 0; - } - - // Clean up cursor - if (currentCursor_ != nullptr) { - g_object_unref(currentCursor_); - currentCursor_ = nullptr; - } - - // Clean up WebView - webView_.reset(); - - // Clean up channel delegate - if (channelDelegate_) { - channelDelegate_->unregisterMethodCallHandler(); - channelDelegate_.reset(); - } - - // Nullify window reference (GTK handles cleanup via destroy signal) - window_ = nullptr; - headerBar_ = nullptr; - backButton_ = nullptr; - forwardButton_ = nullptr; - reloadButton_ = nullptr; - urlEntry_ = nullptr; - progressBar_ = nullptr; - menuButton_ = nullptr; - contentBox_ = nullptr; - drawingArea_ = nullptr; - - // Clean up GL resources - if (glArea_ != nullptr && gtk_widget_get_realized(glArea_)) { - gtk_gl_area_make_current(GTK_GL_AREA(glArea_)); - if (glTexture_ != 0) { - glDeleteTextures(1, &glTexture_); - glTexture_ = 0; - } - if (glVBO_ != 0) { - glDeleteBuffers(1, &glVBO_); - glVBO_ = 0; - } - if (glProgram_ != 0) { - glDeleteProgram(glProgram_); - glProgram_ = 0; - } - } - glArea_ = nullptr; - glInitialized_ = false; - glAttribPosition_ = -1; - glAttribTexture_ = -1; - glUniformTexture_ = -1; - - manager_ = nullptr; - messenger_ = nullptr; - parentWindow_ = nullptr; - plugin_ = nullptr; -} - -void InAppBrowser::setupWindow(const InAppBrowserCreationParams& params) { - // Create top-level window - window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); - - // Set window title - if (!settings_->toolbarTopFixedTitle.empty()) { - gtk_window_set_title(window_, settings_->toolbarTopFixedTitle.c_str()); - } else { - gtk_window_set_title(window_, "InAppBrowser"); - } - - // Set window size - int width = 1280; - int height = 720; - if (settings_->windowFrame) { - width = static_cast(settings_->windowFrame->width); - height = static_cast(settings_->windowFrame->height); - } - gtk_window_set_default_size(window_, width, height); - - // Set window position - if (settings_->windowFrame) { - gtk_window_move(window_, static_cast(settings_->windowFrame->x), - static_cast(settings_->windowFrame->y)); - } - - // Set window type hints - if (settings_->windowType == InAppBrowserWindowType::child) { - if (parentWindow_ != nullptr) { - gtk_window_set_transient_for(window_, parentWindow_); - gtk_window_set_destroy_with_parent(window_, TRUE); - } - } - - // Set opacity - gtk_widget_set_opacity(GTK_WIDGET(window_), settings_->windowAlphaValue); - - // Create main vertical box - contentBox_ = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_container_add(GTK_CONTAINER(window_), contentBox_); - - // Connect signals - g_signal_connect(window_, "destroy", G_CALLBACK(OnWindowDestroy), this); - g_signal_connect(window_, "delete-event", G_CALLBACK(OnWindowDeleteEvent), this); -} - -void InAppBrowser::setupToolbar() { - // Create header bar - headerBar_ = gtk_header_bar_new(); - gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(headerBar_), TRUE); - - // Apply background color if specified - if (!settings_->toolbarTopBackgroundColor.empty()) { - GtkCssProvider* provider = gtk_css_provider_new(); - std::string gtkColor = ConvertColorToGtkCss(settings_->toolbarTopBackgroundColor); - std::string css = "headerbar { background-color: " + gtkColor + "; }"; - gtk_css_provider_load_from_data(provider, css.c_str(), -1, nullptr); - GtkStyleContext* context = gtk_widget_get_style_context(headerBar_); - gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - g_object_unref(provider); - } - - // Create navigation buttons (unless hidden) - if (!settings_->hideDefaultMenuItems) { - // Navigation button box - GtkWidget* navBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_style_context_add_class(gtk_widget_get_style_context(navBox), "linked"); - - // Back button - backButton_ = gtk_button_new_from_icon_name("go-previous-symbolic", GTK_ICON_SIZE_BUTTON); - gtk_widget_set_tooltip_text(backButton_, "Go Back"); - gtk_widget_set_sensitive(backButton_, FALSE); - g_signal_connect(backButton_, "clicked", G_CALLBACK(OnBackClicked), this); - gtk_box_pack_start(GTK_BOX(navBox), backButton_, FALSE, FALSE, 0); - - // Forward button - forwardButton_ = gtk_button_new_from_icon_name("go-next-symbolic", GTK_ICON_SIZE_BUTTON); - gtk_widget_set_tooltip_text(forwardButton_, "Go Forward"); - gtk_widget_set_sensitive(forwardButton_, FALSE); - g_signal_connect(forwardButton_, "clicked", G_CALLBACK(OnForwardClicked), this); - gtk_box_pack_start(GTK_BOX(navBox), forwardButton_, FALSE, FALSE, 0); - - // Reload button - reloadButton_ = gtk_button_new_from_icon_name("view-refresh-symbolic", GTK_ICON_SIZE_BUTTON); - gtk_widget_set_tooltip_text(reloadButton_, "Reload"); - g_signal_connect(reloadButton_, "clicked", G_CALLBACK(OnReloadClicked), this); - gtk_box_pack_start(GTK_BOX(navBox), reloadButton_, FALSE, FALSE, 0); - - gtk_header_bar_pack_start(GTK_HEADER_BAR(headerBar_), navBox); - } - - // Create URL entry (unless hidden) - if (!settings_->hideUrlBar) { - urlEntry_ = gtk_entry_new(); - gtk_entry_set_placeholder_text(GTK_ENTRY(urlEntry_), "Enter URL..."); - gtk_widget_set_hexpand(urlEntry_, TRUE); - gtk_entry_set_icon_from_icon_name(GTK_ENTRY(urlEntry_), GTK_ENTRY_ICON_PRIMARY, "globe-symbolic"); - g_signal_connect(urlEntry_, "activate", G_CALLBACK(OnUrlEntryActivated), this); - gtk_header_bar_set_custom_title(GTK_HEADER_BAR(headerBar_), urlEntry_); - } - - // Create menu button if there are menu items - if (!menuItems_.empty()) { - menuButton_ = gtk_menu_button_new(); - gtk_button_set_image(GTK_BUTTON(menuButton_), - gtk_image_new_from_icon_name("open-menu-symbolic", GTK_ICON_SIZE_BUTTON)); - gtk_widget_set_tooltip_text(menuButton_, "Menu"); - - // Create menu - GtkWidget* menu = gtk_menu_new(); - for (const auto& item : menuItems_) { - GtkWidget* menuItem = gtk_menu_item_new_with_label(item.title.c_str()); - g_object_set_data(G_OBJECT(menuItem), "menu-item-id", GINT_TO_POINTER(item.id)); - g_signal_connect(menuItem, "activate", G_CALLBACK(OnMenuItemActivated), this); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem); - } - gtk_widget_show_all(menu); - gtk_menu_button_set_popup(GTK_MENU_BUTTON(menuButton_), menu); - - gtk_header_bar_pack_end(GTK_HEADER_BAR(headerBar_), menuButton_); - } - - // Use the header bar as the title bar - gtk_window_set_titlebar(window_, headerBar_); - - // Create progress bar (in content area, below header) - if (!settings_->hideProgressBar) { - progressBar_ = gtk_progress_bar_new(); - gtk_widget_set_valign(progressBar_, GTK_ALIGN_START); - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressBar_), 0.0); - gtk_box_pack_start(GTK_BOX(contentBox_), progressBar_, FALSE, FALSE, 0); - - // Style the progress bar to be thin - GtkCssProvider* provider = gtk_css_provider_new(); - gtk_css_provider_load_from_data( - provider, - "progressbar { min-height: 3px; } " - "progressbar trough { min-height: 3px; } " - "progressbar progress { min-height: 3px; }", - -1, nullptr); - GtkStyleContext* context = gtk_widget_get_style_context(progressBar_); - gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - g_object_unref(provider); - } -} - -void InAppBrowser::setupDrawingArea() { - // Try to use GtkGLArea for hardware-accelerated zero-copy rendering - // This provides better performance by avoiding GPU->CPU->GPU copies - bool canUseGl = InAppWebView::IsWpeWebKitAvailable(); - - if (canUseGl) { - // Create GtkGLArea for zero-copy EGL texture rendering - glArea_ = gtk_gl_area_new(); - gtk_widget_set_can_focus(glArea_, TRUE); - gtk_widget_set_hexpand(glArea_, TRUE); - gtk_widget_set_vexpand(glArea_, TRUE); - - // Use OpenGL ES for compatibility with WPE's EGL images - gtk_gl_area_set_use_es(GTK_GL_AREA(glArea_), TRUE); - - // Enable events - gtk_widget_add_events(glArea_, - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | - GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK | - GDK_SMOOTH_SCROLL_MASK | GDK_KEY_PRESS_MASK | - GDK_KEY_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK | - GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); - - // Connect GL-specific signals - g_signal_connect(glArea_, "realize", G_CALLBACK(OnGlAreaRealize), this); - g_signal_connect(glArea_, "render", G_CALLBACK(OnGlAreaRender), this); - g_signal_connect(glArea_, "resize", G_CALLBACK(OnGlAreaResize), this); - - // Connect input signals (same as drawing area) - g_signal_connect(glArea_, "button-press-event", G_CALLBACK(OnDrawingAreaButtonPress), this); - g_signal_connect(glArea_, "button-release-event", G_CALLBACK(OnDrawingAreaButtonRelease), this); - g_signal_connect(glArea_, "motion-notify-event", G_CALLBACK(OnDrawingAreaMotionNotify), this); - g_signal_connect(glArea_, "scroll-event", G_CALLBACK(OnDrawingAreaScroll), this); - g_signal_connect(glArea_, "key-press-event", G_CALLBACK(OnDrawingAreaKeyPress), this); - g_signal_connect(glArea_, "key-release-event", G_CALLBACK(OnDrawingAreaKeyRelease), this); - g_signal_connect(glArea_, "focus-in-event", G_CALLBACK(OnDrawingAreaFocusIn), this); - g_signal_connect(glArea_, "focus-out-event", G_CALLBACK(OnDrawingAreaFocusOut), this); - g_signal_connect(glArea_, "enter-notify-event", G_CALLBACK(OnDrawingAreaEnterNotify), this); - g_signal_connect(glArea_, "leave-notify-event", G_CALLBACK(OnDrawingAreaLeaveNotify), this); - g_signal_connect(glArea_, "map", G_CALLBACK(OnDrawingAreaMap), this); - g_signal_connect(glArea_, "unmap", G_CALLBACK(OnDrawingAreaUnmap), this); - g_signal_connect(glArea_, "size-allocate", G_CALLBACK(OnGlAreaSizeAllocate), this); - - gtk_box_pack_start(GTK_BOX(contentBox_), glArea_, TRUE, TRUE, 0); - useGlRendering_ = true; - } else { - // Fall back to original GtkDrawingArea implementation - setupDrawingAreaFallback(); - } -} - -void InAppBrowser::setupDrawingAreaFallback() { - // Original GtkDrawingArea code - used when GL rendering is not available - drawingArea_ = gtk_drawing_area_new(); - gtk_widget_set_can_focus(drawingArea_, TRUE); - gtk_widget_set_hexpand(drawingArea_, TRUE); - gtk_widget_set_vexpand(drawingArea_, TRUE); - - // Enable events - gtk_widget_add_events(drawingArea_, - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | - GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK | GDK_KEY_PRESS_MASK | - GDK_KEY_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK | GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK); - - // Connect signals - g_signal_connect(drawingArea_, "draw", G_CALLBACK(OnDrawingAreaDraw), this); - g_signal_connect(drawingArea_, "realize", G_CALLBACK(OnDrawingAreaRealize), this); - g_signal_connect(drawingArea_, "button-press-event", G_CALLBACK(OnDrawingAreaButtonPress), this); - g_signal_connect(drawingArea_, "button-release-event", G_CALLBACK(OnDrawingAreaButtonRelease), - this); - g_signal_connect(drawingArea_, "motion-notify-event", G_CALLBACK(OnDrawingAreaMotionNotify), - this); - g_signal_connect(drawingArea_, "scroll-event", G_CALLBACK(OnDrawingAreaScroll), this); - g_signal_connect(drawingArea_, "key-press-event", G_CALLBACK(OnDrawingAreaKeyPress), this); - g_signal_connect(drawingArea_, "key-release-event", G_CALLBACK(OnDrawingAreaKeyRelease), this); - g_signal_connect(drawingArea_, "size-allocate", G_CALLBACK(OnDrawingAreaSizeAllocate), this); - g_signal_connect(drawingArea_, "focus-in-event", G_CALLBACK(OnDrawingAreaFocusIn), this); - g_signal_connect(drawingArea_, "focus-out-event", G_CALLBACK(OnDrawingAreaFocusOut), this); - g_signal_connect(drawingArea_, "map", G_CALLBACK(OnDrawingAreaMap), this); - g_signal_connect(drawingArea_, "unmap", G_CALLBACK(OnDrawingAreaUnmap), this); - g_signal_connect(drawingArea_, "enter-notify-event", G_CALLBACK(OnDrawingAreaEnterNotify), this); - g_signal_connect(drawingArea_, "leave-notify-event", G_CALLBACK(OnDrawingAreaLeaveNotify), this); - - gtk_box_pack_start(GTK_BOX(contentBox_), drawingArea_, TRUE, TRUE, 0); - useGlRendering_ = false; -} - -void InAppBrowser::setupWebView(const InAppBrowserCreationParams& params) { - if (messenger_ == nullptr || !FL_IS_BINARY_MESSENGER(messenger_)) { - errorLog("InAppBrowser::setupWebView - messenger is null or invalid"); - return; - } - - // Create InAppWebView creation params - InAppWebViewCreationParams webViewParams; - webViewParams.plugin = plugin_; - webViewParams.id = 0; // Will be set by channel attachment - webViewParams.gtkWindow = window_; - webViewParams.initialSettings = params.initialWebViewSettings; - webViewParams.contextMenu = params.contextMenu; - - if (params.initialUserScripts.has_value()) { - webViewParams.initialUserScripts = params.initialUserScripts.value(); - } - - // Check for WebViewEnvironment - if (params.webViewEnvironmentId.has_value() && !params.webViewEnvironmentId->empty()) { - WebViewEnvironment* webViewEnv = plugin_ ? plugin_->webViewEnvironment : nullptr; - WebKitWebContext* webContext = nullptr; - if (webViewEnv != nullptr) { - webContext = webViewEnv->getWebContext(params.webViewEnvironmentId.value()); - } - if (webContext != nullptr) { - webViewParams.webContext = webContext; - } - } - - // Create the InAppWebView - pass nullptr for registrar since we have messenger directly - webView_ = std::make_shared(nullptr, messenger_, 0, webViewParams); - - // Attach channel with browser-specific ID - webView_->AttachChannel(messenger_, METHOD_CHANNEL_NAME_PREFIX + id_, true); - - // Set initial size (will be updated on realize) - webView_->setSize(800, 600); - - // Set up frame callback - uses GL queue_render for GPU path, scheduleFrame for CPU path - webView_->SetOnFrameAvailable([this]() { - if (useGlRendering_ && glArea_ != nullptr) { - gtk_gl_area_queue_render(GTK_GL_AREA(glArea_)); - } else { - scheduleFrame(); - } - }); - - // Set up cursor change callback - webView_->SetOnCursorChanged([this](const std::string& cursorName) { - OnCursorChanged(cursorName); - }); - - // Set up progress change callback for progress bar - webView_->SetOnProgressChanged([this](double progress) { - didChangeProgress(progress); - }); - - // Set up navigation state change callback for back/forward buttons - webView_->SetOnNavigationStateChanged([this]() { - didChangeNavigationState(); - }); - - // Load initial content - loadInitialContent(params); -} - -void InAppBrowser::loadInitialContent(const InAppBrowserCreationParams& params) { - if (!webView_) { - return; - } - - if (params.urlRequest.has_value()) { - webView_->loadUrl(params.urlRequest.value()); - } else if (params.assetFilePath.has_value()) { - webView_->loadFile(params.assetFilePath.value()); - } else if (params.data.has_value()) { - webView_->loadData(params.data.value(), "text/html", "UTF-8", ""); - } -} - -void InAppBrowser::applySettings() { - if (!settings_) { - return; - } - - // Apply visibility - if (settings_->hideToolbarTop && headerBar_) { - gtk_widget_hide(headerBar_); - } - - // Apply window opacity - gtk_widget_set_opacity(GTK_WIDGET(window_), settings_->windowAlphaValue); -} - -void InAppBrowser::close() { - if (window_ != nullptr && !destroyed_) { - gtk_window_close(window_); - } -} - -void InAppBrowser::show() { - if (window_ != nullptr && !destroyed_) { - gtk_widget_show_all(GTK_WIDGET(window_)); - // Reapply visibility settings - if (settings_->hideToolbarTop && headerBar_) { - gtk_widget_hide(headerBar_); - } - if (settings_->hideProgressBar && progressBar_) { - gtk_widget_hide(progressBar_); - } - } -} - -void InAppBrowser::hide() { - if (window_ != nullptr && !destroyed_) { - gtk_widget_hide(GTK_WIDGET(window_)); - } -} - -bool InAppBrowser::isHidden() const { - if (window_ == nullptr || destroyed_) { - return true; - } - return !gtk_widget_is_visible(GTK_WIDGET(window_)); -} - -void InAppBrowser::setSettings(const std::shared_ptr& newSettings, - FlValue* newSettingsMap) { - if (!newSettings) { - return; - } - - // Update WebView settings - if (webView_ && newSettingsMap != nullptr) { - webView_->setSettings(std::make_shared(newSettingsMap), newSettingsMap); - } - - // Handle hidden change - if (fl_map_contains_not_null(newSettingsMap, "hidden") && - settings_->hidden != newSettings->hidden) { - if (newSettings->hidden) { - hide(); - } else { - show(); - } - } - - // Handle toolbar visibility change - if (fl_map_contains_not_null(newSettingsMap, "hideToolbarTop") && headerBar_ != nullptr) { - if (newSettings->hideToolbarTop) { - gtk_widget_hide(headerBar_); - } else { - gtk_widget_show(headerBar_); - } - } - - // Handle progress bar visibility - if (fl_map_contains_not_null(newSettingsMap, "hideProgressBar") && progressBar_ != nullptr) { - if (newSettings->hideProgressBar) { - gtk_widget_hide(progressBar_); - } else { - gtk_widget_show(progressBar_); - } - } - - // Handle title change - if (fl_map_contains_not_null(newSettingsMap, "toolbarTopFixedTitle") && - settings_->toolbarTopFixedTitle != newSettings->toolbarTopFixedTitle) { - if (!newSettings->toolbarTopFixedTitle.empty()) { - gtk_window_set_title(window_, newSettings->toolbarTopFixedTitle.c_str()); - } - } - - // Handle opacity change - if (fl_map_contains_not_null(newSettingsMap, "windowAlphaValue") && - settings_->windowAlphaValue != newSettings->windowAlphaValue) { - gtk_widget_set_opacity(GTK_WIDGET(window_), newSettings->windowAlphaValue); - } - - // Handle window frame change - if (fl_map_contains_not_null(newSettingsMap, "windowFrame") && newSettings->windowFrame) { - gtk_window_move(window_, static_cast(newSettings->windowFrame->x), - static_cast(newSettings->windowFrame->y)); - gtk_window_resize(window_, static_cast(newSettings->windowFrame->width), - static_cast(newSettings->windowFrame->height)); - } - - settings_ = newSettings; -} - -FlValue* InAppBrowser::getSettings() const { - if (!settings_) { - return fl_value_new_null(); - } - - FlValue* settingsMap = settings_->getRealSettings(this); - - // Merge with WebView settings - if (webView_) { - FlValue* webViewSettings = webView_->getSettings(); - if (webViewSettings != nullptr && fl_value_get_type(webViewSettings) == FL_VALUE_TYPE_MAP) { - size_t len = fl_value_get_length(webViewSettings); - for (size_t i = 0; i < len; i++) { - FlValue* key = fl_value_get_map_key(webViewSettings, i); - FlValue* value = fl_value_get_map_value(webViewSettings, i); - if (fl_value_get_type(key) == FL_VALUE_TYPE_STRING) { - fl_value_set_string_take(settingsMap, fl_value_get_string(key), fl_value_ref(value)); - } - } - } - } - - return settingsMap; -} - -void InAppBrowser::didChangeTitle(const std::optional& title) { - if (title.has_value() && settings_->toolbarTopFixedTitle.empty()) { - updateTitle(title.value()); - } -} - -void InAppBrowser::didChangeUrl(const std::optional& url) { - if (url.has_value()) { - updateUrlEntry(url.value()); - } - updateNavigationButtons(); -} - -void InAppBrowser::didChangeProgress(double progress) { - updateProgressBar(progress); -} - -void InAppBrowser::didChangeNavigationState() { - updateNavigationButtons(); -} - -void InAppBrowser::updateNavigationButtons() { - if (!webView_) { - return; - } - - if (backButton_ != nullptr) { - gtk_widget_set_sensitive(backButton_, webView_->canGoBack()); - } - if (forwardButton_ != nullptr) { - gtk_widget_set_sensitive(forwardButton_, webView_->canGoForward()); - } -} - -void InAppBrowser::updateProgressBar(double progress) { - if (progressBar_ == nullptr) { - return; - } - - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressBar_), progress); - - // Hide progress bar when complete - if (progress >= 1.0) { - gtk_widget_hide(progressBar_); - } else if (!settings_->hideProgressBar) { - gtk_widget_show(progressBar_); - } -} - -void InAppBrowser::updateUrlEntry(const std::string& url) { - if (urlEntry_ != nullptr) { - gtk_entry_set_text(GTK_ENTRY(urlEntry_), url.c_str()); - } -} - -void InAppBrowser::updateTitle(const std::string& title) { - if (window_ != nullptr && !destroyed_) { - gtk_window_set_title(window_, title.c_str()); - } -} - -void InAppBrowser::scheduleFrame() { - if (destroyed_ || frameSourceId_ != 0) { - return; - } - frameSourceId_ = g_idle_add(OnFrameCallback, this); -} - -gboolean InAppBrowser::OnFrameCallback(gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser && !browser->destroyed_) { - browser->frameSourceId_ = 0; - // This callback is only used for the CPU rendering path (GtkDrawingArea) - if (browser->drawingArea_ != nullptr) { - gtk_widget_queue_draw(browser->drawingArea_); - } - } else if (browser) { - browser->frameSourceId_ = 0; - } - return G_SOURCE_REMOVE; -} - -// Convert GDK modifier flags to WPE modifier flags -// GDK: Shift=1, Lock=2, Control=4, Mod1(Alt)=8, Mod4(Super)=64 -// WPE: Control=1, Shift=2, Alt=4, Meta=8 -static int ConvertGdkModifiersToWpe(guint gdkState) { - int wpeModifiers = 0; - if (gdkState & GDK_CONTROL_MASK) // GDK bit 2 -> WPE bit 0 - wpeModifiers |= 1; - if (gdkState & GDK_SHIFT_MASK) // GDK bit 0 -> WPE bit 1 - wpeModifiers |= 2; - if (gdkState & GDK_MOD1_MASK) // GDK bit 3 (Alt) -> WPE bit 2 - wpeModifiers |= 4; - if (gdkState & GDK_MOD4_MASK) // GDK bit 6 (Super/Meta) -> WPE bit 3 - wpeModifiers |= 8; - return wpeModifiers; -} - -// Convert RGBA to BGRA for Cairo ARGB32 format (which is BGRA on little-endian) -static void ConvertRGBAToBGRA(uint8_t* buffer, size_t size) { - // Process 4 bytes at a time (one pixel: RGBA -> BGRA) - for (size_t i = 0; i + 3 < size; i += 4) { - // Swap R and B channels - uint8_t r = buffer[i]; - buffer[i] = buffer[i + 2]; // B - buffer[i + 2] = r; // R - // G and A stay in place - } -} - -// GTK Signal handlers - -void InAppBrowser::OnWindowDestroy(GtkWidget* widget, gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser && !browser->destroyed_) { - // Notify Dart about exit - if (browser->channelDelegate_) { - browser->channelDelegate_->onExit(); - } - - // Remove from manager - if (browser->manager_) { - browser->manager_->removeBrowser(browser->id_); - } - } -} - -gboolean InAppBrowser::OnWindowDeleteEvent(GtkWidget* widget, GdkEvent* event, gpointer user_data) { - // Allow the window to be destroyed - return FALSE; -} - -void InAppBrowser::OnBackClicked(GtkButton* button, gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser && browser->webView_) { - browser->webView_->goBack(); - } -} - -void InAppBrowser::OnForwardClicked(GtkButton* button, gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser && browser->webView_) { - browser->webView_->goForward(); - } -} - -void InAppBrowser::OnReloadClicked(GtkButton* button, gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser && browser->webView_) { - browser->webView_->reload(); - } -} - -void InAppBrowser::OnUrlEntryActivated(GtkEntry* entry, gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser && browser->webView_) { - const gchar* text = gtk_entry_get_text(entry); - if (text != nullptr && strlen(text) > 0) { - std::string url(text); - // Add http:// if no scheme specified - if (url.find("://") == std::string::npos) { - url = "https://" + url; - } - browser->webView_->loadUrl(url); - } - } -} - -gboolean InAppBrowser::OnDrawingAreaDraw(GtkWidget* widget, cairo_t* cr, gpointer user_data) { - auto* browser = static_cast(user_data); - if (!browser || browser->destroyed_ || !browser->webView_) { - return FALSE; - } - - // Get the pixel buffer from WebView - uint32_t width = 0, height = 0; - size_t bufferSize = browser->webView_->GetPixelBufferSize(&width, &height); - - if (bufferSize == 0 || width == 0 || height == 0) { - // Fill with white background when no content - cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); - cairo_paint(cr); - return TRUE; - } - - // Allocate buffer and copy pixels - std::vector buffer(bufferSize); - if (!browser->webView_->CopyPixelBufferTo(buffer.data(), bufferSize, &width, &height)) { - return FALSE; - } - - // Convert RGBA to BGRA for Cairo - ConvertRGBAToBGRA(buffer.data(), bufferSize); - - // Create Cairo surface from pixel buffer (BGRA format) - cairo_surface_t* surface = cairo_image_surface_create_for_data( - buffer.data(), CAIRO_FORMAT_ARGB32, width, height, width * 4); - - if (cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS) { - // Scale to fit drawing area - GtkAllocation alloc; - gtk_widget_get_allocation(widget, &alloc); - - double scaleX = static_cast(alloc.width) / width; - double scaleY = static_cast(alloc.height) / height; - - cairo_scale(cr, scaleX, scaleY); - cairo_set_source_surface(cr, surface, 0, 0); - cairo_paint(cr); - } - - cairo_surface_destroy(surface); - return TRUE; -} - -void InAppBrowser::OnDrawingAreaRealize(GtkWidget* widget, gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser && browser->webView_) { - GtkAllocation alloc; - gtk_widget_get_allocation(widget, &alloc); - browser->webView_->setSize(alloc.width, alloc.height); - } -} - -gboolean InAppBrowser::OnDrawingAreaButtonPress(GtkWidget* widget, GdkEventButton* event, - gpointer user_data) { - auto* browser = static_cast(user_data); - if (!browser || !browser->webView_) { - return FALSE; - } - - gtk_widget_grab_focus(widget); - - int button = 0; - switch (event->button) { - case 1: - button = 1; - break; // Primary - case 2: - button = 3; - break; // Tertiary (middle) - case 3: - button = 2; - break; // Secondary (right) - default: - button = static_cast(event->button); - } - - browser->webView_->SetCursorPos(event->x, event->y); - browser->webView_->SetPointerButton(1, button, 1); // Down - return TRUE; -} - -gboolean InAppBrowser::OnDrawingAreaButtonRelease(GtkWidget* widget, GdkEventButton* event, - gpointer user_data) { - auto* browser = static_cast(user_data); - if (!browser || !browser->webView_) { - return FALSE; - } - - int button = 0; - switch (event->button) { - case 1: - button = 1; - break; - case 2: - button = 3; - break; - case 3: - button = 2; - break; - default: - button = static_cast(event->button); - } - - browser->webView_->SetCursorPos(event->x, event->y); - browser->webView_->SetPointerButton(4, button, 1); // Up - return TRUE; -} - -gboolean InAppBrowser::OnDrawingAreaMotionNotify(GtkWidget* widget, GdkEventMotion* event, - gpointer user_data) { - auto* browser = static_cast(user_data); - if (!browser || !browser->webView_) { - return FALSE; - } - - browser->webView_->SetCursorPos(event->x, event->y); - browser->webView_->SetPointerButton(5, 0, 0); // Update (motion) - return TRUE; -} - -gboolean InAppBrowser::OnDrawingAreaScroll(GtkWidget* widget, GdkEventScroll* event, - gpointer user_data) { - auto* browser = static_cast(user_data); - if (!browser || !browser->webView_) { - return FALSE; - } - - double dx = 0, dy = 0; - - if (event->direction == GDK_SCROLL_SMOOTH) { - dx = event->delta_x * -53.0; - dy = event->delta_y * -53.0; - } else { - switch (event->direction) { - case GDK_SCROLL_UP: - dy = 53.0; - break; - case GDK_SCROLL_DOWN: - dy = -53.0; - break; - case GDK_SCROLL_LEFT: - dx = 53.0; - break; - case GDK_SCROLL_RIGHT: - dx = -53.0; - break; - default: - break; - } - } - - browser->webView_->SetScrollDelta(dx, dy); - return TRUE; -} - -gboolean InAppBrowser::OnDrawingAreaKeyPress(GtkWidget* widget, GdkEventKey* event, - gpointer user_data) { - auto* browser = static_cast(user_data); - if (!browser || !browser->webView_) { - return FALSE; - } - - std::string characters; - if (event->string != nullptr && event->string[0] != '\0') { - characters = event->string; - } - - // Convert GDK modifiers to WPE format - int wpeModifiers = ConvertGdkModifiersToWpe(event->state); - - // type: 0=down, 1=up for WPE - browser->webView_->SendKeyEvent(0, event->keyval, event->hardware_keycode, wpeModifiers, - characters); - return TRUE; -} - -gboolean InAppBrowser::OnDrawingAreaKeyRelease(GtkWidget* widget, GdkEventKey* event, - gpointer user_data) { - auto* browser = static_cast(user_data); - if (!browser || !browser->webView_) { - return FALSE; - } - - // Convert GDK modifiers to WPE format - int wpeModifiers = ConvertGdkModifiersToWpe(event->state); - - // type: 0=down, 1=up for WPE - browser->webView_->SendKeyEvent(1, event->keyval, event->hardware_keycode, wpeModifiers, ""); - return TRUE; -} - -void InAppBrowser::OnMenuItemActivated(GtkMenuItem* item, gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser && browser->channelDelegate_) { - int32_t menuItemId = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "menu-item-id")); - browser->channelDelegate_->onMenuItemClicked(menuItemId); - } -} - -void InAppBrowser::OnDrawingAreaSizeAllocate(GtkWidget* widget, GdkRectangle* allocation, - gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser && browser->webView_ && allocation) { - browser->webView_->setSize(allocation->width, allocation->height); - } -} - -gboolean InAppBrowser::OnDrawingAreaFocusIn(GtkWidget* widget, GdkEventFocus* event, - gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser && browser->webView_) { - browser->webView_->setFocused(true); - } - return FALSE; -} - -gboolean InAppBrowser::OnDrawingAreaFocusOut(GtkWidget* widget, GdkEventFocus* event, - gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser && browser->webView_) { - browser->webView_->setFocused(false); - } - return FALSE; -} - -void InAppBrowser::OnDrawingAreaMap(GtkWidget* widget, gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser && browser->webView_) { - browser->webView_->setVisible(true); - } -} - -void InAppBrowser::OnDrawingAreaUnmap(GtkWidget* widget, gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser && browser->webView_) { - browser->webView_->setVisible(false); - } -} - -gboolean InAppBrowser::OnDrawingAreaEnterNotify(GtkWidget* widget, GdkEventCrossing* event, - gpointer user_data) { - // Mouse entered the drawing area - no special action needed - return FALSE; -} - -gboolean InAppBrowser::OnDrawingAreaLeaveNotify(GtkWidget* widget, GdkEventCrossing* event, - gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser) { - // Reset cursor to default when leaving the drawing area - GdkWindow* gdkWindow = gtk_widget_get_window(widget); - if (gdkWindow) { - gdk_window_set_cursor(gdkWindow, nullptr); - } - if (browser->currentCursor_ != nullptr) { - g_object_unref(browser->currentCursor_); - browser->currentCursor_ = nullptr; - } - } - return FALSE; -} - -// === GtkGLArea Signal Handlers for GPU-Accelerated Rendering === - -void InAppBrowser::OnGlAreaRealize(GtkGLArea* area, gpointer user_data) { - auto* browser = static_cast(user_data); - - gtk_gl_area_make_current(area); - GError* error = gtk_gl_area_get_error(area); - if (error != nullptr) { - errorLog("InAppBrowser: GtkGLArea error during realize: %s", error->message); - return; - } - - // Create texture for EGL image binding - glGenTextures(1, &browser->glTexture_); - - // === Shader-based rendering setup (OpenGL ES compatible) === - // Vertex shader - transforms position and passes texture coords - const char* vertexSource = - "#version 100\n" - "attribute vec2 position;\n" - "attribute vec2 texture;\n" - "varying vec2 v_texture;\n" - "void main() {\n" - " v_texture = texture;\n" - " gl_Position = vec4(position, 0.0, 1.0);\n" - "}\n"; - - // Fragment shader - samples texture - const char* fragmentSource = - "#version 100\n" - "precision mediump float;\n" - "uniform sampler2D u_texture;\n" - "varying vec2 v_texture;\n" - "void main() {\n" - " gl_FragColor = texture2D(u_texture, v_texture);\n" - "}\n"; - - // Compile vertex shader - GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertexShader, 1, &vertexSource, nullptr); - glCompileShader(vertexShader); - - GLint compiled = 0; - glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &compiled); - if (!compiled) { - GLchar infoLog[512]; - glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog); - errorLog("InAppBrowser: Vertex shader compilation failed: %s", infoLog); - glDeleteShader(vertexShader); - return; - } - - // Compile fragment shader - GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragmentShader, 1, &fragmentSource, nullptr); - glCompileShader(fragmentShader); - - glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &compiled); - if (!compiled) { - GLchar infoLog[512]; - glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog); - errorLog("InAppBrowser: Fragment shader compilation failed: %s", infoLog); - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - return; - } - - // Create and link program - browser->glProgram_ = glCreateProgram(); - glAttachShader(browser->glProgram_, vertexShader); - glAttachShader(browser->glProgram_, fragmentShader); - glLinkProgram(browser->glProgram_); - - GLint linked = 0; - glGetProgramiv(browser->glProgram_, GL_LINK_STATUS, &linked); - if (!linked) { - GLchar infoLog[512]; - glGetProgramInfoLog(browser->glProgram_, 512, nullptr, infoLog); - errorLog("InAppBrowser: Shader program linking failed: %s", infoLog); - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - glDeleteProgram(browser->glProgram_); - browser->glProgram_ = 0; - return; - } - - // Shaders are linked into program, can delete them now - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - - // Get attribute and uniform locations - browser->glAttribPosition_ = glGetAttribLocation(browser->glProgram_, "position"); - browser->glAttribTexture_ = glGetAttribLocation(browser->glProgram_, "texture"); - browser->glUniformTexture_ = glGetUniformLocation(browser->glProgram_, "u_texture"); - - // Create VBO with fullscreen quad vertex data (matching COG's layout) - // Non-interleaved: positions first, then texture coords - // Position (NDC): forms a quad covering -1 to 1 in both axes using TRIANGLE_STRIP - // Order: top-left, top-right, bottom-left, bottom-right - static const GLfloat vertexData[] = { - // Positions (8 floats) - -1.0f, 1.0f, // Top-left - 1.0f, 1.0f, // Top-right - -1.0f, -1.0f, // Bottom-left - 1.0f, -1.0f, // Bottom-right - // Texture coordinates (8 floats) - Y flipped for correct orientation - 0.0f, 0.0f, // Top-left - 1.0f, 0.0f, // Top-right - 0.0f, 1.0f, // Bottom-left - 1.0f, 1.0f, // Bottom-right - }; - - glGenBuffers(1, &browser->glVBO_); - glBindBuffer(GL_ARRAY_BUFFER, browser->glVBO_); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - browser->glInitialized_ = true; - - // Set initial size - GtkAllocation alloc; - gtk_widget_get_allocation(GTK_WIDGET(area), &alloc); - if (browser->webView_) { - browser->webView_->setSize(alloc.width, alloc.height); - } -} - -gboolean InAppBrowser::OnGlAreaRender(GtkGLArea* area, GdkGLContext* context, - gpointer user_data) { - auto* browser = static_cast(user_data); - - if (!browser || browser->destroyed_ || !browser->webView_ || !browser->glInitialized_) { - return FALSE; - } - - // Clear the framebuffer with white background - glClearColor(1.0f, 1.0f, 1.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - // Get viewport dimensions - need to account for device scale factor - GtkAllocation alloc; - gtk_widget_get_allocation(GTK_WIDGET(area), &alloc); - gint scaleFactor = gtk_widget_get_scale_factor(GTK_WIDGET(area)); - - // For high-DPI displays, the actual framebuffer is larger - int fbWidth = alloc.width * scaleFactor; - int fbHeight = alloc.height * scaleFactor; - - glViewport(0, 0, fbWidth, fbHeight); - - // Try to get EGL image for zero-copy rendering - uint32_t imgWidth = 0, imgHeight = 0; - void* eglImage = browser->webView_->GetCurrentEglImage(&imgWidth, &imgHeight); - - if (eglImage != nullptr && imgWidth > 0 && imgHeight > 0) { - // Get the glEGLImageTargetTexture2DOES function - static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = - (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES"); - - if (glEGLImageTargetTexture2DOES != nullptr && browser->glProgram_ != 0) { - // Zero-copy path: bind EGL image directly as GL texture - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, browser->glTexture_); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast(eglImage)); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - // Use shader program for rendering - glUseProgram(browser->glProgram_); - glUniform1i(browser->glUniformTexture_, 0); - - // Bind VBO and set up vertex attributes (non-interleaved layout) - glBindBuffer(GL_ARRAY_BUFFER, browser->glVBO_); - - // Position attribute: 2 floats, stride 0 (tightly packed), offset 0 - glVertexAttribPointer(browser->glAttribPosition_, 2, GL_FLOAT, GL_FALSE, - 0, (void*)0); - glEnableVertexAttribArray(browser->glAttribPosition_); - - // Texture attribute: 2 floats, stride 0, offset = 4 positions * 2 floats = 8 floats - glVertexAttribPointer(browser->glAttribTexture_, 2, GL_FLOAT, GL_FALSE, - 0, (void*)(8 * sizeof(GLfloat))); - glEnableVertexAttribArray(browser->glAttribTexture_); - - // Draw fullscreen quad as triangle strip - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - - - // Cleanup state - glDisableVertexAttribArray(browser->glAttribPosition_); - glDisableVertexAttribArray(browser->glAttribTexture_); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - glUseProgram(0); - - return TRUE; - } - } - - // Fallback: use pixel buffer rendering - return browser->RenderFromPixelBuffer(area); -} - -void InAppBrowser::OnGlAreaResize(GtkGLArea* area, gint width, gint height, - gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser && browser->webView_ && width > 0 && height > 0) { - // GtkGLArea resize signal provides physical pixel dimensions - // WebView needs logical dimensions, so divide by scale factor - gint scaleFactor = gtk_widget_get_scale_factor(GTK_WIDGET(area)); - gint logicalWidth = width / scaleFactor; - gint logicalHeight = height / scaleFactor; - // Set scale factor for HiDPI rendering - WebView will render at physical resolution - browser->webView_->setScaleFactor(static_cast(scaleFactor)); - browser->webView_->setSize(logicalWidth, logicalHeight); - } -} - -void InAppBrowser::OnGlAreaSizeAllocate(GtkWidget* widget, GdkRectangle* allocation, - gpointer user_data) { - auto* browser = static_cast(user_data); - if (browser && browser->webView_ && allocation) { - if (allocation->width > 0 && allocation->height > 0) { - // size-allocate gives logical dimensions, which is what WebView needs - // Also set scale factor for HiDPI rendering - gint scaleFactor = gtk_widget_get_scale_factor(widget); - browser->webView_->setScaleFactor(static_cast(scaleFactor)); - browser->webView_->setSize(allocation->width, allocation->height); - // Queue a redraw to ensure the GL content is re-rendered at new size - if (browser->glArea_ != nullptr) { - gtk_gl_area_queue_render(GTK_GL_AREA(browser->glArea_)); - } - } - } -} - -gboolean InAppBrowser::RenderFromPixelBuffer(GtkGLArea* area) { - // Fallback: upload pixel buffer to texture and render - // This handles SHM mode where EGL images aren't available - - if (!webView_ || !glInitialized_ || glProgram_ == 0) { - return TRUE; // Nothing to render, but handled - } - - uint32_t width = 0, height = 0; - size_t bufferSize = webView_->GetPixelBufferSize(&width, &height); - - if (bufferSize == 0 || width == 0 || height == 0) { - return TRUE; // Nothing to render - } - - std::vector buffer(bufferSize); - if (!webView_->CopyPixelBufferTo(buffer.data(), bufferSize, &width, &height)) { - return FALSE; - } - - // Get viewport dimensions - account for device scale factor - GtkAllocation alloc; - gtk_widget_get_allocation(GTK_WIDGET(area), &alloc); - gint scaleFactor = gtk_widget_get_scale_factor(GTK_WIDGET(area)); - int fbWidth = alloc.width * scaleFactor; - int fbHeight = alloc.height * scaleFactor; - - glViewport(0, 0, fbWidth, fbHeight); - - // Upload pixel buffer to texture - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, glTexture_); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, buffer.data()); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - // Use shader program for rendering - glUseProgram(glProgram_); - glUniform1i(glUniformTexture_, 0); - - // Bind VBO and set up vertex attributes (non-interleaved layout) - glBindBuffer(GL_ARRAY_BUFFER, glVBO_); - - // Position attribute: 2 floats, stride 0 (tightly packed), offset 0 - glVertexAttribPointer(glAttribPosition_, 2, GL_FLOAT, GL_FALSE, - 0, (void*)0); - glEnableVertexAttribArray(glAttribPosition_); - - // Texture attribute: 2 floats, stride 0, offset = 4 positions * 2 floats = 8 floats - glVertexAttribPointer(glAttribTexture_, 2, GL_FLOAT, GL_FALSE, - 0, (void*)(8 * sizeof(GLfloat))); - glEnableVertexAttribArray(glAttribTexture_); - - // Draw fullscreen quad as triangle strip - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - // Cleanup state - glDisableVertexAttribArray(glAttribPosition_); - glDisableVertexAttribArray(glAttribTexture_); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - glUseProgram(0); - - return TRUE; -} - -void InAppBrowser::OnCursorChanged(const std::string& cursorName) { - // Handle cursor changes for both GL area and drawing area - GtkWidget* targetWidget = useGlRendering_ ? glArea_ : drawingArea_; - if (destroyed_ || targetWidget == nullptr) { - return; - } - - GdkWindow* gdkWindow = gtk_widget_get_window(targetWidget); - if (!gdkWindow) { - return; - } - - // Clean up previous cursor - if (currentCursor_ != nullptr) { - g_object_unref(currentCursor_); - currentCursor_ = nullptr; - } - - if (cursorName == "none") { - currentCursor_ = gdk_cursor_new_for_display(gdk_display_get_default(), GDK_BLANK_CURSOR); - gdk_window_set_cursor(gdkWindow, currentCursor_); - return; - } - - // Use gdk_cursor_new_from_name which accepts CSS cursor names (GTK 3.16+) - GdkDisplay* display = gdk_display_get_default(); - currentCursor_ = gdk_cursor_new_from_name(display, cursorName.c_str()); - - // Fallback if cursor name not recognized - if (!currentCursor_) { - currentCursor_ = gdk_cursor_new_from_name(display, "default"); - } - - // Ultimate fallback to GDK_LEFT_PTR - if (!currentCursor_) { - currentCursor_ = gdk_cursor_new_for_display(display, GDK_LEFT_PTR); - } - - gdk_window_set_cursor(gdkWindow, currentCursor_); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser.h b/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser.h deleted file mode 100644 index 2d469e6a5e..0000000000 --- a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser.h +++ /dev/null @@ -1,235 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_BROWSER_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_BROWSER_H_ - -#include -#include - -#include -#include -#include -#include - -#include "../in_app_webview/in_app_webview.h" -#include "../in_app_webview/in_app_webview_settings.h" -#include "../types/url_request.h" -#include "in_app_browser_channel_delegate.h" -#include "in_app_browser_settings.h" - -namespace flutter_inappwebview_plugin { - -class InAppBrowserManager; -class PluginInstance; - -/// Menu item for InAppBrowser -struct InAppBrowserMenuItem { - int32_t id = 0; - std::string title; - int32_t order = 0; - - InAppBrowserMenuItem() = default; - explicit InAppBrowserMenuItem(FlValue* map); -}; - -/// Creation parameters for InAppBrowser -struct InAppBrowserCreationParams { - PluginInstance* plugin = nullptr; - std::string id; - std::optional> urlRequest; - std::optional assetFilePath; - std::optional data; - std::shared_ptr initialSettings; - std::shared_ptr initialWebViewSettings; - std::optional>> initialUserScripts; - std::optional webViewEnvironmentId; - std::optional> contextMenu; - std::vector menuItems; -}; - -/// InAppBrowser - A standalone browser window with embedded WebView -/// -/// Creates a GTK window with an optional toolbar and an embedded WPE WebView. -/// Supports navigation controls, URL bar, progress indicator, and custom menus. -/// -/// The browser window can be shown, hidden, and configured with various settings -/// like window size, position, opacity, and toolbar visibility. -class InAppBrowser { - public: - static constexpr const char* METHOD_CHANNEL_NAME_PREFIX = - "com.pichillilorenzo/flutter_inappbrowser_"; - - /// Create an InAppBrowser with the given parameters - /// @param manager The manager that owns this browser - /// @param messenger The Flutter binary messenger for channel communication - /// @param parentWindow The parent GTK window (optional, for child window type) - /// @param params Creation parameters - InAppBrowser(InAppBrowserManager* manager, FlBinaryMessenger* messenger, - GtkWindow* parentWindow, const InAppBrowserCreationParams& params); - ~InAppBrowser(); - - /// Get the unique ID of this browser - const std::string& id() const { return id_; } - - /// Get the GTK window - GtkWindow* getWindow() const { return window_; } - - /// Get the embedded WebView - InAppWebView* webView() const { return webView_.get(); } - - /// Get the channel delegate - InAppBrowserChannelDelegate* channelDelegate() const { return channelDelegate_.get(); } - - /// Get the current settings - std::shared_ptr settings() const { return settings_; } - - /// Close the browser window - void close(); - - /// Show the browser window - void show(); - - /// Hide the browser window - void hide(); - - /// Check if the browser is hidden - bool isHidden() const; - - /// Update the browser settings - /// @param newSettings The new settings to apply - /// @param newSettingsMap The FlValue map of new settings (for checking which changed) - void setSettings(const std::shared_ptr& newSettings, - FlValue* newSettingsMap); - - /// Get the current settings as FlValue - FlValue* getSettings() const; - - /// Called when the WebView title changes - void didChangeTitle(const std::optional& title); - - /// Called when the WebView URL changes - void didChangeUrl(const std::optional& url); - - /// Called when the load progress changes - void didChangeProgress(double progress); - - /// Called when navigation state changes (can go back/forward) - void didChangeNavigationState(); - - private: - PluginInstance* plugin_ = nullptr; - InAppBrowserManager* manager_ = nullptr; - FlBinaryMessenger* messenger_ = nullptr; - GtkWindow* parentWindow_ = nullptr; // Parent window for child window type - std::string id_; - bool destroyed_ = false; - - // GTK Window (created by this browser) - GtkWindow* window_ = nullptr; - - // Toolbar widgets - GtkWidget* headerBar_ = nullptr; - GtkWidget* backButton_ = nullptr; - GtkWidget* forwardButton_ = nullptr; - GtkWidget* reloadButton_ = nullptr; - GtkWidget* urlEntry_ = nullptr; - GtkWidget* progressBar_ = nullptr; - GtkWidget* menuButton_ = nullptr; - GtkWidget* contentBox_ = nullptr; - - // WebView rendering - std::shared_ptr webView_; - GtkWidget* drawingArea_ = nullptr; - guint frameSourceId_ = 0; - GdkCursor* currentCursor_ = nullptr; - - // GPU rendering with GtkGLArea (zero-copy EGL texture path) - GtkWidget* glArea_ = nullptr; - bool useGlRendering_ = false; - unsigned int glTexture_ = 0; - bool glInitialized_ = false; - - // Shader-based rendering (OpenGL ES compatible) - unsigned int glProgram_ = 0; - unsigned int glVBO_ = 0; - int glAttribPosition_ = -1; - int glAttribTexture_ = -1; - int glUniformTexture_ = -1; - - // Channel delegate - std::unique_ptr channelDelegate_; - - // Settings - std::shared_ptr settings_; - - // Menu items - std::vector menuItems_; - - // Window setup methods - void setupWindow(const InAppBrowserCreationParams& params); - void setupToolbar(); - void setupWebView(const InAppBrowserCreationParams& params); - void setupDrawingArea(); - void applySettings(); - void loadInitialContent(const InAppBrowserCreationParams& params); - - // Update toolbar state - void updateNavigationButtons(); - void updateProgressBar(double progress); - void updateUrlEntry(const std::string& url); - void updateTitle(const std::string& title); - - // GTK Signal handlers (static callbacks) - static void OnWindowDestroy(GtkWidget* widget, gpointer user_data); - static gboolean OnWindowDeleteEvent(GtkWidget* widget, GdkEvent* event, gpointer user_data); - static void OnBackClicked(GtkButton* button, gpointer user_data); - static void OnForwardClicked(GtkButton* button, gpointer user_data); - static void OnReloadClicked(GtkButton* button, gpointer user_data); - static void OnUrlEntryActivated(GtkEntry* entry, gpointer user_data); - static gboolean OnDrawingAreaDraw(GtkWidget* widget, cairo_t* cr, gpointer user_data); - static void OnDrawingAreaRealize(GtkWidget* widget, gpointer user_data); - static gboolean OnDrawingAreaButtonPress(GtkWidget* widget, GdkEventButton* event, - gpointer user_data); - static gboolean OnDrawingAreaButtonRelease(GtkWidget* widget, GdkEventButton* event, - gpointer user_data); - static gboolean OnDrawingAreaMotionNotify(GtkWidget* widget, GdkEventMotion* event, - gpointer user_data); - static gboolean OnDrawingAreaScroll(GtkWidget* widget, GdkEventScroll* event, - gpointer user_data); - static gboolean OnDrawingAreaKeyPress(GtkWidget* widget, GdkEventKey* event, - gpointer user_data); - static gboolean OnDrawingAreaKeyRelease(GtkWidget* widget, GdkEventKey* event, - gpointer user_data); - static void OnDrawingAreaSizeAllocate(GtkWidget* widget, GdkRectangle* allocation, gpointer user_data); - static gboolean OnDrawingAreaFocusIn(GtkWidget* widget, GdkEventFocus* event, gpointer user_data); - static gboolean OnDrawingAreaFocusOut(GtkWidget* widget, GdkEventFocus* event, gpointer user_data); - static void OnDrawingAreaMap(GtkWidget* widget, gpointer user_data); - static void OnDrawingAreaUnmap(GtkWidget* widget, gpointer user_data); - static gboolean OnDrawingAreaEnterNotify(GtkWidget* widget, GdkEventCrossing* event, gpointer user_data); - static gboolean OnDrawingAreaLeaveNotify(GtkWidget* widget, GdkEventCrossing* event, gpointer user_data); - static void OnMenuItemActivated(GtkMenuItem* item, gpointer user_data); - - // GtkGLArea signal handlers (for GPU-accelerated rendering) - static void OnGlAreaRealize(GtkGLArea* area, gpointer user_data); - static gboolean OnGlAreaRender(GtkGLArea* area, GdkGLContext* context, gpointer user_data); - static void OnGlAreaResize(GtkGLArea* area, gint width, gint height, gpointer user_data); - static void OnGlAreaSizeAllocate(GtkWidget* widget, GdkRectangle* allocation, gpointer user_data); - - // Fallback pixel buffer rendering (for SHM mode or when EGL is unavailable) - gboolean RenderFromPixelBuffer(GtkGLArea* area); - - // Fallback setup for GtkDrawingArea (when GtkGLArea fails) - void setupDrawingAreaFallback(); - - // Cursor change handler - void OnCursorChanged(const std::string& cursorName); - - // Schedule frame redraw - void scheduleFrame(); - static gboolean OnFrameCallback(gpointer user_data); - - // Clean up - void cleanup(); -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_BROWSER_H_ diff --git a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_channel_delegate.cc b/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_channel_delegate.cc deleted file mode 100644 index abdb088e9e..0000000000 --- a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_channel_delegate.cc +++ /dev/null @@ -1,98 +0,0 @@ -#include "in_app_browser_channel_delegate.h" - -#include - -#include "../utils/flutter.h" -#include "../utils/log.h" -#include "in_app_browser.h" - -namespace flutter_inappwebview_plugin { - -InAppBrowserChannelDelegate::InAppBrowserChannelDelegate(InAppBrowser* browser, - FlBinaryMessenger* messenger, - const std::string& channelName) - : ChannelDelegate(messenger, channelName), browser_(browser) {} - -InAppBrowserChannelDelegate::~InAppBrowserChannelDelegate() { - debugLog("dealloc InAppBrowserChannelDelegate"); - browser_ = nullptr; -} - -void InAppBrowserChannelDelegate::HandleMethodCall(FlMethodCall* method_call) { - const gchar* methodName = fl_method_call_get_name(method_call); - FlValue* args = fl_method_call_get_args(method_call); - - if (browser_ == nullptr) { - fl_method_call_respond_error(method_call, "ERROR", "Browser instance is null", nullptr, - nullptr); - return; - } - - if (strcmp(methodName, "show") == 0) { - browser_->show(); - fl_method_call_respond_success(method_call, fl_value_new_bool(true), nullptr); - return; - } - - if (strcmp(methodName, "hide") == 0) { - browser_->hide(); - fl_method_call_respond_success(method_call, fl_value_new_bool(true), nullptr); - return; - } - - if (strcmp(methodName, "close") == 0) { - browser_->close(); - fl_method_call_respond_success(method_call, fl_value_new_bool(true), nullptr); - return; - } - - if (strcmp(methodName, "isHidden") == 0) { - bool hidden = browser_->isHidden(); - fl_method_call_respond_success(method_call, fl_value_new_bool(hidden), nullptr); - return; - } - - if (strcmp(methodName, "setSettings") == 0) { - FlValue* settingsValue = fl_value_lookup_string(args, "settings"); - if (settingsValue != nullptr && fl_value_get_type(settingsValue) == FL_VALUE_TYPE_MAP) { - auto newSettings = std::make_shared(settingsValue); - browser_->setSettings(newSettings, settingsValue); - } - fl_method_call_respond_success(method_call, fl_value_new_bool(true), nullptr); - return; - } - - if (strcmp(methodName, "getSettings") == 0) { - g_autoptr(FlValue) result = browser_->getSettings(); - fl_method_call_respond_success(method_call, result, nullptr); - return; - } - - fl_method_call_respond_not_implemented(method_call, nullptr); -} - -void InAppBrowserChannelDelegate::onBrowserCreated() const { - if (channel_ == nullptr) { - return; - } - invokeMethod("onBrowserCreated", nullptr); -} - -void InAppBrowserChannelDelegate::onMenuItemClicked(int32_t menuItemId) const { - if (channel_ == nullptr) { - return; - } - g_autoptr(FlValue) args = to_fl_map({ - {"id", make_fl_value(static_cast(menuItemId))}, - }); - invokeMethod("onMenuItemClicked", args); -} - -void InAppBrowserChannelDelegate::onExit() const { - if (channel_ == nullptr) { - return; - } - invokeMethod("onExit", nullptr); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_channel_delegate.h b/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_channel_delegate.h deleted file mode 100644 index 3d53968362..0000000000 --- a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_channel_delegate.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_BROWSER_CHANNEL_DELEGATE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_BROWSER_CHANNEL_DELEGATE_H_ - -#include - -#include - -#include "../types/channel_delegate.h" - -namespace flutter_inappwebview_plugin { - -class InAppBrowser; - -/// Channel delegate for InAppBrowser instance communication -/// -/// Handles method calls from Dart and sends events back to the Dart side. -/// Each InAppBrowser instance has its own channel delegate with a unique channel name. -class InAppBrowserChannelDelegate : public ChannelDelegate { - public: - /// Create a channel delegate for a specific browser instance - /// @param browser The browser instance this delegate belongs to - /// @param messenger The Flutter binary messenger - /// @param channelName The unique channel name for this browser - InAppBrowserChannelDelegate(InAppBrowser* browser, FlBinaryMessenger* messenger, - const std::string& channelName); - ~InAppBrowserChannelDelegate() override; - - /// Handle method calls from Flutter - void HandleMethodCall(FlMethodCall* method_call) override; - - /// Notify Dart that the browser window has been created - void onBrowserCreated() const; - - /// Notify Dart that a menu item was clicked - /// @param menuItemId The ID of the clicked menu item - void onMenuItemClicked(int32_t menuItemId) const; - - /// Notify Dart that the browser window is about to close - void onExit() const; - - private: - InAppBrowser* browser_ = nullptr; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_BROWSER_CHANNEL_DELEGATE_H_ diff --git a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_manager.cc b/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_manager.cc deleted file mode 100644 index e7891f3076..0000000000 --- a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_manager.cc +++ /dev/null @@ -1,234 +0,0 @@ -#include "in_app_browser_manager.h" - -#include - -#include - -#include "../plugin_instance.h" -#include "../in_app_webview/in_app_webview_settings.h" -#include "../types/url_request.h" -#include "../types/user_script.h" -#include "../types/context_menu.h" -#include "../utils/flutter.h" -#include "../utils/log.h" - -namespace flutter_inappwebview_plugin { - -InAppBrowserManager::InAppBrowserManager(PluginInstance* plugin) : plugin_(plugin) { - // Validate plugin - if (plugin_ == nullptr) { - errorLog("InAppBrowserManager: Invalid plugin instance"); - return; - } - - registrar_ = plugin_->registrar(); - if (!FL_IS_PLUGIN_REGISTRAR(registrar_)) { - errorLog("InAppBrowserManager: Invalid registrar"); - return; - } - - messenger_ = plugin_->messenger(); - if (messenger_ == nullptr || !FL_IS_BINARY_MESSENGER(messenger_)) { - errorLog("InAppBrowserManager: Failed to get messenger from plugin"); - messenger_ = nullptr; - return; - } - - // Keep reference to messenger to ensure it stays valid - g_object_ref(messenger_); - - // Cache the GTK window and FlView from plugin - gtk_window_ = plugin_->gtkWindow(); - fl_view_ = plugin_->flView(); - - // Create the method channel - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - method_channel_ = fl_method_channel_new(messenger_, METHOD_CHANNEL_NAME, FL_METHOD_CODEC(codec)); - - fl_method_channel_set_method_call_handler(method_channel_, HandleMethodCall, this, nullptr); -} - -InAppBrowserManager::~InAppBrowserManager() { - debugLog("dealloc InAppBrowserManager"); - - // Clean up all browsers first - browsers_.clear(); - - if (method_channel_ != nullptr) { - fl_method_channel_set_method_call_handler(method_channel_, nullptr, nullptr, nullptr); - g_object_unref(method_channel_); - method_channel_ = nullptr; - } - - // Release messenger reference - if (messenger_ != nullptr) { - g_object_unref(messenger_); - messenger_ = nullptr; - } - - gtk_window_ = nullptr; - fl_view_ = nullptr; - registrar_ = nullptr; - plugin_ = nullptr; -} - -FlPluginRegistrar* InAppBrowserManager::registrar() const { - return registrar_; -} - -void InAppBrowserManager::HandleMethodCall(FlMethodChannel* channel, FlMethodCall* method_call, - gpointer user_data) { - auto* self = static_cast(user_data); - self->HandleMethodCallImpl(method_call); -} - -void InAppBrowserManager::HandleMethodCallImpl(FlMethodCall* method_call) { - const gchar* method = fl_method_call_get_name(method_call); - FlValue* args = fl_method_call_get_args(method_call); - - if (strcmp(method, "open") == 0) { - createInAppBrowser(args); - fl_method_call_respond_success(method_call, fl_value_new_bool(true), nullptr); - return; - } - - if (strcmp(method, "openWithSystemBrowser") == 0) { - auto urlOpt = get_optional_fl_map_value(args, "url"); - if (urlOpt.has_value()) { - openWithSystemBrowser(urlOpt.value(), method_call); - } else { - fl_method_call_respond_error(method_call, "INVALID_ARGUMENTS", "URL is required", nullptr, - nullptr); - } - return; - } - - fl_method_call_respond_not_implemented(method_call, nullptr); -} - -void InAppBrowserManager::createInAppBrowser(FlValue* arguments) { - if (arguments == nullptr || fl_value_get_type(arguments) != FL_VALUE_TYPE_MAP) { - return; - } - - // Parse arguments - std::string id = get_fl_map_value(arguments, "id", ""); - if (id.empty()) { - debugLog("InAppBrowserManager: Missing browser ID"); - return; - } - - // Parse URL request - std::optional> urlRequest; - FlValue* urlRequestValue = fl_value_lookup_string(arguments, "urlRequest"); - if (urlRequestValue != nullptr && fl_value_get_type(urlRequestValue) == FL_VALUE_TYPE_MAP) { - urlRequest = std::make_shared(urlRequestValue); - } - - // Parse asset file path - auto assetFilePath = get_optional_fl_map_value(arguments, "assetFilePath"); - - // Parse data - auto data = get_optional_fl_map_value(arguments, "data"); - - // Parse settings - FlValue* settingsValue = fl_value_lookup_string(arguments, "settings"); - auto initialSettings = std::make_shared(settingsValue); - auto initialWebViewSettings = std::make_shared(settingsValue); - - // Parse user scripts - std::optional>> initialUserScripts; - FlValue* userScriptsValue = fl_value_lookup_string(arguments, "initialUserScripts"); - if (userScriptsValue != nullptr && fl_value_get_type(userScriptsValue) == FL_VALUE_TYPE_LIST) { - std::vector> scripts; - size_t count = fl_value_get_length(userScriptsValue); - for (size_t i = 0; i < count; i++) { - FlValue* scriptValue = fl_value_get_list_value(userScriptsValue, i); - if (scriptValue != nullptr && fl_value_get_type(scriptValue) == FL_VALUE_TYPE_MAP) { - scripts.push_back(std::make_shared(scriptValue)); - } - } - if (!scripts.empty()) { - initialUserScripts = scripts; - } - } - - // Parse WebView environment ID - auto webViewEnvironmentId = get_optional_fl_map_value(arguments, "webViewEnvironmentId"); - - // Parse context menu - std::optional> contextMenu; - FlValue* contextMenuValue = fl_value_lookup_string(arguments, "contextMenu"); - if (contextMenuValue != nullptr && fl_value_get_type(contextMenuValue) == FL_VALUE_TYPE_MAP) { - contextMenu = std::make_shared(contextMenuValue); - } - - // Parse menu items - std::vector menuItems; - FlValue* menuItemsValue = fl_value_lookup_string(arguments, "menuItems"); - if (menuItemsValue != nullptr && fl_value_get_type(menuItemsValue) == FL_VALUE_TYPE_LIST) { - size_t count = fl_value_get_length(menuItemsValue); - for (size_t i = 0; i < count; i++) { - FlValue* itemValue = fl_value_get_list_value(menuItemsValue, i); - if (itemValue != nullptr && fl_value_get_type(itemValue) == FL_VALUE_TYPE_MAP) { - menuItems.push_back(InAppBrowserMenuItem(itemValue)); - } - } - } - - // Create params - InAppBrowserCreationParams params; - params.plugin = plugin_; - params.id = id; - params.urlRequest = urlRequest; - params.assetFilePath = assetFilePath; - params.data = data; - params.initialSettings = initialSettings; - params.initialWebViewSettings = initialWebViewSettings; - params.initialUserScripts = initialUserScripts; - params.webViewEnvironmentId = webViewEnvironmentId; - params.contextMenu = contextMenu; - params.menuItems = menuItems; - - // Create the browser - pass cached messenger directly - auto browser = std::make_unique(this, messenger_, gtk_window_, params); - browsers_[id] = std::move(browser); -} - -void InAppBrowserManager::openWithSystemBrowser(const std::string& url, - FlMethodCall* method_call) { - GError* error = nullptr; - - // Use GIO to open the URL with the default handler - gboolean success = g_app_info_launch_default_for_uri(url.c_str(), nullptr, &error); - - if (!success) { - std::string errorMsg = "Failed to open URL"; - if (error != nullptr) { - errorMsg = error->message; - g_error_free(error); - } - debugLog("InAppBrowserManager: " + errorMsg + " - " + url); - fl_method_call_respond_error(method_call, "OPEN_URL_ERROR", errorMsg.c_str(), nullptr, nullptr); - return; - } - - fl_method_call_respond_success(method_call, fl_value_new_bool(true), nullptr); -} - -void InAppBrowserManager::removeBrowser(const std::string& id) { - auto it = browsers_.find(id); - if (it != browsers_.end()) { - browsers_.erase(it); - } -} - -InAppBrowser* InAppBrowserManager::getBrowser(const std::string& id) { - auto it = browsers_.find(id); - if (it != browsers_.end()) { - return it->second.get(); - } - return nullptr; -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_manager.h b/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_manager.h deleted file mode 100644 index a886b7fc40..0000000000 --- a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_manager.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_BROWSER_MANAGER_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_BROWSER_MANAGER_H_ - -#include - -#include -#include -#include - -#include "in_app_browser.h" - -namespace flutter_inappwebview_plugin { - -class PluginInstance; - -/// Manager class for InAppBrowser instances -/// -/// Handles the static method channel for creating browsers and opening URLs -/// with the system browser. Maintains a map of all active browser instances. -class InAppBrowserManager { - public: - static constexpr const char* METHOD_CHANNEL_NAME = - "com.pichillilorenzo/flutter_inappbrowser"; - - /// Create the manager - /// @param plugin The plugin instance - InAppBrowserManager(PluginInstance* plugin); - ~InAppBrowserManager(); - - /// Get the plugin instance - PluginInstance* plugin() const { return plugin_; } - - /// Get the registrar - FlPluginRegistrar* registrar() const; - - /// Get the messenger - FlBinaryMessenger* messenger() const { return messenger_; } - - /// Create a new InAppBrowser instance - /// @param arguments The creation arguments from Dart - void createInAppBrowser(FlValue* arguments); - - /// Open a URL with the system browser - /// @param url The URL to open - /// @param result The method result to respond to - void openWithSystemBrowser(const std::string& url, FlMethodCall* method_call); - - /// Remove a browser from the manager (called when browser is destroyed) - /// @param id The browser ID to remove - void removeBrowser(const std::string& id); - - /// Get a browser by ID - /// @param id The browser ID - /// @return The browser instance or nullptr - InAppBrowser* getBrowser(const std::string& id); - - private: - PluginInstance* plugin_ = nullptr; - FlPluginRegistrar* registrar_ = nullptr; - FlBinaryMessenger* messenger_ = nullptr; - FlMethodChannel* method_channel_ = nullptr; - GtkWindow* gtk_window_ = nullptr; - FlView* fl_view_ = nullptr; - - /// Map of browser ID to browser instance - std::map> browsers_; - - /// Handle method calls from Flutter - static void HandleMethodCall(FlMethodChannel* channel, FlMethodCall* method_call, - gpointer user_data); - void HandleMethodCallImpl(FlMethodCall* method_call); -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_BROWSER_MANAGER_H_ diff --git a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_settings.cc b/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_settings.cc deleted file mode 100644 index cfd483547e..0000000000 --- a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_settings.cc +++ /dev/null @@ -1,127 +0,0 @@ -#include "in_app_browser_settings.h" - -#include - -#include "../utils/flutter.h" -#include "../utils/log.h" -#include "in_app_browser.h" - -namespace flutter_inappwebview_plugin { - -namespace { - -InAppBrowserWindowType windowTypeFromString(const std::string& s) { - if (s == "CHILD") { - return InAppBrowserWindowType::child; - } - return InAppBrowserWindowType::window; -} - -std::string windowTypeToString(InAppBrowserWindowType t) { - switch (t) { - case InAppBrowserWindowType::child: - return "CHILD"; - default: - return "WINDOW"; - } -} - -} // namespace - -// InAppBrowserRect implementation - -InAppBrowserRect::InAppBrowserRect(FlValue* map) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - x = get_fl_map_value(map, "x", 0); - y = get_fl_map_value(map, "y", 0); - width = get_fl_map_value(map, "width", 0); - height = get_fl_map_value(map, "height", 0); -} - -FlValue* InAppBrowserRect::toFlValue() const { - return to_fl_map({ - {"x", make_fl_value(x)}, - {"y", make_fl_value(y)}, - {"width", make_fl_value(width)}, - {"height", make_fl_value(height)}, - }); -} - -// InAppBrowserSettings implementation - -InAppBrowserSettings::InAppBrowserSettings() = default; - -InAppBrowserSettings::InAppBrowserSettings(FlValue* map) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - hidden = get_fl_map_value(map, "hidden", hidden); - hideToolbarTop = get_fl_map_value(map, "hideToolbarTop", hideToolbarTop); - toolbarTopBackgroundColor = get_fl_map_value(map, "toolbarTopBackgroundColor", toolbarTopBackgroundColor); - hideUrlBar = get_fl_map_value(map, "hideUrlBar", hideUrlBar); - hideProgressBar = get_fl_map_value(map, "hideProgressBar", hideProgressBar); - hideDefaultMenuItems = get_fl_map_value(map, "hideDefaultMenuItems", hideDefaultMenuItems); - toolbarTopFixedTitle = get_fl_map_value(map, "toolbarTopFixedTitle", toolbarTopFixedTitle); - - auto windowTypeStr = get_fl_map_value(map, "windowType", "WINDOW"); - windowType = windowTypeFromString(windowTypeStr); - - windowAlphaValue = get_fl_map_value(map, "windowAlphaValue", windowAlphaValue); - - FlValue* frameValue = fl_value_lookup_string(map, "windowFrame"); - if (frameValue != nullptr && fl_value_get_type(frameValue) == FL_VALUE_TYPE_MAP) { - windowFrame = std::make_shared(frameValue); - } -} - -InAppBrowserSettings::~InAppBrowserSettings() { - debugLog("dealloc InAppBrowserSettings"); -} - -FlValue* InAppBrowserSettings::toFlValue() const { - FlValue* result = to_fl_map({ - {"hidden", make_fl_value(hidden)}, - {"hideToolbarTop", make_fl_value(hideToolbarTop)}, - {"toolbarTopBackgroundColor", make_fl_value(toolbarTopBackgroundColor)}, - {"hideUrlBar", make_fl_value(hideUrlBar)}, - {"hideProgressBar", make_fl_value(hideProgressBar)}, - {"hideDefaultMenuItems", make_fl_value(hideDefaultMenuItems)}, - {"toolbarTopFixedTitle", make_fl_value(toolbarTopFixedTitle)}, - {"windowType", make_fl_value(windowTypeToString(windowType))}, - {"windowAlphaValue", make_fl_value(windowAlphaValue)}, - {"windowFrame", windowFrame ? windowFrame->toFlValue() : fl_value_new_null()}, - }); - return result; -} - -FlValue* InAppBrowserSettings::getRealSettings(const InAppBrowser* browser) const { - FlValue* settingsMap = toFlValue(); - - if (browser != nullptr) { - GtkWindow* window = browser->getWindow(); - if (window != nullptr) { - // Update hidden state - fl_value_set_string_take(settingsMap, "hidden", - make_fl_value(!gtk_widget_is_visible(GTK_WIDGET(window)))); - - // Update window opacity - fl_value_set_string_take(settingsMap, "windowAlphaValue", - make_fl_value(gtk_widget_get_opacity(GTK_WIDGET(window)))); - - // Update window frame - int x = 0, y = 0, width = 0, height = 0; - gtk_window_get_position(window, &x, &y); - gtk_window_get_size(window, &width, &height); - InAppBrowserRect frame(static_cast(x), static_cast(y), - static_cast(width), static_cast(height)); - fl_value_set_string_take(settingsMap, "windowFrame", frame.toFlValue()); - } - } - - return settingsMap; -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_settings.h b/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_settings.h deleted file mode 100644 index 71bbe77fcd..0000000000 --- a/flutter_inappwebview_linux/linux/in_app_browser/in_app_browser_settings.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_BROWSER_SETTINGS_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_BROWSER_SETTINGS_H_ - -#include - -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -class InAppBrowser; - -/// Window type for InAppBrowser -enum class InAppBrowserWindowType { - window, // Top-level window - child // Child window (transient for parent) -}; - -/// Rect structure for window frame -struct InAppBrowserRect { - double x = 0; - double y = 0; - double width = 0; - double height = 0; - - InAppBrowserRect() = default; - InAppBrowserRect(double x, double y, double width, double height) - : x(x), y(y), width(width), height(height) {} - explicit InAppBrowserRect(FlValue* map); - - FlValue* toFlValue() const; -}; - -/// Settings class for InAppBrowser -/// -/// Stores configuration options for the browser window appearance and behavior. -class InAppBrowserSettings { - public: - /// Start with hidden window - bool hidden = false; - - /// Hide the top toolbar - bool hideToolbarTop = false; - - /// Toolbar background color (CSS color string, e.g., "#RRGGBB" or "#AARRGGBB") - std::string toolbarTopBackgroundColor; - - /// Hide the URL bar in the toolbar - bool hideUrlBar = false; - - /// Hide the progress bar - bool hideProgressBar = false; - - /// Hide the default menu items (back, forward, reload) - bool hideDefaultMenuItems = false; - - /// Fixed title for the window (instead of using page title) - std::string toolbarTopFixedTitle; - - /// Window type (top-level or child) - InAppBrowserWindowType windowType = InAppBrowserWindowType::window; - - /// Window opacity (0.0 to 1.0) - double windowAlphaValue = 1.0; - - /// Window frame (position and size) - std::shared_ptr windowFrame; - - InAppBrowserSettings(); - explicit InAppBrowserSettings(FlValue* map); - ~InAppBrowserSettings(); - - /// Convert settings to FlValue map - FlValue* toFlValue() const; - - /// Get actual settings from a live browser instance - FlValue* getRealSettings(const InAppBrowser* browser) const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_BROWSER_SETTINGS_H_ diff --git a/flutter_inappwebview_linux/linux/in_app_webview/custom_platform_view.cc b/flutter_inappwebview_linux/linux/in_app_webview/custom_platform_view.cc deleted file mode 100644 index 6ed81d841e..0000000000 --- a/flutter_inappwebview_linux/linux/in_app_webview/custom_platform_view.cc +++ /dev/null @@ -1,629 +0,0 @@ -#include "custom_platform_view.h" - -#include - -#include - -#include "../utils/flutter.h" -#include "../utils/log.h" -#include "inappwebview_egl_texture.h" -#include "inappwebview_texture.h" - -namespace flutter_inappwebview_plugin { - -namespace { -// Check if GL textures should be used (enabled by default, can be disabled) -// Disable with FLUTTER_INAPPWEBVIEW_LINUX_DISABLE_GL=1 to force software rendering. -bool UseGLTextureEnvOverride() { - if (g_getenv("FLUTTER_INAPPWEBVIEW_LINUX_DISABLE_GL") != nullptr) { - return false; - } - return true; -} - -// Check if OpenGL is actually available in the current GDK backend -bool IsOpenGLAvailable() { - static bool checked = false; - static bool available = false; - - if (checked) { - return available; - } - checked = true; - - GdkDisplay* display = gdk_display_get_default(); - if (display == nullptr) { - debugLog("CustomPlatformView: No GDK display available"); - return false; - } - - // Try to create a temporary window to test GL support - GdkWindowAttr attrs; - memset(&attrs, 0, sizeof(attrs)); - attrs.width = 1; - attrs.height = 1; - attrs.wclass = GDK_INPUT_OUTPUT; - attrs.window_type = GDK_WINDOW_TOPLEVEL; - - GdkWindow* test_window = gdk_window_new(nullptr, &attrs, 0); - if (test_window == nullptr) { - debugLog("CustomPlatformView: Failed to create test window for GL check"); - return false; - } - - GError* error = nullptr; - GdkGLContext* gl_context = gdk_window_create_gl_context(test_window, &error); - - if (gl_context != nullptr) { - available = true; - g_object_unref(gl_context); - debugLog("CustomPlatformView: OpenGL is available"); - } else { - debugLog(std::string("CustomPlatformView: OpenGL not available: ") + - (error ? error->message : "unknown error")); - if (error) { - g_error_free(error); - } - } - - gdk_window_destroy(test_window); - - return available; -} - -bool UseGLTexture() { - if (!UseGLTextureEnvOverride()) { - return false; - } - return IsOpenGLAvailable(); -} -} // namespace - -CustomPlatformView::CustomPlatformView(FlBinaryMessenger* messenger, - FlTextureRegistrar* texture_registrar, - std::shared_ptr webview) - : webview_(std::move(webview)), texture_registrar_(texture_registrar) { - if (messenger == nullptr) { - errorLog("CustomPlatformView: messenger is null"); - return; - } - - if (texture_registrar_ == nullptr) { - errorLog("CustomPlatformView: texture_registrar is null"); - return; - } - - // Create texture - two modes: - // 1. EGL/GL texture (hardware accelerated) - uses zero-copy EGL when available, - // falls back to pixel buffer upload when EGL is not available (e.g., in VMs) - // 2. Pixel buffer texture (software) - pure software fallback when GL is disabled - // - // The EGL texture handles both EGL and SHM modes internally, providing the best - // performance for each environment. - if (UseGLTexture()) { - texture_ = FL_TEXTURE(inappwebview_egl_texture_new(webview_.get())); - egl_texture_ = INAPPWEBVIEW_EGL_TEXTURE(texture_); - // In zero-copy EGL mode, we don't need pixel readback - the EGL image is passed - // directly to Flutter. This improves performance and avoids GL context issues. - webview_->SetSkipPixelReadback(true); - debugLog("CustomPlatformView: using GL texture (hardware accelerated)"); - } else { - texture_ = FL_TEXTURE(inappwebview_texture_new(webview_.get())); - debugLog("CustomPlatformView: using pixel buffer texture (software)"); - } - - if (texture_ == nullptr) { - errorLog("CustomPlatformView: failed to create texture"); - return; - } - - // Register the texture - this assigns the texture ID - gboolean registered = fl_texture_registrar_register_texture(texture_registrar_, texture_); - if (!registered) { - errorLog("CustomPlatformView: failed to register texture"); - g_object_unref(texture_); - texture_ = nullptr; - return; - } - - // Now get the texture ID after registration - texture_id_ = fl_texture_get_id(texture_); - - // Attach the webview method channel using the same id used on Dart side. - // Dart uses the returned id from createInAppWebView as both textureId and - // controller/view id. - if (webview_ != nullptr) { - webview_->AttachChannel(messenger, texture_id_); - } - - // Set up the webview's callback to mark frame available - // For EGL texture, we also update the EGL image reference - webview_->SetOnFrameAvailable([this]() { - // If using EGL texture, update the EGL image reference before marking available - if (egl_texture_ != nullptr && webview_ != nullptr) { - uint32_t width = 0; - uint32_t height = 0; - void* egl_image = webview_->GetCurrentEglImage(&width, &height); - if (egl_image != nullptr) { - inappwebview_egl_texture_set_egl_image(egl_texture_, egl_image, width, height); - } - } - MarkTextureFrameAvailable(); - }); - - // Set up cursor change callback - webview_->SetOnCursorChanged( - [this](const std::string& cursor_name) { EmitCursorChanged(cursor_name); }); - - // Create method channel for platform view operations - std::string method_channel_name = - "com.pichillilorenzo/custom_platform_view_" + std::to_string(texture_id_); - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - method_channel_ = - fl_method_channel_new(messenger, method_channel_name.c_str(), FL_METHOD_CODEC(codec)); - if (method_channel_ != nullptr) { - fl_method_channel_set_method_call_handler(method_channel_, HandleMethodCall, this, nullptr); - } - - // Create event channel for cursor changes, etc. - std::string event_channel_name = - "com.pichillilorenzo/custom_platform_view_" + std::to_string(texture_id_) + "_events"; - g_autoptr(FlStandardMethodCodec) event_codec = fl_standard_method_codec_new(); - event_channel_ = - fl_event_channel_new(messenger, event_channel_name.c_str(), FL_METHOD_CODEC(event_codec)); - if (event_channel_ != nullptr) { - fl_event_channel_set_stream_handlers(event_channel_, OnListen, OnCancel, this, nullptr); - } -} - -CustomPlatformView::~CustomPlatformView() { - debugLog("dealloc CustomPlatformView"); - - if (method_channel_ != nullptr) { - fl_method_channel_set_method_call_handler(method_channel_, nullptr, nullptr, nullptr); - g_object_unref(method_channel_); - method_channel_ = nullptr; - } - - if (event_channel_ != nullptr) { - fl_event_channel_set_stream_handlers(event_channel_, nullptr, nullptr, nullptr, nullptr); - g_object_unref(event_channel_); - event_channel_ = nullptr; - } - - if (texture_registrar_ != nullptr && texture_ != nullptr) { - fl_texture_registrar_unregister_texture(texture_registrar_, texture_); - } - - if (texture_ != nullptr) { - g_object_unref(texture_); - texture_ = nullptr; - } -} - -void CustomPlatformView::MarkTextureFrameAvailable() { - if (texture_registrar_ != nullptr && texture_ != nullptr) { - fl_texture_registrar_mark_texture_frame_available(texture_registrar_, texture_); - } -} - -void CustomPlatformView::HandleMethodCall(FlMethodChannel* channel, FlMethodCall* method_call, - gpointer user_data) { - auto* self = static_cast(user_data); - self->HandleMethodCallImpl(method_call); -} - -void CustomPlatformView::HandleMethodCallImpl(FlMethodCall* method_call) { - const gchar* method = fl_method_call_get_name(method_call); - FlValue* args = fl_method_call_get_args(method_call); - - // setSize: [double width, double height, double scaleFactor] - if (strcmp(method, "setSize") == 0) { - if (fl_value_get_type(args) == FL_VALUE_TYPE_LIST && fl_value_get_length(args) >= 2) { - FlValue* width_value = fl_value_get_list_value(args, 0); - FlValue* height_value = fl_value_get_list_value(args, 1); - double width = 0, height = 0; - double scale_factor = 1.0; - - if (fl_value_get_type(width_value) == FL_VALUE_TYPE_FLOAT) { - width = fl_value_get_float(width_value); - } else if (fl_value_get_type(width_value) == FL_VALUE_TYPE_INT) { - width = static_cast(fl_value_get_int(width_value)); - } - - if (fl_value_get_type(height_value) == FL_VALUE_TYPE_FLOAT) { - height = fl_value_get_float(height_value); - } else if (fl_value_get_type(height_value) == FL_VALUE_TYPE_INT) { - height = static_cast(fl_value_get_int(height_value)); - } - - if (webview_ && width > 0 && height > 0) { - if (fl_value_get_length(args) >= 3) { - FlValue* scale_value = fl_value_get_list_value(args, 2); - if (scale_value != nullptr) { - if (fl_value_get_type(scale_value) == FL_VALUE_TYPE_FLOAT) { - scale_factor = fl_value_get_float(scale_value); - } else if (fl_value_get_type(scale_value) == FL_VALUE_TYPE_INT) { - scale_factor = static_cast(fl_value_get_int(scale_value)); - } - } - } - webview_->setScaleFactor(scale_factor); - // IMPORTANT: GTK/WebKit may already apply the monitor scale factor to - // offscreen rendering. Passing physical pixels here can double-scale - // the snapshot size. Keep the widget size in logical pixels and use - // scaleFactor only for input coordinate conversion. - webview_->setSize(static_cast(width), static_cast(height)); - } - } - fl_method_call_respond_success(method_call, nullptr, nullptr); - return; - } - - // setTextureOffset: [double x, double y] - if (strcmp(method, "setTextureOffset") == 0) { - if (fl_value_get_type(args) == FL_VALUE_TYPE_LIST && fl_value_get_length(args) >= 2) { - FlValue* x_value = fl_value_get_list_value(args, 0); - FlValue* y_value = fl_value_get_list_value(args, 1); - double x = 0, y = 0; - - if (fl_value_get_type(x_value) == FL_VALUE_TYPE_FLOAT) { - x = fl_value_get_float(x_value); - } else if (fl_value_get_type(x_value) == FL_VALUE_TYPE_INT) { - x = static_cast(fl_value_get_int(x_value)); - } - - if (fl_value_get_type(y_value) == FL_VALUE_TYPE_FLOAT) { - y = fl_value_get_float(y_value); - } else if (fl_value_get_type(y_value) == FL_VALUE_TYPE_INT) { - y = static_cast(fl_value_get_int(y_value)); - } - - if (webview_) { - webview_->SetTextureOffset(x, y); - } - } - fl_method_call_respond_success(method_call, nullptr, nullptr); - return; - } - - // setCursorPos: [double x, double y] - if (strcmp(method, "setCursorPos") == 0) { - if (fl_value_get_type(args) == FL_VALUE_TYPE_LIST && fl_value_get_length(args) >= 2) { - FlValue* x_value = fl_value_get_list_value(args, 0); - FlValue* y_value = fl_value_get_list_value(args, 1); - double x = 0, y = 0; - - if (fl_value_get_type(x_value) == FL_VALUE_TYPE_FLOAT) { - x = fl_value_get_float(x_value); - } else if (fl_value_get_type(x_value) == FL_VALUE_TYPE_INT) { - x = static_cast(fl_value_get_int(x_value)); - } - - if (fl_value_get_type(y_value) == FL_VALUE_TYPE_FLOAT) { - y = fl_value_get_float(y_value); - } else if (fl_value_get_type(y_value) == FL_VALUE_TYPE_INT) { - y = static_cast(fl_value_get_int(y_value)); - } - - if (webview_) { - webview_->SetCursorPos(x, y); - } - } - fl_method_call_respond_success(method_call, nullptr, nullptr); - return; - } - - // setPointerButton: {"kind": int, "button": int, "clickCount": int} - if (strcmp(method, "setPointerButton") == 0) { - if (fl_value_get_type(args) == FL_VALUE_TYPE_MAP) { - FlValue* kind_value = fl_value_lookup_string(args, "kind"); - FlValue* button_value = fl_value_lookup_string(args, "button"); - FlValue* click_count_value = fl_value_lookup_string(args, "clickCount"); - - if (kind_value != nullptr && button_value != nullptr) { - int kind = 0, button = 0, clickCount = 1; - - if (fl_value_get_type(kind_value) == FL_VALUE_TYPE_INT) { - kind = static_cast(fl_value_get_int(kind_value)); - } - if (fl_value_get_type(button_value) == FL_VALUE_TYPE_INT) { - button = static_cast(fl_value_get_int(button_value)); - } - if (click_count_value != nullptr && - fl_value_get_type(click_count_value) == FL_VALUE_TYPE_INT) { - clickCount = static_cast(fl_value_get_int(click_count_value)); - } - - if (webview_) { - webview_->SetPointerButton(kind, button, clickCount); - } - } - } - fl_method_call_respond_success(method_call, nullptr, nullptr); - return; - } - - // setScrollDelta: [double dx, double dy] - if (strcmp(method, "setScrollDelta") == 0) { - if (fl_value_get_type(args) == FL_VALUE_TYPE_LIST && fl_value_get_length(args) >= 2) { - FlValue* dx_value = fl_value_get_list_value(args, 0); - FlValue* dy_value = fl_value_get_list_value(args, 1); - double dx = 0, dy = 0; - - if (fl_value_get_type(dx_value) == FL_VALUE_TYPE_FLOAT) { - dx = fl_value_get_float(dx_value); - } else if (fl_value_get_type(dx_value) == FL_VALUE_TYPE_INT) { - dx = static_cast(fl_value_get_int(dx_value)); - } - - if (fl_value_get_type(dy_value) == FL_VALUE_TYPE_FLOAT) { - dy = fl_value_get_float(dy_value); - } else if (fl_value_get_type(dy_value) == FL_VALUE_TYPE_INT) { - dy = static_cast(fl_value_get_int(dy_value)); - } - - if (webview_) { - webview_->SetScrollDelta(dx, dy); - } - } - fl_method_call_respond_success(method_call, nullptr, nullptr); - return; - } - - // sendKeyEvent: {"type": int, "keyCode": int64, "scanCode": int, "modifiers": int, "characters": - // string} - if (strcmp(method, "sendKeyEvent") == 0) { - if (fl_value_get_type(args) == FL_VALUE_TYPE_MAP) { - FlValue* type_value = fl_value_lookup_string(args, "type"); - FlValue* keyCode_value = fl_value_lookup_string(args, "keyCode"); - FlValue* scanCode_value = fl_value_lookup_string(args, "scanCode"); - FlValue* modifiers_value = fl_value_lookup_string(args, "modifiers"); - FlValue* characters_value = fl_value_lookup_string(args, "characters"); - - int type = 0, scanCode = 0, modifiers = 0; - int64_t keyCode = 0; - std::string characters; - - if (type_value != nullptr && fl_value_get_type(type_value) == FL_VALUE_TYPE_INT) { - type = static_cast(fl_value_get_int(type_value)); - } - if (keyCode_value != nullptr && fl_value_get_type(keyCode_value) == FL_VALUE_TYPE_INT) { - keyCode = fl_value_get_int(keyCode_value); - } - if (scanCode_value != nullptr && fl_value_get_type(scanCode_value) == FL_VALUE_TYPE_INT) { - scanCode = static_cast(fl_value_get_int(scanCode_value)); - } - if (modifiers_value != nullptr && fl_value_get_type(modifiers_value) == FL_VALUE_TYPE_INT) { - modifiers = static_cast(fl_value_get_int(modifiers_value)); - } - if (characters_value != nullptr && - fl_value_get_type(characters_value) == FL_VALUE_TYPE_STRING) { - characters = fl_value_get_string(characters_value); - } - - if (webview_) { - webview_->SendKeyEvent(type, keyCode, scanCode, modifiers, characters); - } - } - fl_method_call_respond_success(method_call, nullptr, nullptr); - return; - } - - // sendTouchEvent: {"type": int, "id": int, "x": double, "y": double, "touchPoints": list} - if (strcmp(method, "sendTouchEvent") == 0) { - if (fl_value_get_type(args) == FL_VALUE_TYPE_MAP) { - FlValue* type_value = fl_value_lookup_string(args, "type"); - FlValue* id_value = fl_value_lookup_string(args, "id"); - FlValue* x_value = fl_value_lookup_string(args, "x"); - FlValue* y_value = fl_value_lookup_string(args, "y"); - FlValue* touchPoints_value = fl_value_lookup_string(args, "touchPoints"); - - int type = 0, id = 0; - double x = 0, y = 0; - std::vector> touchPoints; - - if (type_value != nullptr && fl_value_get_type(type_value) == FL_VALUE_TYPE_INT) { - type = static_cast(fl_value_get_int(type_value)); - } - if (id_value != nullptr && fl_value_get_type(id_value) == FL_VALUE_TYPE_INT) { - id = static_cast(fl_value_get_int(id_value)); - } - if (x_value != nullptr && fl_value_get_type(x_value) == FL_VALUE_TYPE_FLOAT) { - x = fl_value_get_float(x_value); - } - if (y_value != nullptr && fl_value_get_type(y_value) == FL_VALUE_TYPE_FLOAT) { - y = fl_value_get_float(y_value); - } - - // Parse touch points list - if (touchPoints_value != nullptr && - fl_value_get_type(touchPoints_value) == FL_VALUE_TYPE_LIST) { - size_t len = fl_value_get_length(touchPoints_value); - for (size_t i = 0; i < len; i++) { - FlValue* point = fl_value_get_list_value(touchPoints_value, i); - if (fl_value_get_type(point) == FL_VALUE_TYPE_MAP) { - int point_id = 0, point_type = 0; - double point_x = 0, point_y = 0; - - FlValue* pid = fl_value_lookup_string(point, "id"); - FlValue* px = fl_value_lookup_string(point, "x"); - FlValue* py = fl_value_lookup_string(point, "y"); - FlValue* ptype = fl_value_lookup_string(point, "type"); - - if (pid && fl_value_get_type(pid) == FL_VALUE_TYPE_INT) { - point_id = static_cast(fl_value_get_int(pid)); - } - if (px && fl_value_get_type(px) == FL_VALUE_TYPE_FLOAT) { - point_x = fl_value_get_float(px); - } - if (py && fl_value_get_type(py) == FL_VALUE_TYPE_FLOAT) { - point_y = fl_value_get_float(py); - } - if (ptype && fl_value_get_type(ptype) == FL_VALUE_TYPE_INT) { - point_type = static_cast(fl_value_get_int(ptype)); - } - - touchPoints.emplace_back(point_id, point_x, point_y, point_type); - } - } - } - - if (webview_) { - webview_->SendTouchEvent(type, id, x, y, touchPoints); - } - } - fl_method_call_respond_success(method_call, nullptr, nullptr); - return; - } - - // setFocused: bool focused - if (strcmp(method, "setFocused") == 0) { - bool focused = false; - if (fl_value_get_type(args) == FL_VALUE_TYPE_BOOL) { - focused = fl_value_get_bool(args); - } else if (fl_value_get_type(args) == FL_VALUE_TYPE_INT) { - focused = fl_value_get_int(args) != 0; - } - - if (webview_) { - webview_->setFocused(focused); - } - fl_method_call_respond_success(method_call, nullptr, nullptr); - return; - } - - // setVisible: bool visible - if (strcmp(method, "setVisible") == 0) { - bool visible = true; - if (fl_value_get_type(args) == FL_VALUE_TYPE_BOOL) { - visible = fl_value_get_bool(args); - } else if (fl_value_get_type(args) == FL_VALUE_TYPE_INT) { - visible = fl_value_get_int(args) != 0; - } - - if (webview_) { - webview_->setVisible(visible); - } - fl_method_call_respond_success(method_call, nullptr, nullptr); - return; - } - - // getActivityState: returns uint32 - if (strcmp(method, "getActivityState") == 0) { - uint32_t state = 0; - if (webview_) { - state = webview_->getActivityState(); - } - g_autoptr(FlValue) result = fl_value_new_int(static_cast(state)); - fl_method_call_respond_success(method_call, result, nullptr); - return; - } - - // setTargetRefreshRate: int rate - if (strcmp(method, "setTargetRefreshRate") == 0) { - uint32_t rate = 0; - if (fl_value_get_type(args) == FL_VALUE_TYPE_INT) { - rate = static_cast(fl_value_get_int(args)); - } - - if (webview_) { - webview_->setTargetRefreshRate(rate); - } - fl_method_call_respond_success(method_call, nullptr, nullptr); - return; - } - - // getTargetRefreshRate: returns uint32 - if (strcmp(method, "getTargetRefreshRate") == 0) { - uint32_t rate = 0; - if (webview_) { - rate = webview_->getTargetRefreshRate(); - } - g_autoptr(FlValue) result = fl_value_new_int(static_cast(rate)); - fl_method_call_respond_success(method_call, result, nullptr); - return; - } - - // requestEnterFullscreen - if (strcmp(method, "requestEnterFullscreen") == 0) { - if (webview_) { - webview_->requestEnterFullscreen(); - } - fl_method_call_respond_success(method_call, nullptr, nullptr); - return; - } - - // requestExitFullscreen - if (strcmp(method, "requestExitFullscreen") == 0) { - if (webview_) { - webview_->requestExitFullscreen(); - } - fl_method_call_respond_success(method_call, nullptr, nullptr); - return; - } - - // isInFullscreen: returns bool - if (strcmp(method, "isInFullscreen") == 0) { - bool fullscreen = false; - if (webview_) { - fullscreen = webview_->isInFullscreen(); - } - g_autoptr(FlValue) result = fl_value_new_bool(fullscreen); - fl_method_call_respond_success(method_call, result, nullptr); - return; - } - - // requestPointerLock: returns bool - if (strcmp(method, "requestPointerLock") == 0) { - bool success = false; - if (webview_) { - success = webview_->requestPointerLock(); - } - g_autoptr(FlValue) result = fl_value_new_bool(success); - fl_method_call_respond_success(method_call, result, nullptr); - return; - } - - // requestPointerUnlock: returns bool - if (strcmp(method, "requestPointerUnlock") == 0) { - bool success = false; - if (webview_) { - success = webview_->requestPointerUnlock(); - } - g_autoptr(FlValue) result = fl_value_new_bool(success); - fl_method_call_respond_success(method_call, result, nullptr); - return; - } - - fl_method_call_respond_not_implemented(method_call, nullptr); -} - -FlMethodErrorResponse* CustomPlatformView::OnListen(FlEventChannel* channel, FlValue* args, - gpointer user_data) { - auto* self = static_cast(user_data); - self->event_sink_active_ = true; - return nullptr; -} - -FlMethodErrorResponse* CustomPlatformView::OnCancel(FlEventChannel* channel, FlValue* args, - gpointer user_data) { - auto* self = static_cast(user_data); - self->event_sink_active_ = false; - return nullptr; -} - -void CustomPlatformView::EmitCursorChanged(const std::string& cursor_name) { - if (!event_sink_active_ || event_channel_ == nullptr) { - return; - } - - g_autoptr(FlValue) event = to_fl_map({ - {"type", make_fl_value(std::string("cursorChanged"))}, - {"value", make_fl_value(cursor_name)}, - }); - - fl_event_channel_send(event_channel_, event, nullptr, nullptr); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/in_app_webview/custom_platform_view.h b/flutter_inappwebview_linux/linux/in_app_webview/custom_platform_view.h deleted file mode 100644 index 576f916ef5..0000000000 --- a/flutter_inappwebview_linux/linux/in_app_webview/custom_platform_view.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CUSTOM_PLATFORM_VIEW_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_CUSTOM_PLATFORM_VIEW_H_ - -#include - -#include -#include - -#include "in_app_webview.h" -#include "inappwebview_egl_texture.h" - -namespace flutter_inappwebview_plugin { - -using WebViewType = InAppWebView; - -/// CustomPlatformView handles the method channel communication for -/// pointer/mouse events, sizing, and other platform view operations. -/// This is similar to the Windows implementation. -class CustomPlatformView { - public: - CustomPlatformView(FlBinaryMessenger* messenger, FlTextureRegistrar* texture_registrar, - std::shared_ptr webview); - ~CustomPlatformView(); - - int64_t texture_id() const { return texture_id_; } - WebViewType* webview() const { return webview_.get(); } - - // Keep-alive ID management - // When set, this WebView should be preserved when disposed and stored in keepAliveWebViews_ - void set_keep_alive_id(const std::string& id) { keepAliveId_ = id; } - const std::string& keep_alive_id() const { return keepAliveId_; } - bool has_keep_alive_id() const { return !keepAliveId_.empty(); } - - void MarkTextureFrameAvailable(); - - private: - std::shared_ptr webview_; - FlTextureRegistrar* texture_registrar_; - FlTexture* texture_ = nullptr; - InAppWebViewEGLTexture* egl_texture_ = nullptr; // Pointer to EGL texture if using zero-copy mode - int64_t texture_id_ = -1; - std::string keepAliveId_; // Keep-alive ID for preserving WebView across widget disposal - - FlMethodChannel* method_channel_ = nullptr; - FlEventChannel* event_channel_ = nullptr; - bool event_sink_active_ = false; - - // Method call handler - static void HandleMethodCall(FlMethodChannel* channel, FlMethodCall* method_call, - gpointer user_data); - void HandleMethodCallImpl(FlMethodCall* method_call); - - // Event channel handlers - static FlMethodErrorResponse* OnListen(FlEventChannel* channel, FlValue* args, - gpointer user_data); - static FlMethodErrorResponse* OnCancel(FlEventChannel* channel, FlValue* args, - gpointer user_data); - - void EmitCursorChanged(const std::string& cursor_name); -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_CUSTOM_PLATFORM_VIEW_H_ diff --git a/flutter_inappwebview_linux/linux/in_app_webview/in_app_webview.cc b/flutter_inappwebview_linux/linux/in_app_webview/in_app_webview.cc deleted file mode 100644 index 95b3c80696..0000000000 --- a/flutter_inappwebview_linux/linux/in_app_webview/in_app_webview.cc +++ /dev/null @@ -1,8001 +0,0 @@ -// WPE WebKit-based InAppWebView implementation -// -// This file provides offscreen web rendering using WPE WebKit. -// Supports two backend APIs: -// - WPEPlatform (HAVE_WPE_PLATFORM): New modern API for WPE WebKit 2.40+ -// - WPEBackend-FDO (HAVE_WPE_BACKEND_LEGACY): Legacy API for older systems - -#include "in_app_webview.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Use epoxy for OpenGL/EGL instead of direct headers to avoid conflicts -#include -#include - -// WPEPlatform API (new modern API) -#ifdef HAVE_WPE_PLATFORM -#include -#include -#include // For SHM software rendering fallback -#endif - -// WPEBackend-FDO API (legacy) -#ifdef HAVE_WPE_BACKEND_LEGACY -#include -#include -#include -#endif - -// Cairo for PNG encoding (used by takeScreenshot) -#include - -#include "../plugin_scripts_js/color_input_js.h" -#include "../plugin_scripts_js/console_log_js.h" -#include "../plugin_scripts_js/cursor_detection_js.h" -#include "../plugin_scripts_js/date_input_js.h" -#include "../plugin_scripts_js/intercept_ajax_request_js.h" -#include "../plugin_scripts_js/intercept_fetch_request_js.h" -#include "../plugin_scripts_js/javascript_bridge_js.h" -#include "../plugin_scripts_js/on_load_resource_js.h" -#include "../plugin_scripts_js/print_interception_js.h" -#include "../plugin_scripts_js/web_message_channel_js.h" -#include "../plugin_scripts_js/web_message_listener_js.h" -#include "../types/client_cert_challenge.h" -#include "../types/client_cert_response.h" -#include "../types/create_window_action.h" -#include "../types/custom_scheme_response.h" -#include "../types/hit_test_result.h" -#include "../types/navigation_action.h" -#include "../types/server_trust_challenge.h" -#include "../types/web_resource_error.h" -#include "../types/web_resource_request.h" -#include "../types/web_view_transport.h" -#include "../credential_database.h" -#include "../flutter_inappwebview_linux_plugin_private.h" -#include "../plugin_instance.h" -#include "../utils/flutter.h" -#include "../utils/gl_context.h" -#include "../utils/log.h" -#include "../utils/uri.h" -#include "in_app_webview_manager.h" -#include "simd_convert.h" -#include "user_content_controller.h" -#include "webview_channel_delegate.h" -#include "../types/find_session.h" -#include "../web_message/web_message_channel.h" -#include "../web_message/web_message_listener.h" - -using json = nlohmann::json; - -// Forward declaration of InAppWebView for FileChooserContext -namespace flutter_inappwebview_plugin { -class InAppWebView; -} - -// Context data for non-blocking file chooser dialog -// Defined early because HideFileChooser() needs access to members -struct FileChooserContext { - WebKitFileChooserRequest* request; - bool selectMultiple; - flutter_inappwebview_plugin::InAppWebView* webview; // Pointer to webview for tracking active dialog - gulong response_handler_id; // Signal handler ID for cleanup - - FileChooserContext(WebKitFileChooserRequest* req, bool multi, - flutter_inappwebview_plugin::InAppWebView* wv) - : request(req), selectMultiple(multi), webview(wv), response_handler_id(0) { - g_object_ref(request); - } - - ~FileChooserContext() { - g_object_unref(request); - } -}; - -// GDK for EGL display access -#include -#ifdef GDK_WINDOWING_WAYLAND -#include -#endif -#ifdef GDK_WINDOWING_X11 -#include -#endif - -// C-style callback functions outside the namespace for C API compatibility -#ifdef HAVE_WPE_BACKEND_LEGACY -extern "C" { -static void wpe_export_fdo_egl_image_callback(void* data, struct wpe_fdo_egl_exported_image* image); - -static void wpe_export_shm_buffer_callback(void* data, struct wpe_fdo_shm_exported_buffer* buffer); -} -#endif - -namespace flutter_inappwebview_plugin { - -namespace { - -// WPE modifier mask - matches wpe_input_modifier enum from wpe/input.h -// Control = bit 0 (1), Shift = bit 1 (2), Alt = bit 2 (4), Meta = bit 3 (8) -// These are not used directly in C++ code - modifiers come from Dart already in WPE format - -// Generate a random hex string for the JS bridge secret -std::string GenerateRandomSecret(size_t length = 32) { - static const char* hex_chars = "0123456789abcdef"; - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<> dis(0, 15); - - std::string result; - result.reserve(length); - for (size_t i = 0; i < length; ++i) { - result += hex_chars[dis(gen)]; - } - return result; -} - -} // namespace - -#ifdef HAVE_WPE_BACKEND_LEGACY -// Get the directory where the executable is located (only needed for legacy backend) -static std::string GetExecutableDir() { - char path[PATH_MAX]; - ssize_t len = readlink("/proc/self/exe", path, sizeof(path) - 1); - if (len != -1) { - path[len] = '\0'; - std::string exe_path(path); - size_t last_slash = exe_path.rfind('/'); - if (last_slash != std::string::npos) { - return exe_path.substr(0, last_slash); - } - } - return ""; -} -#endif - -bool InAppWebView::IsWpeWebKitAvailable() { - static bool checked = false; - static bool available = false; - - if (checked) { - return available; - } - checked = true; - -#ifdef HAVE_WPE_PLATFORM - // WPEPlatform API: No loader initialization needed - // The platform is initialized when we create a WPEDisplay - debugLog("InAppWebView: Using WPEPlatform API (modern)"); - available = true; -#elif defined(HAVE_WPE_BACKEND_LEGACY) - // Legacy WPEBackend-FDO: Need to initialize the loader - // Try to load the WPE backend library - // First, try to load from the bundled lib/ directory using the full path. - std::string exe_dir = GetExecutableDir(); - if (!exe_dir.empty()) { - std::string bundled_lib_path = exe_dir + "/lib/libWPEBackend-fdo-1.0.so.1"; - std::string bundled_lib_dir = exe_dir + "/lib"; - - // Check if the bundled library exists - if (access(bundled_lib_path.c_str(), F_OK) == 0) { - // Set environment variables for the WPE WebProcess child process. - setenv("WPE_BACKEND_LIBRARY", bundled_lib_path.c_str(), 0); - - // Also prepend the lib directory to LD_LIBRARY_PATH - const char* current_ld_path = getenv("LD_LIBRARY_PATH"); - std::string new_ld_path = bundled_lib_dir; - if (current_ld_path != nullptr && strlen(current_ld_path) > 0) { - new_ld_path += ":"; - new_ld_path += current_ld_path; - } - setenv("LD_LIBRARY_PATH", new_ld_path.c_str(), 1); - - available = wpe_loader_init(bundled_lib_path.c_str()) != 0; - } - } - - // Fall back to system library if bundled version not found or failed to load - if (!available) { - available = wpe_loader_init("libWPEBackend-fdo-1.0.so.1") != 0; - } - - if (available) { - debugLog("InAppWebView: Using WPEBackend-FDO API (legacy)"); - } -#else - #error "Neither HAVE_WPE_PLATFORM nor HAVE_WPE_BACKEND_LEGACY is defined" -#endif - - return available; -} - -#ifdef HAVE_WPE_PLATFORM -// Check if DMA-BUF rendering should be used (called at WebView initialization) -// Returns true if DMA-BUF rendering is expected to work -// Note: The actual environment detection and LIBGL_ALWAYS_SOFTWARE setting -// is now done at plugin registration time via utils/software_rendering.h -bool InAppWebView::PreflightDmaBufSupport() { - const char* sw_env = getenv("LIBGL_ALWAYS_SOFTWARE"); - if (sw_env && (strcmp(sw_env, "1") == 0 || strcasecmp(sw_env, "true") == 0)) { - return false; // Software rendering mode - } - return true; // Hardware rendering mode -} -#endif - -InAppWebView::InAppWebView(FlPluginRegistrar* registrar, FlBinaryMessenger* messenger, int64_t id, - const InAppWebViewCreationParams& params) - : plugin_(params.plugin), registrar_(registrar), messenger_(messenger), gtk_window_(params.gtkWindow), fl_view_(params.flView), manager_(params.manager), id_(id), settings_(params.initialSettings), - initial_user_scripts_(params.initialUserScripts) { - js_bridge_secret_ = GenerateRandomSecret(); - - if (params.windowId.has_value()) { - window_id_ = params.windowId.value(); - } - - if (params.contextMenu.has_value()) { - context_menu_config_ = params.contextMenu.value(); - } - - InitWpeBackend(); - InitWebView(params); - RegisterEventHandlers(); - - // Set up monitor change handlers and initial refresh rate (like Cog browser does) - // This helps WPE synchronize frame production with the display - SetupMonitorChangeHandlers(); - UpdateMonitorRefreshRate(); - - if (settings_) { - settings_->applyToWebView(webview_); -#ifdef HAVE_WPE_PLATFORM - if (wpe_display_ != nullptr) { - settings_->applyWpePlatformSettings(wpe_display_); - } -#endif - } - - RegisterCustomSchemes(); - - // Apply content blockers if specified, then load initial content - // Content blockers must be compiled asynchronously - if (settings_ && settings_->contentBlockers != nullptr && content_blocker_handler_) { - // Store initial load params for callback - auto initialUrlRequest = params.initialUrlRequest; - auto initialData = params.initialData; - auto initialDataMimeType = params.initialDataMimeType; - auto initialDataEncoding = params.initialDataEncoding; - auto initialDataBaseUrl = params.initialDataBaseUrl; - auto initialFile = params.initialFile; - - content_blocker_handler_->setContentBlockers( - settings_->contentBlockers, - [this, initialUrlRequest, initialData, initialDataMimeType, initialDataEncoding, - initialDataBaseUrl, initialFile](bool success) { - if (!success) { - debugLog("InAppWebView: Content blockers failed to apply, loading content anyway"); - } - - // Now load initial content - if (initialUrlRequest.has_value()) { - loadUrl(initialUrlRequest.value()); - } else if (initialData.has_value()) { - std::string mimeType = initialDataMimeType.value_or("text/html"); - std::string encoding = initialDataEncoding.value_or("UTF-8"); - std::string baseUrl = initialDataBaseUrl.value_or("about:blank"); - loadData(initialData.value(), mimeType, encoding, baseUrl); - } else if (initialFile.has_value()) { - loadFile(initialFile.value()); - } - }); - } else { - // No content blockers - load initial content immediately - if (params.initialUrlRequest.has_value()) { - auto& urlRequest = params.initialUrlRequest.value(); - loadUrl(urlRequest); - } else if (params.initialData.has_value()) { - std::string mimeType = params.initialDataMimeType.value_or("text/html"); - std::string encoding = params.initialDataEncoding.value_or("UTF-8"); - std::string baseUrl = params.initialDataBaseUrl.value_or("about:blank"); - loadData(params.initialData.value(), mimeType, encoding, baseUrl); - } else if (params.initialFile.has_value()) { - loadFile(params.initialFile.value()); - } - } -} - -void InAppWebView::AttachChannel(FlBinaryMessenger* messenger, int64_t channel_id) { - channel_id_ = channel_id; - if (messenger == nullptr) { - errorLog("InAppWebView: AttachChannel messenger is null"); - return; - } - - std::string channelName = std::string(METHOD_CHANNEL_NAME_PREFIX) + std::to_string(channel_id_); - channel_delegate_ = std::make_unique(this, messenger, channelName); - - if (findInteractionController_) { - findInteractionController_->attachChannel(messenger, std::to_string(channel_id_)); - } -} - -void InAppWebView::AttachChannel(FlBinaryMessenger* messenger, const std::string& channel_id, const bool is_full_channel_name) { - string_channel_id_ = channel_id; - if (messenger == nullptr) { - errorLog("InAppWebView: AttachChannel messenger is null"); - return; - } - - // Determine the channel name: - // - If is_full_channel_name (InAppBrowser case), use it directly - // - If channel_id is just an ID (HeadlessInAppWebView case), prepend the prefix - std::string channelName; - if (is_full_channel_name) { - // Already has the prefix (InAppBrowser passes full channel name) - channelName = channel_id; - } else { - // Just an ID, prepend the prefix (HeadlessInAppWebView case) - channelName = std::string(METHOD_CHANNEL_NAME_PREFIX) + channel_id; - } - channel_delegate_ = std::make_unique(this, messenger, channelName); - - if (findInteractionController_) { - findInteractionController_->attachChannel(messenger, channel_id); - } -} - -InAppWebView::~InAppWebView() { - debugLog("dealloc InAppWebView"); - - CleanupMonitorChangeHandlers(); - - context_menu_popup_.reset(); - - if (findInteractionController_) { - findInteractionController_->dispose(); - findInteractionController_.reset(); - } - - if (pending_context_menu_ != nullptr) { - g_object_unref(pending_context_menu_); - pending_context_menu_ = nullptr; - } - if (pending_hit_test_result_ != nullptr) { - g_object_unref(pending_hit_test_result_); - pending_hit_test_result_ = nullptr; - } - - if (last_hit_test_result_ != nullptr) { - g_object_unref(last_hit_test_result_); - last_hit_test_result_ = nullptr; - } - - // Disconnect download-started signal from NetworkSession before destroying webview - if (webview_ != nullptr && download_started_handler_id_ != 0) { - WebKitNetworkSession* network_session = webkit_web_view_get_network_session(webview_); - if (network_session != nullptr) { - g_signal_handler_disconnect(network_session, download_started_handler_id_); - } - download_started_handler_id_ = 0; - } - - for (auto& pair : web_message_channels_) { - if (pair.second) { - pair.second->dispose(); - } - } - web_message_channels_.clear(); - - for (auto& pair : web_message_listeners_) { - if (pair.second) { - pair.second->dispose(); - } - } - web_message_listeners_.clear(); - - // IMPORTANT: Clean up user content controller FIRST while webview is still valid - // The UserContentController destructor needs access to WebKit's user content manager - // which becomes invalid after we unref the webview - user_content_controller_.reset(); - - // IMPORTANT: Clean up content blocker handler BEFORE the webview is destroyed - // The ContentBlockerHandler destructor calls removeAllFilters which needs a valid content manager - content_blocker_handler_.reset(); - - for (auto& pair : pending_policy_decisions_) { - webkit_policy_decision_ignore(pair.second); - g_object_unref(pair.second); - } - pending_policy_decisions_.clear(); - -#ifdef HAVE_WPE_PLATFORM - // === WPEPlatform proper shutdown sequence === - // Mark as disposing to prevent buffer callbacks from processing - is_disposing_.store(true); - - // 1. First disconnect signals to stop receiving callbacks - if (wpe_view_ != nullptr && buffer_rendered_handler_ != 0) { - g_signal_handler_disconnect(wpe_view_, buffer_rendered_handler_); - buffer_rendered_handler_ = 0; - } - // Note: scale_changed_handler_ is connected to gtk_window_, not wpe_view_ - if (gtk_window_ != nullptr && scale_changed_handler_ != 0) { - g_signal_handler_disconnect(gtk_window_, scale_changed_handler_); - scale_changed_handler_ = 0; - } - - if (wpe_view_ != nullptr) { - wpe_view_focus_out(wpe_view_); - } - - if (wpe_view_ != nullptr) { - wpe_view_unmap(wpe_view_); - } - - // 4. Release any pending buffer back to WPE and clean up EGL image - { - std::lock_guard lock(wpe_buffer_mutex_); - - // Clean up EGL image first (while display is still valid) - if (current_egl_image_ != nullptr && egl_display_ != nullptr) { - static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr; - if (eglDestroyImageKHR == nullptr) { - eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR"); - } - if (eglDestroyImageKHR != nullptr) { - eglDestroyImageKHR(static_cast(egl_display_), - static_cast(current_egl_image_)); - } - current_egl_image_ = nullptr; - } - - // Release pending buffer back to WPE - if (current_buffer_ != nullptr && wpe_view_ != nullptr) { - wpe_view_buffer_released(wpe_view_, current_buffer_); - } - current_buffer_ = nullptr; - current_buffer_width_ = 0; - current_buffer_height_ = 0; - } - - if (wpe_view_ != nullptr) { - wpe_view_closed(wpe_view_); - } - - wpe_view_ = nullptr; - wpe_toplevel_ = nullptr; - - if (webview_ != nullptr) { - g_object_unref(webview_); - webview_ = nullptr; - } - - if (wpe_display_ != nullptr) { - g_object_unref(wpe_display_); - wpe_display_ = nullptr; - } - - egl_display_ = nullptr; -#elif defined(HAVE_WPE_BACKEND_LEGACY) - { - std::lock_guard lock(exported_image_mutex_); - if (exported_image_ != nullptr && exportable_ != nullptr) { - ::wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image(exportable_, - exported_image_); - exported_image_ = nullptr; - } - } - - if (webview_ != nullptr) { - g_object_unref(webview_); - webview_ = nullptr; - } -#endif -} - -void InAppWebView::InitWpeBackend() { - if (!IsWpeWebKitAvailable()) { - errorLog("InAppWebView: WPE WebKit not available"); - return; - } - -#ifdef HAVE_WPE_PLATFORM - // === WPEPlatform API (Modern) === - - // NOTE: The DMA-BUF preflight check and LIBGL_ALWAYS_SOFTWARE setup - // is now done at plugin registration time via RunEarlyPreflightCheck(). - // This ensures the environment is set BEFORE any WPEDisplay is created. - - // Create a headless display for offscreen rendering - GError* error = nullptr; - - wpe_display_ = wpe_display_headless_new(); - if (wpe_display_ == nullptr) { - errorLog("InAppWebView: Failed to create WPEDisplayHeadless"); - return; - } - - // Connect the display - if (!wpe_display_connect(wpe_display_, &error)) { - errorLog("InAppWebView: Failed to connect WPEDisplay: " + - std::string(error ? error->message : "unknown")); - g_clear_error(&error); - g_clear_object(&wpe_display_); - return; - } - - // Get EGL display from WPEDisplay for texture operations - egl_display_ = wpe_display_get_egl_display(wpe_display_, &error); - if (egl_display_ == nullptr) { - // Software rendering mode - no EGL display available - g_clear_error(&error); - } - - // Note: The WebView will be created in InitWebView() using the "display" property - // WPEView and WPEToplevel are obtained from the WebView after creation - -#elif defined(HAVE_WPE_BACKEND_LEGACY) - // === WPEBackend-FDO API (Legacy) === - - // Get EGL display from GDK - EGLDisplay egl_display = EGL_NO_DISPLAY; - GdkDisplay* gdk_display = gdk_display_get_default(); - - if (gdk_display != nullptr) { -#ifdef GDK_WINDOWING_WAYLAND - if (GDK_IS_WAYLAND_DISPLAY(gdk_display)) { - struct wl_display* wl_display = gdk_wayland_display_get_wl_display(gdk_display); - if (wl_display != nullptr) { - egl_display = eglGetDisplay((EGLNativeDisplayType)wl_display); - } - } -#endif -#ifdef GDK_WINDOWING_X11 - if (egl_display == EGL_NO_DISPLAY && GDK_IS_X11_DISPLAY(gdk_display)) { - Display* x11_display = gdk_x11_display_get_xdisplay(gdk_display); - if (x11_display != nullptr) { - egl_display = eglGetDisplay((EGLNativeDisplayType)x11_display); - } - } -#endif - } - - // If we couldn't get an EGL display, try the default - if (egl_display == EGL_NO_DISPLAY) { - egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - } - - // Initialize EGL if needed - if (egl_display != EGL_NO_DISPLAY) { - EGLint major, minor; - if (!eglInitialize(egl_display, &major, &minor)) { - errorLog("InAppWebView: Failed to initialize EGL"); - egl_display = EGL_NO_DISPLAY; - } - } - - egl_display_ = egl_display; - - // Initialize WPE FDO with the EGL display - if (!wpe_fdo_initialize_for_egl_display(egl_display)) { - errorLog("InAppWebView: Failed to initialize WPE FDO"); - // Try again with headless mode - if (!wpe_fdo_initialize_for_egl_display(EGL_NO_DISPLAY)) { - errorLog("InAppWebView: Failed to initialize WPE FDO in headless mode"); - } - } - - // Create the exportable backend for DMA-BUF export - static struct wpe_view_backend_exportable_fdo_egl_client exportable_client = { - nullptr, // export_egl_image callback (legacy) - wpe_export_fdo_egl_image_callback, // export_fdo_egl_image callback - wpe_export_shm_buffer_callback, // export_shm_buffer callback - nullptr, nullptr // reserved - }; - - exportable_ = - wpe_view_backend_exportable_fdo_egl_create(&exportable_client, this, width_, height_); - - if (exportable_ == nullptr) { - errorLog("InAppWebView: Failed to create WPE exportable backend"); - return; - } - - wpe_backend_ = wpe_view_backend_exportable_fdo_get_view_backend(exportable_); - - // Create WebKit backend wrapper - backend_ = webkit_web_view_backend_new( - wpe_backend_, - [](gpointer data) { - auto* exportable = static_cast(data); - wpe_view_backend_exportable_fdo_destroy(exportable); - }, - exportable_); - - wpe_view_backend_dispatch_set_device_scale_factor(wpe_backend_, scale_factor_); - - // Set initial activity state - wpe_view_backend_add_activity_state(wpe_backend_, wpe_view_activity_state_visible); - wpe_view_backend_add_activity_state(wpe_backend_, wpe_view_activity_state_in_window); - wpe_view_backend_add_activity_state(wpe_backend_, wpe_view_activity_state_focused); - - // Set up fullscreen handler for DOM fullscreen requests - wpe_view_backend_set_fullscreen_handler( - wpe_backend_, - [](void* data, bool fullscreen) -> bool { - auto* self = static_cast(data); - return self->OnDomFullscreenRequest(fullscreen); - }, - this); - - // Set up pointer lock handler for games/immersive applications - wpe_view_backend_set_pointer_lock_handler( - wpe_backend_, - [](void* data, bool lock) -> bool { - auto* self = static_cast(data); - return self->OnPointerLockRequest(lock); - }, - this); -#endif -} - -void InAppWebView::InitWebView(const InAppWebViewCreationParams& params) { -#ifdef HAVE_WPE_PLATFORM - // === WPEPlatform API === - // With WPEPlatform, we pass the "display" property to create the WebView - // The WPEView is automatically created by WebKit - - if (wpe_display_ == nullptr) { - errorLog("InAppWebView: Cannot create webview without WPEDisplay"); - return; - } - - // Create WebKit settings - WebKitSettings* settings = webkit_settings_new(); - - bool useIncognito = params.initialSettings && params.initialSettings->incognito; - WebKitNetworkSession* networkSession = nullptr; - - if (useIncognito) { - networkSession = webkit_network_session_new_ephemeral(); - debugLog("InAppWebView: Creating WebView with ephemeral (incognito) network session"); - } - - WebKitWebContext* webContext = params.webContext; - - // Check if we're creating a related webview (for multi-window support) - if (params.relatedWebView != nullptr) { - webview_ = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, - "display", wpe_display_, - "user-content-manager", webkit_web_view_get_user_content_manager(params.relatedWebView), - "settings", webkit_web_view_get_settings(params.relatedWebView), - "related-view", params.relatedWebView, - nullptr)); - } else if (webContext != nullptr) { - if (networkSession != nullptr) { - webview_ = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, - "display", wpe_display_, - "web-context", webContext, - "network-session", networkSession, - "settings", settings, - nullptr)); - } else { - webview_ = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, - "display", wpe_display_, - "web-context", webContext, - "settings", settings, - nullptr)); - } - } else if (networkSession != nullptr) { - webview_ = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, - "display", wpe_display_, - "network-session", networkSession, - "settings", settings, - nullptr)); - } else { - webview_ = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, - "display", wpe_display_, - "settings", settings, - nullptr)); - } - - g_object_unref(settings); - - if (webview_ == nullptr) { - errorLog("InAppWebView: Failed to create WebKitWebView with WPEPlatform"); - if (networkSession != nullptr) { - g_object_unref(networkSession); - } - return; - } - - // Get WPEView from the WebView (created automatically by WebKit) - wpe_view_ = webkit_web_view_get_wpe_view(webview_); - if (wpe_view_ == nullptr) { - errorLog("InAppWebView: Failed to get WPEView from WebView"); - g_object_unref(webview_); - webview_ = nullptr; - return; - } - - // Note: Scale factor in WPEPlatform is read from the display, not set directly - // The WPEDisplay handles scale factor automatically based on the output - - // IMPORTANT: Connect to buffer-rendered signal BEFORE mapping the view - // This ensures we don't miss the first frame that WPE renders after mapping - buffer_rendered_handler_ = g_signal_connect(wpe_view_, "buffer-rendered", - G_CALLBACK(+[](WPEView* view, WPEBuffer* buffer, gpointer user_data) { - auto* self = static_cast(user_data); - self->OnWpePlatformBufferRendered(buffer); - }), this); - - // Get toplevel for size management (need this before setting scale) - wpe_toplevel_ = wpe_view_get_toplevel(wpe_view_); - - // WPEDisplayHeadless doesn't track real display scale, so we need to get it from GTK - // and manually notify WPE when it changes - if (gtk_window_ != nullptr) { - // Get initial scale from GTK window (which tracks the actual display scale) - int gtk_scale = gtk_widget_get_scale_factor(GTK_WIDGET(gtk_window_)); - if (gtk_scale > 0 && static_cast(gtk_scale) != scale_factor_) { - scale_factor_ = static_cast(gtk_scale); - // Notify WPE about the real display scale - if (wpe_toplevel_ != nullptr) { - wpe_toplevel_scale_changed(wpe_toplevel_, scale_factor_); - } - } - - // Connect to GTK window's scale-factor changes (triggered for example by Ubuntu display settings) - scale_changed_handler_ = g_signal_connect(gtk_window_, "notify::scale-factor", - G_CALLBACK(+[](GObject* object, GParamSpec* pspec, gpointer user_data) { - auto* self = static_cast(user_data); - auto* widget = GTK_WIDGET(object); - int new_scale = gtk_widget_get_scale_factor(widget); - - if (new_scale > 0 && static_cast(new_scale) != self->scale_factor_) { - self->scale_factor_ = static_cast(new_scale); - - // Notify WPE about the scale change so it renders at the correct resolution - if (self->wpe_toplevel_ != nullptr) { - wpe_toplevel_scale_changed(self->wpe_toplevel_, self->scale_factor_); - } - - // Notify Flutter that dimensions may have changed - if (self->on_frame_available_) { - self->on_frame_available_(); - } - } - }), this); - } else { - debugLog("Warning: No GTK window available for scale detection"); - } - - // Map the view to start rendering - wpe_view_map(wpe_view_); - - // Set focus so the view starts rendering and receiving input - wpe_view_focus_in(wpe_view_); - - // Resize toplevel (already obtained earlier for scale setup) - if (wpe_toplevel_ != nullptr) { - wpe_toplevel_resize(wpe_toplevel_, width_, height_); - } - - // Apply ITP setting if configured - if (params.initialSettings != nullptr) { - WebKitNetworkSession* session = webkit_web_view_get_network_session(webview_); - if (session != nullptr && params.initialSettings->itpEnabled) { - webkit_network_session_set_itp_enabled(session, TRUE); - } - } - -#elif defined(HAVE_WPE_BACKEND_LEGACY) - // === WPEBackend-FDO API (Legacy) === - - if (backend_ == nullptr) { - errorLog("InAppWebView: Cannot create webview without backend"); - return; - } - - // Check if we're creating a related webview (for multi-window support) - if (params.relatedWebView != nullptr) { - webview_ = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, - "backend", backend_, - "user-content-manager", webkit_web_view_get_user_content_manager(params.relatedWebView), - "settings", webkit_web_view_get_settings(params.relatedWebView), - "related-view", params.relatedWebView, - nullptr)); - - if (webview_ == nullptr) { - errorLog("InAppWebView: Failed to create related WebKitWebView"); - return; - } - } else { - // Create WebKit settings for a standalone webview - WebKitSettings* settings = webkit_settings_new(); - - // Check if incognito mode is enabled - bool useIncognito = params.initialSettings && params.initialSettings->incognito; - WebKitNetworkSession* networkSession = nullptr; - - if (useIncognito) { - networkSession = webkit_network_session_new_ephemeral(); - debugLog("InAppWebView: Creating WebView with ephemeral (incognito) network session"); - } - - // Check if a custom WebKitWebContext is provided - WebKitWebContext* webContext = params.webContext; - - if (webContext != nullptr) { - debugLog("InAppWebView: Creating WebView with custom WebKitWebContext"); - - if (networkSession != nullptr) { - webview_ = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, - "backend", backend_, - "web-context", webContext, - "network-session", networkSession, - nullptr)); - } else { - webview_ = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, - "backend", backend_, - "web-context", webContext, - nullptr)); - } - } else if (networkSession != nullptr) { - webview_ = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, - "backend", backend_, - "network-session", networkSession, - nullptr)); - } else { - webview_ = webkit_web_view_new(backend_); - } - - if (webview_ == nullptr) { - errorLog("InAppWebView: Failed to create WebKitWebView"); - if (settings != nullptr) { - g_object_unref(settings); - } - if (networkSession != nullptr) { - g_object_unref(networkSession); - } - return; - } - - if (params.initialSettings != nullptr) { - WebKitNetworkSession* session = webkit_web_view_get_network_session(webview_); - if (session != nullptr && params.initialSettings->itpEnabled) { - webkit_network_session_set_itp_enabled(session, TRUE); - debugLog("InAppWebView: ITP enabled"); - } - } - - webkit_web_view_set_settings(webview_, settings); - g_object_unref(settings); - } -#endif - - // === Common initialization (both APIs) === - - WebKitColor bg = {1.0, 1.0, 1.0, 1.0}; - webkit_web_view_set_background_color(webview_, &bg); - - user_content_controller_ = std::make_unique(webview_); - - findInteractionController_ = std::make_unique(this); - - // Create content blocker handler for Safari-style content blocking rules - WebKitUserContentManager* content_manager = webkit_web_view_get_user_content_manager(webview_); - if (content_manager != nullptr) { - content_blocker_handler_ = std::make_unique(content_manager); - } -} - -void InAppWebView::RegisterEventHandlers() { - if (webview_ == nullptr) { - return; - } - - // Set up the script message handler callback - if (user_content_controller_) { - // Set up handler callback for the callHandler message handler - // The registration is done via messageHandlerNames in plugin scripts (javascript_bridge_js.h) - // This uses the with_reply API for proper Promise resolution in iframes - user_content_controller_->setScriptMessageWithReplyHandler("callHandler", - [this](const std::string& body, WebKitScriptMessageReply* reply) -> bool { - return handleScriptMessageWithReply(body, reply); - }); - - // Add plugin scripts based on settings - // The plugin scripts register their message handlers via messageHandlerNames - PrepareAndAddUserScripts(); - } - - g_signal_connect(webview_, "load-changed", G_CALLBACK(OnLoadChanged), this); - g_signal_connect(webview_, "decide-policy", G_CALLBACK(OnDecidePolicy), this); - g_signal_connect(webview_, "notify::estimated-load-progress", - G_CALLBACK(OnNotifyEstimatedLoadProgress), this); - g_signal_connect(webview_, "notify::title", G_CALLBACK(OnNotifyTitle), this); - g_signal_connect(webview_, "notify::uri", G_CALLBACK(OnNotifyUri), this); - g_signal_connect(webview_, "load-failed", G_CALLBACK(OnLoadFailed), this); - g_signal_connect(webview_, "load-failed-with-tls-errors", G_CALLBACK(OnLoadFailedWithTlsErrors), - this); - g_signal_connect(webview_, "close", G_CALLBACK(OnCloseRequest), this); - g_signal_connect(webview_, "script-dialog", G_CALLBACK(OnScriptDialog), this); - g_signal_connect(webview_, "permission-request", G_CALLBACK(OnPermissionRequest), this); - g_signal_connect(webview_, "authenticate", G_CALLBACK(OnAuthenticate), this); - g_signal_connect(webview_, "context-menu", G_CALLBACK(OnContextMenu), this); - g_signal_connect(webview_, "context-menu-dismissed", G_CALLBACK(OnContextMenuDismissed), this); - g_signal_connect(webview_, "enter-fullscreen", G_CALLBACK(OnEnterFullscreen), this); - g_signal_connect(webview_, "leave-fullscreen", G_CALLBACK(OnLeaveFullscreen), this); - g_signal_connect(webview_, "mouse-target-changed", G_CALLBACK(OnMouseTargetChanged), this); - g_signal_connect(webview_, "create", G_CALLBACK(OnCreateWebView), this); - g_signal_connect(webview_, "web-process-terminated", G_CALLBACK(OnWebProcessTerminated), this); - g_signal_connect(webview_, "run-file-chooser", G_CALLBACK(OnRunFileChooser), this); - g_signal_connect(webview_, "show-option-menu", G_CALLBACK(OnShowOptionMenu), this); - - // Connect to download-started signal on NetworkSession (WPE WebKit 2.40+ API) - // Note: In WPE WebKit, download-started is on NetworkSession, not WebView - WebKitNetworkSession* network_session = webkit_web_view_get_network_session(webview_); - if (network_session != nullptr) { - download_started_handler_id_ = g_signal_connect(network_session, "download-started", G_CALLBACK(OnDownloadStarted), this); - } - - // Connect to back-forward-list changed signal for navigation state updates - // This enables InAppBrowser back/forward button state tracking - WebKitBackForwardList* bfList = webkit_web_view_get_back_forward_list(webview_); - if (bfList != nullptr) { - g_signal_connect(bfList, "changed", G_CALLBACK(OnBackForwardListChanged), this); - } - - // Connect to notify::camera-capture-state signal for onCameraCaptureStateChanged - // Available since WPE WebKit 2.34 - g_signal_connect(webview_, "notify::camera-capture-state", - G_CALLBACK(OnNotifyCameraCaptureState), this); - - // Connect to notify::microphone-capture-state signal for onMicrophoneCaptureStateChanged - // Available since WPE WebKit 2.34 - g_signal_connect(webview_, "notify::microphone-capture-state", - G_CALLBACK(OnNotifyMicrophoneCaptureState), this); - - webkit_web_view_add_frame_displayed_callback( - webview_, - [](WebKitWebView*, gpointer data) { - auto* self = static_cast(data); - self->OnFrameDisplayed(data); - }, - this, nullptr); -} - -void InAppWebView::PrepareAndAddUserScripts() { - if (user_content_controller_ == nullptr) { - return; - } - - bool javaScriptBridgeEnabled = java_script_bridge_enabled_; - if (settings_) { - javaScriptBridgeEnabled = settings_->javaScriptBridgeEnabled; - } - - if (!javaScriptBridgeEnabled) { - return; - } - - // Get plugin scripts settings - std::optional> pluginScriptsOriginAllowList = std::nullopt; - bool pluginScriptsForMainFrameOnly = false; - - if (settings_) { - pluginScriptsOriginAllowList = settings_->pluginScriptsOriginAllowList; - pluginScriptsForMainFrameOnly = settings_->pluginScriptsForMainFrameOnly; - } - - // Get JavaScript bridge-specific settings - // If javaScriptBridgeOriginAllowList is not set, fall back to pluginScriptsOriginAllowList - std::optional> javaScriptBridgeOriginAllowList = pluginScriptsOriginAllowList; - bool javaScriptBridgeForMainFrameOnly = pluginScriptsForMainFrameOnly; - - if (settings_) { - if (settings_->javaScriptBridgeOriginAllowList.has_value()) { - javaScriptBridgeOriginAllowList = settings_->javaScriptBridgeOriginAllowList; - } - if (settings_->javaScriptBridgeForMainFrameOnly.has_value()) { - javaScriptBridgeForMainFrameOnly = settings_->javaScriptBridgeForMainFrameOnly.value(); - } - } - - // === Add JavaScript Bridge Plugin Script === - // This is the core bridge for communication between web content and native code - auto jsBridgeScript = JavaScriptBridgeJS::JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT( - js_bridge_secret_, javaScriptBridgeOriginAllowList, javaScriptBridgeForMainFrameOnly); - user_content_controller_->addPluginScript(std::move(jsBridgeScript)); - - // === Add Console Log Interception Script === - // Note: Console log is always for main frame only to avoid issues - // (see https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738) - auto consoleLogScript = ConsoleLogJS::CONSOLE_LOG_JS_PLUGIN_SCRIPT(pluginScriptsOriginAllowList); - user_content_controller_->addPluginScript(std::move(consoleLogScript)); - - // === Add Color Input Interception Script === - // WPE WebKit doesn't have the run-color-chooser signal, so we handle - // via JavaScript interception - auto colorInputScript = - ColorInputJS::COLOR_INPUT_JS_PLUGIN_SCRIPT(pluginScriptsOriginAllowList, pluginScriptsForMainFrameOnly); - user_content_controller_->addPluginScript(std::move(colorInputScript)); - - // === Add Date Input Interception Script === - // WPE WebKit doesn't have date picker support, so we handle addPluginScript(std::move(cursorDetectionScript)); - - // === Add OnLoadResource Script === - // Uses PerformanceObserver API to track resource loading - if (settings_ != nullptr && settings_->useOnLoadResource) { - auto onLoadResourceScript = OnLoadResourceJS::ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT( - pluginScriptsOriginAllowList, pluginScriptsForMainFrameOnly); - user_content_controller_->addPluginScript(std::move(onLoadResourceScript)); - } - - // === Add AJAX Request Interception Script === - // Intercepts XMLHttpRequest calls for shouldInterceptAjaxRequest, onAjaxReadyStateChange, onAjaxProgress - if (settings_ != nullptr && settings_->useShouldInterceptAjaxRequest) { - auto ajaxInterceptScript = InterceptAjaxRequestJS::INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT( - pluginScriptsOriginAllowList, - pluginScriptsForMainFrameOnly, - settings_->useOnAjaxReadyStateChange, - settings_->useOnAjaxProgress); - user_content_controller_->addPluginScript(std::move(ajaxInterceptScript)); - } - - // === Add Fetch Request Interception Script === - // Intercepts fetch() calls for shouldInterceptFetchRequest - if (settings_ != nullptr && settings_->useShouldInterceptFetchRequest) { - auto fetchInterceptScript = InterceptFetchRequestJS::INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT( - pluginScriptsOriginAllowList, pluginScriptsForMainFrameOnly); - user_content_controller_->addPluginScript(std::move(fetchInterceptScript)); - } - - // === Add Print Interception Script === - // WPE WebKit doesn't have a native print signal, so we intercept window.print() - // via JavaScript and notify the Dart side - auto printInterceptionScript = PrintInterceptionJS::PRINT_INTERCEPTION_JS_PLUGIN_SCRIPT( - pluginScriptsOriginAllowList, pluginScriptsForMainFrameOnly); - user_content_controller_->addPluginScript(std::move(printInterceptionScript)); - - // TODO: Add additional plugin scripts as needed: - // - FindTextHighlightJS - // - etc. - - // === Add Initial User Scripts === - // These are scripts passed via initialUserScripts parameter from Dart - for (const auto& userScript : initial_user_scripts_) { - user_content_controller_->addUserScript(userScript); - } -} - -// === Monitor Change Handlers === - -void InAppWebView::SetupMonitorChangeHandlers() { - if (registrar_ == nullptr) { - return; - } - - // Get the GdkDisplay to connect to monitors-changed signal - GdkDisplay* display = gdk_display_get_default(); - if (display != nullptr) { - // Connect to monitors-changed signal on the display - // This fires when monitors are added, removed, or their properties change - monitors_changed_handler_id_ = g_signal_connect( - display, "monitor-added", - G_CALLBACK(+[](GdkDisplay*, GdkMonitor*, gpointer user_data) { - auto* self = static_cast(user_data); - self->UpdateMonitorRefreshRate(); - }), - this); - - // Also connect to monitor-removed in case the window moves to another monitor - g_signal_connect( - display, "monitor-removed", - G_CALLBACK(+[](GdkDisplay*, GdkMonitor*, gpointer user_data) { - auto* self = static_cast(user_data); - self->UpdateMonitorRefreshRate(); - }), - this); - } - - // Connect to configure-event on the toplevel window to detect window moves/resizes - // This helps us detect when the window moves between monitors - if (gtk_window_ != nullptr) { - configure_event_handler_id_ = g_signal_connect( - gtk_window_, "configure-event", - G_CALLBACK(+[](GtkWidget*, GdkEventConfigure*, gpointer user_data) -> gboolean { - auto* self = static_cast(user_data); - self->UpdateMonitorRefreshRate(); - return FALSE; // Continue event propagation - }), - this); - } -} - -void InAppWebView::CleanupMonitorChangeHandlers() { - // Disconnect monitors-changed signal - if (monitors_changed_handler_id_ != 0) { - GdkDisplay* display = gdk_display_get_default(); - if (display != nullptr) { - g_signal_handler_disconnect(display, monitors_changed_handler_id_); - } - monitors_changed_handler_id_ = 0; - } - - // Disconnect configure-event signal - if (configure_event_handler_id_ != 0 && gtk_window_ != nullptr) { - g_signal_handler_disconnect(gtk_window_, configure_event_handler_id_); - configure_event_handler_id_ = 0; - } -} - -void InAppWebView::UpdateMonitorRefreshRate() { -#ifdef HAVE_WPE_BACKEND_LEGACY - if (gtk_window_ == nullptr || wpe_backend_ == nullptr) { - return; - } - - int refresh_rate_mhz = flutter_inappwebview_linux_plugin_get_monitor_refresh_rate_for_window(gtk_window_); - if (refresh_rate_mhz > 0) { - uint32_t new_rate = static_cast(refresh_rate_mhz); - // Only update if the rate has actually changed - if (new_rate != target_refresh_rate_) { - wpe_view_backend_set_target_refresh_rate(wpe_backend_, new_rate); - target_refresh_rate_ = new_rate; - } - } -#endif -} - -// === WPE Backend Callbacks === - -void InAppWebView::OnFrameDisplayed(void* data) { - auto* self = static_cast(data); - - if (self->on_frame_available_) { - self->on_frame_available_(); - } -} - -#ifdef HAVE_WPE_BACKEND_LEGACY -void InAppWebView::OnExportDmaBuf(::wpe_fdo_egl_exported_image* image) { - if (image == nullptr) { - return; - } - - uint32_t img_width = wpe_fdo_egl_exported_image_get_width(image); - uint32_t img_height = wpe_fdo_egl_exported_image_get_height(image); - - // Get the EGL image from the exported image - EGLImageKHR egl_image = wpe_fdo_egl_exported_image_get_egl_image(image); - - // Only do pixel readback if: - // 1. skip_pixel_readback_ is false (not using zero-copy mode) - // 2. egl_display_ is available - // 3. We have a valid EGL image - if (!skip_pixel_readback_ && egl_image != EGL_NO_IMAGE_KHR && egl_display_ != nullptr) { - ReadPixelsFromEglImage(egl_image, img_width, img_height); - } - - // Protect exported_image_ access - this method is called from WPE's thread - // while GetCurrentEglImage may be called from Flutter's rendering thread - { - std::lock_guard lock(exported_image_mutex_); - - // Release previous exported image - if (exported_image_ != nullptr && exportable_ != nullptr) { - ::wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image(exportable_, - exported_image_); - } - - exported_image_ = image; - } - - // Call on_frame_available BEFORE dispatch_frame_complete - // This ensures the EGL image is captured before we signal WPE we're ready for more - if (on_frame_available_) { - on_frame_available_(); - } - - // Dispatch frame complete to allow WebKit to render next frame - // Note: This is moved AFTER on_frame_available to ensure the EGL image is used first - if (exportable_ != nullptr) { - wpe_view_backend_exportable_fdo_dispatch_frame_complete(exportable_); - } -} -#endif - -#ifdef HAVE_WPE_PLATFORM -void InAppWebView::OnWpePlatformBufferRendered(WPEBuffer* buffer) { - if (buffer == nullptr) { - return; - } - - // Don't process buffers during destruction - if (is_disposing_.load()) { - // Still need to release the buffer back to WPE - if (wpe_view_ != nullptr) { - wpe_view_buffer_released(wpe_view_, buffer); - } - return; - } - - // Get buffer dimensions - uint32_t buf_width = static_cast(wpe_buffer_get_width(buffer)); - uint32_t buf_height = static_cast(wpe_buffer_get_height(buffer)); - - - WPEBuffer* previous_buffer = nullptr; - bool buffer_handled = false; - - // Track EGL import failures to avoid repeated attempts - // Static because if EGL fails once, it will likely keep failing (e.g., no GPU) - static bool egl_import_failed_permanently = false; - - { - std::lock_guard lock(wpe_buffer_mutex_); - - // Store reference to previous buffer - we'll release it AFTER importing the new one - // This ensures the EGL image's backing memory stays valid until we have a new frame - previous_buffer = current_buffer_; - - // Destroy previous EGL image if we created one - if (current_egl_image_ != nullptr && egl_display_ != nullptr) { - static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr; - if (eglDestroyImageKHR == nullptr) { - eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR"); - } - if (eglDestroyImageKHR != nullptr) { - eglDestroyImageKHR(static_cast(egl_display_), - static_cast(current_egl_image_)); - } - current_egl_image_ = nullptr; - } - - // Check buffer type to determine best rendering path - bool is_dma_buf = WPE_IS_BUFFER_DMA_BUF(buffer); - bool is_shm = WPE_IS_BUFFER_SHM(buffer); - - // === Priority 1: Try EGL image import (zero-copy, best performance) === - // Only attempt EGL for DMA-BUF buffers (SHM buffers cannot be imported via EGL) - // Skip if previous EGL attempts failed - if (egl_display_ != nullptr && - is_dma_buf && !egl_import_failed_permanently) { - GError* error = nullptr; - void* egl_image = wpe_buffer_import_to_egl_image(buffer, &error); - - if (egl_image != nullptr) { - current_egl_image_ = egl_image; - current_buffer_width_ = buf_width; - current_buffer_height_ = buf_height; - buffer_handled = true; - } else { - // Mark EGL as permanently failed so we don't keep trying - // This is common in VMs or software-only environments - egl_import_failed_permanently = true; - if (error != nullptr) { - g_clear_error(&error); - } - } - } - - // === Priority 2: Direct SHM buffer access (no GBM required) === - // WPEBufferSHM provides direct pixel access without requiring GBM device - if (!buffer_handled && is_shm) { - WPEBufferSHM* shm_buffer = WPE_BUFFER_SHM(buffer); - GBytes* data = wpe_buffer_shm_get_data(shm_buffer); - - if (data != nullptr) { - guint stride = wpe_buffer_shm_get_stride(shm_buffer); - WPEPixelFormat format = wpe_buffer_shm_get_format(shm_buffer); - - gsize size; - const uint8_t* pixels = static_cast(g_bytes_get_data(data, &size)); - - if (pixels != nullptr && size > 0) { - // Store in pixel buffer for software rendering - size_t write_idx = write_buffer_index_.load(std::memory_order_relaxed); - auto& pixel_buffer = pixel_buffers_[write_idx]; - - if (pixel_buffer.data.size() != size) { - pixel_buffer.data.resize(size); - } - memcpy(pixel_buffer.data.data(), pixels, size); - - // WPE SHM buffers use ARGB8888 format (BGRA in memory on little-endian) - // Flutter expects RGBA8888, so we need to convert - // ConvertARGB32ToRGBA handles the BGRA -> RGBA conversion - if (format == WPE_PIXEL_FORMAT_ARGB8888) { - ConvertARGB32ToRGBA(pixel_buffer.data.data(), // source (in-place) - pixel_buffer.data.data(), // destination (in-place) - buf_width, buf_height, - stride); - } - - pixel_buffer.width = buf_width; - pixel_buffer.height = buf_height; - - // Swap buffers - { - std::lock_guard swap_lock(buffer_swap_mutex_); - read_buffer_index_.store(write_idx, std::memory_order_release); - write_buffer_index_.store((write_idx + 1) % kNumBuffers, std::memory_order_relaxed); - } - - current_buffer_width_ = buf_width; - current_buffer_height_ = buf_height; - buffer_handled = true; - } - // Note: Don't unref data - it's borrowed from the buffer - } - } - - // === Priority 3: Generic pixel import (works for DMA-BUF with GBM device) === - // This is a fallback for DMA-BUF when EGL failed but GBM device is available - if (!buffer_handled) { - GError* error = nullptr; - GBytes* pixels = wpe_buffer_import_to_pixels(buffer, &error); - if (pixels != nullptr) { - gsize size; - const uint8_t* data = static_cast(g_bytes_get_data(pixels, &size)); - - // Store in pixel buffer for software rendering - size_t write_idx = write_buffer_index_.load(std::memory_order_relaxed); - auto& pixel_buffer = pixel_buffers_[write_idx]; - - if (pixel_buffer.data.size() != size) { - pixel_buffer.data.resize(size); - } - memcpy(pixel_buffer.data.data(), data, size); - - // GBM pixel import also returns ARGB8888, convert to RGBA - uint32_t stride = buf_width * 4; - ConvertARGB32ToRGBA(pixel_buffer.data.data(), - pixel_buffer.data.data(), - buf_width, buf_height, - stride); - - pixel_buffer.width = buf_width; - pixel_buffer.height = buf_height; - - // Swap buffers - { - std::lock_guard swap_lock(buffer_swap_mutex_); - read_buffer_index_.store(write_idx, std::memory_order_release); - write_buffer_index_.store((write_idx + 1) % kNumBuffers, std::memory_order_relaxed); - } - - g_bytes_unref(pixels); - current_buffer_width_ = buf_width; - current_buffer_height_ = buf_height; - buffer_handled = true; - } else { - if (error != nullptr) { - g_clear_error(&error); - } - } - } - - if (!buffer_handled) { - debugLog("ERROR: No rendering method succeeded!"); - } - - // Store reference to current buffer - we keep it until the NEXT frame arrives - // This ensures the EGL image's backing DMA-BUF memory stays valid - current_buffer_ = buffer; - } - - // Release the PREVIOUS buffer now that we have a new one - // The previous EGL image has been destroyed and we have a new frame, - // so it's safe to let WPE reuse the old buffer's memory - if (previous_buffer != nullptr && wpe_view_ != nullptr && WPE_IS_BUFFER(previous_buffer)) { - wpe_view_buffer_released(wpe_view_, previous_buffer); - } - - if (buffer_handled && on_frame_available_) { - on_frame_available_(); - } -} -#endif - -void InAppWebView::ReadPixelsFromEglImage(void* egl_image, uint32_t width, uint32_t height) { - // CRITICAL: Check for GL context before any GL operations - // WPE WebKit calls this from its own thread which may not have a GL context - if (!HasCurrentGLContext()) { - return; - } - - EGLDisplay display = static_cast(egl_display_); - EGLImageKHR image = static_cast(egl_image); - - if (display == EGL_NO_DISPLAY || image == EGL_NO_IMAGE_KHR) { - return; - } - - // Create texture from EGL image if we haven't already - if (readback_texture_ == 0) { - glGenTextures(1, &readback_texture_); - } - - // Create FBO if needed - if (fbo_ == 0) { - glGenFramebuffers(1, &fbo_); - } - - glBindTexture(GL_TEXTURE_2D, readback_texture_); - - // Use the OES_EGL_image extension to create texture from EGL image - static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullptr; - if (glEGLImageTargetTexture2DOES == nullptr) { - glEGLImageTargetTexture2DOES = - (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES"); - } - - if (glEGLImageTargetTexture2DOES != nullptr) { - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); - } else { - glBindTexture(GL_TEXTURE_2D, 0); - return; - } - - glBindFramebuffer(GL_FRAMEBUFFER, fbo_); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, readback_texture_, 0); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - return; - } - - size_t buffer_size = width * height * 4; // RGBA - - // Use triple buffering - size_t write_idx = write_buffer_index_.load(std::memory_order_relaxed); - auto& buffer = pixel_buffers_[write_idx]; - - if (buffer.data.size() != buffer_size) { - buffer.data.resize(buffer_size); - } - - buffer.width = width; - buffer.height = height; - - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data.data()); - - { - std::lock_guard lock(buffer_swap_mutex_); - read_buffer_index_.store(write_idx, std::memory_order_release); - write_buffer_index_.store((write_idx + 1) % kNumBuffers, std::memory_order_relaxed); - } - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); -} - -// === Navigation Methods === - -void InAppWebView::loadUrl(const std::string& url) { - if (webview_ == nullptr) - return; - - webkit_web_view_load_uri(webview_, url.c_str()); -} - -void InAppWebView::loadUrl(const std::shared_ptr& urlRequest) { - if (webview_ == nullptr || !urlRequest) - return; - - if (!urlRequest->url.has_value()) { - return; - } - - std::string method = urlRequest->method.value_or("GET"); - - if (method == "GET" && !urlRequest->body.has_value() && !urlRequest->headers.has_value()) { - webkit_web_view_load_uri(webview_, urlRequest->url.value().c_str()); - return; - } - - // Create a WebKitURIRequest for more complex requests - WebKitURIRequest* request = webkit_uri_request_new(urlRequest->url.value().c_str()); - - if (urlRequest->headers.has_value()) { - SoupMessageHeaders* headers = webkit_uri_request_get_http_headers(request); - for (const auto& header : urlRequest->headers.value()) { - soup_message_headers_append(headers, header.first.c_str(), header.second.c_str()); - } - } - - webkit_web_view_load_request(webview_, request); - g_object_unref(request); -} - -void InAppWebView::loadData(const std::string& data, const std::string& mime_type, - const std::string& encoding, const std::string& base_url) { - if (webview_ == nullptr) - return; - - g_message("InAppWebView: loadData() called while loading, stopping current load first"); - webkit_web_view_stop_loading(webview_); - // Give WebKit/WPE FDO a moment to clean up pending operations - while (g_main_context_iteration(NULL, FALSE)) { } - - GBytes* bytes = g_bytes_new(data.data(), data.size()); - webkit_web_view_load_bytes(webview_, bytes, mime_type.c_str(), encoding.c_str(), - base_url.c_str()); - g_bytes_unref(bytes); -} - -void InAppWebView::loadFile(const std::string& asset_file_path) { - if (webview_ == nullptr) - return; - - g_message("InAppWebView: loadFile() called while loading, stopping current load first"); - webkit_web_view_stop_loading(webview_); - // Give WebKit/WPE FDO a moment to clean up pending operations - while (g_main_context_iteration(NULL, FALSE)) { } - - // Get the path to the running executable - char exe_path[PATH_MAX]; - ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); - if (len == -1) { - debugLog("Failed to get executable path for loadFile"); - return; - } - exe_path[len] = '\0'; - - // Build the absolute path to the Flutter asset - std::filesystem::path exe_dir = std::filesystem::path(exe_path).parent_path(); - std::filesystem::path flutter_asset_path = - exe_dir / "data" / "flutter_assets" / asset_file_path; - - if (!std::filesystem::exists(flutter_asset_path)) { - debugLog("Asset file not found: " + flutter_asset_path.string()); - return; - } - - std::string file_url = "file://" + flutter_asset_path.string(); - webkit_web_view_load_uri(webview_, file_url.c_str()); -} - -void InAppWebView::postUrl(const std::string& url, const std::vector& postData) { - if (webview_ == nullptr) - return; - - g_message("InAppWebView: postUrl() called while loading, stopping current load first"); - webkit_web_view_stop_loading(webview_); - // Give WebKit/WPE FDO a moment to clean up pending operations - while (g_main_context_iteration(NULL, FALSE)) { } - - // WPE WebKit's webkit_web_view_load_request() doesn't support POST body directly. - // We use JavaScript XMLHttpRequest to perform the POST and load the result. - // This approach is similar to the Web platform implementation. - - // Convert post data to base64 for safe embedding in JavaScript - gchar* base64_data = g_base64_encode(postData.data(), postData.size()); - - // Escape URL for JavaScript string - std::string escaped_url = url; - replace_all(escaped_url, "\\", "\\\\"); - replace_all(escaped_url, "'", "\\'"); - replace_all(escaped_url, "\n", "\\n"); - replace_all(escaped_url, "\r", "\\r"); - - // Create JavaScript that performs the POST request and loads the result - std::string js = R"( -(function() { - var xhr = new XMLHttpRequest(); - xhr.open('POST', ')" + escaped_url + R"(', true); - xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); - xhr.onload = function() { - if (xhr.status >= 200 && xhr.status < 300) { - document.open(); - document.write(xhr.responseText); - document.close(); - } - }; - xhr.onerror = function() { - console.error('postUrl XHR failed for: )" + escaped_url + R"('); - }; - var postData = atob(')" + std::string(base64_data) + R"('); - xhr.send(postData); -})(); -)"; - - g_free(base64_data); - - // First load about:blank to ensure we have a document context, then execute the XHR - // We need to inject the script after a page load - webkit_web_view_load_html(webview_, - "", - url.c_str()); - - // Use evaluateJavascript to run the XHR after the blank page loads - // We need to wait for the load to complete, so we use a delayed approach - std::string* js_copy = new std::string(js); - g_timeout_add(100, [](gpointer user_data) -> gboolean { - auto* data = static_cast*>(user_data); - if (data->first->webview() != nullptr) { - webkit_web_view_evaluate_javascript( - data->first->webview(), - data->second->c_str(), - -1, - nullptr, // world - nullptr, // source_uri - nullptr, // cancellable - nullptr, // callback - nullptr); // user_data - } - delete data->second; - delete data; - return G_SOURCE_REMOVE; - }, new std::pair(this, js_copy)); -} - -void InAppWebView::reload() { - if (webview_ == nullptr) - return; - - webkit_web_view_reload(webview_); -} - -void InAppWebView::reloadFromOrigin() { - if (webview_ == nullptr) - return; - - g_message("InAppWebView: reloadFromOrigin() called while loading, stopping current load first"); - webkit_web_view_stop_loading(webview_); - // Give WebKit/WPE FDO a moment to clean up pending operations - while (g_main_context_iteration(NULL, FALSE)) { } - - webkit_web_view_reload_bypass_cache(webview_); -} - -void InAppWebView::goBack() { - if (webview_ == nullptr) - return; - - webkit_web_view_go_back(webview_); -} - -void InAppWebView::goForward() { - if (webview_ == nullptr) - return; - - webkit_web_view_go_forward(webview_); -} - -bool InAppWebView::canGoBack() const { - if (webview_ == nullptr) - return false; - return webkit_web_view_can_go_back(webview_); -} - -bool InAppWebView::canGoForward() const { - if (webview_ == nullptr) - return false; - return webkit_web_view_can_go_forward(webview_); -} - -void InAppWebView::stopLoading() { - if (webview_ == nullptr) - return; - webkit_web_view_stop_loading(webview_); -} - -bool InAppWebView::isLoading() const { - if (webview_ == nullptr) - return false; - return webkit_web_view_is_loading(webview_); -} - -// === Navigation History === - -FlValue* InAppWebView::getCopyBackForwardList() const { - if (webview_ == nullptr) { - return fl_value_new_null(); - } - - WebKitBackForwardList* bfList = webkit_web_view_get_back_forward_list(webview_); - if (bfList == nullptr) { - return fl_value_new_null(); - } - - GList* backList = webkit_back_forward_list_get_back_list(bfList); - WebKitBackForwardListItem* currentItem = webkit_back_forward_list_get_current_item(bfList); - GList* forwardList = webkit_back_forward_list_get_forward_list(bfList); - - int currentIndex = g_list_length(backList); - - FlValue* historyList = fl_value_new_list(); - int index = 0; - - for (GList* l = backList; l != nullptr; l = l->next) { - WebKitBackForwardListItem* item = WEBKIT_BACK_FORWARD_LIST_ITEM(l->data); - - const gchar* originalUri = webkit_back_forward_list_item_get_original_uri(item); - const gchar* title = webkit_back_forward_list_item_get_title(item); - const gchar* uri = webkit_back_forward_list_item_get_uri(item); - - FlValue* itemMap = to_fl_map({ - {"originalUrl", make_fl_value(originalUri ? originalUri : "")}, - {"title", make_fl_value(title ? title : "")}, - {"url", make_fl_value(uri ? uri : "")}, - {"index", make_fl_value(index)}, - {"offset", make_fl_value(index - currentIndex)}, - }); - - fl_value_append_take(historyList, itemMap); - index++; - } - - if (currentItem != nullptr) { - const gchar* originalUri = webkit_back_forward_list_item_get_original_uri(currentItem); - const gchar* title = webkit_back_forward_list_item_get_title(currentItem); - const gchar* uri = webkit_back_forward_list_item_get_uri(currentItem); - - FlValue* itemMap = to_fl_map({ - {"originalUrl", make_fl_value(originalUri ? originalUri : "")}, - {"title", make_fl_value(title ? title : "")}, - {"url", make_fl_value(uri ? uri : "")}, - {"index", make_fl_value(index)}, - {"offset", make_fl_value(index - currentIndex)}, - }); - - fl_value_append_take(historyList, itemMap); - index++; - } - - for (GList* l = forwardList; l != nullptr; l = l->next) { - WebKitBackForwardListItem* item = WEBKIT_BACK_FORWARD_LIST_ITEM(l->data); - - const gchar* originalUri = webkit_back_forward_list_item_get_original_uri(item); - const gchar* title = webkit_back_forward_list_item_get_title(item); - const gchar* uri = webkit_back_forward_list_item_get_uri(item); - - FlValue* itemMap = to_fl_map({ - {"originalUrl", make_fl_value(originalUri ? originalUri : "")}, - {"title", make_fl_value(title ? title : "")}, - {"url", make_fl_value(uri ? uri : "")}, - {"index", make_fl_value(index)}, - {"offset", make_fl_value(index - currentIndex)}, - }); - - fl_value_append_take(historyList, itemMap); - index++; - } - - return to_fl_map({ - {"list", historyList}, - {"currentIndex", make_fl_value(currentIndex)}, - }); -} - -void InAppWebView::goBackOrForward(int steps) { - if (webview_ == nullptr) - return; - - WebKitBackForwardList* bfList = webkit_web_view_get_back_forward_list(webview_); - if (bfList == nullptr) - return; - - WebKitBackForwardListItem* item = webkit_back_forward_list_get_nth_item(bfList, steps); - if (item != nullptr) { - webkit_web_view_go_to_back_forward_list_item(webview_, item); - } -} - -bool InAppWebView::canGoBackOrForward(int steps) const { - if (webview_ == nullptr) - return false; - - WebKitBackForwardList* bfList = webkit_web_view_get_back_forward_list(webview_); - if (bfList == nullptr) - return false; - - WebKitBackForwardListItem* item = webkit_back_forward_list_get_nth_item(bfList, steps); - return item != nullptr; -} - -// === Getters === - -std::optional InAppWebView::getUrl() const { - if (webview_ == nullptr) - return std::nullopt; - const gchar* uri = webkit_web_view_get_uri(webview_); - if (uri == nullptr) - return std::nullopt; - return std::string(uri); -} - -std::optional InAppWebView::getTitle() const { - if (webview_ == nullptr) - return std::nullopt; - const gchar* title = webkit_web_view_get_title(webview_); - if (title == nullptr) - return std::nullopt; - return std::string(title); -} - -int64_t InAppWebView::getProgress() const { - if (webview_ == nullptr) - return 0; - return static_cast(webkit_web_view_get_estimated_load_progress(webview_) * 100); -} - -// === TLS/SSL Certificate === - -std::optional InAppWebView::getCertificate() const { - if (webview_ == nullptr) { - return std::nullopt; - } - - GTlsCertificate* certificate = nullptr; - GTlsCertificateFlags errors = static_cast(0); - - if (!webkit_web_view_get_tls_info(webview_, &certificate, &errors)) { - return std::nullopt; - } - - if (certificate == nullptr) { - return std::nullopt; - } - - GByteArray* der_data = nullptr; - g_object_get(certificate, "certificate", &der_data, nullptr); - - if (der_data == nullptr || der_data->len == 0) { - if (der_data != nullptr) { - g_byte_array_unref(der_data); - } - return std::nullopt; - } - - std::vector certData(der_data->data, der_data->data + der_data->len); - g_byte_array_unref(der_data); - - return SslCertificate(certData); -} - -HitTestResult InAppWebView::getHitTestResult() const { - if (last_hit_test_result_ == nullptr) { - return HitTestResult(HitTestResultType::UNKNOWN_TYPE); - } - return HitTestResult::fromWebKitHitTestResult(last_hit_test_result_); -} - -// === JavaScript === - -void InAppWebView::evaluateJavascript( - const std::string& source, - const std::optional& worldName, - std::function&)> callback) { - if (webview_ == nullptr) { - if (callback) - callback(std::nullopt); - return; - } - - struct CallbackData { - std::function&)> callback; - }; - - auto* cb_data = new CallbackData{std::move(callback)}; - - const char* world = worldName.has_value() ? worldName->c_str() : nullptr; - - webkit_web_view_evaluate_javascript( - webview_, source.c_str(), source.length(), - world, // world name (for content world support) - nullptr, // source URI - nullptr, // cancellable - [](GObject* source, GAsyncResult* result, gpointer user_data) { - auto* data = static_cast(user_data); - GError* error = nullptr; - JSCValue* js_result = - webkit_web_view_evaluate_javascript_finish(WEBKIT_WEB_VIEW(source), result, &error); - - if (error != nullptr) { - if (data->callback) - data->callback(std::nullopt); - g_error_free(error); - } else if (js_result != nullptr) { - // Use JSON.stringify on the result via JSC to get proper JSON - JSCContext* context = jsc_value_get_context(js_result); - g_autoptr(JSCValue) json_stringify = jsc_context_evaluate( - context, - "(function(v) { return JSON.stringify(v); })", - -1); - g_autoptr(JSCValue) json_value = jsc_value_function_call( - json_stringify, JSC_TYPE_VALUE, js_result, G_TYPE_NONE); - - if (json_value != nullptr && jsc_value_is_string(json_value)) { - g_autofree gchar* str = jsc_value_to_string(json_value); - if (data->callback) { - if (str) { - data->callback(std::string(str)); - } else { - data->callback(std::nullopt); - } - } - } else { - if (data->callback) - data->callback(std::nullopt); - } - g_object_unref(js_result); - } else { - if (data->callback) - data->callback(std::nullopt); - } - - delete data; - }, - cb_data); -} - -// Helper function to convert FlValue to GVariant -void InAppWebView::callAsyncJavaScript( - const std::string& functionBody, - const std::string& argumentsJson, - const std::vector& argumentKeys, - const std::optional& worldName, - std::function callback) { - if (webview_ == nullptr) { - if (callback) { - callback(R"({"value":null,"error":"WebView not available"})"); - } - return; - } - - // Build the wrapped function body that: - // 1. Parses the JSON-encoded arguments - // 2. Destructures them into local variables - // 3. Executes the user's function body - std::string wrappedBody; - - if (!argumentKeys.empty()) { - // Build destructuring: const {key1, key2, ...} = JSON.parse(__args__); - wrappedBody = "const {"; - for (size_t i = 0; i < argumentKeys.size(); i++) { - if (i > 0) wrappedBody += ", "; - wrappedBody += argumentKeys[i]; - } - wrappedBody += "} = JSON.parse(__args__);\n"; - } - wrappedBody += functionBody; - - // Pass the JSON string as a single __args__ argument - GVariantBuilder builder; - g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); - g_variant_builder_add(&builder, "{sv}", "__args__", g_variant_new_string(argumentsJson.c_str())); - GVariant* gvariant_args = g_variant_builder_end(&builder); - - const char* world = worldName.has_value() ? worldName->c_str() : nullptr; - - struct CallbackData { - std::function callback; - }; - auto* cb_data = new CallbackData{std::move(callback)}; - - webkit_web_view_call_async_javascript_function( - webview_, wrappedBody.c_str(), -1, // length: null-terminated - gvariant_args, world, - nullptr, // source_uri - nullptr, // cancellable - [](GObject* source, GAsyncResult* result, gpointer user_data) { - auto* data = static_cast(user_data); - GError* error = nullptr; - JSCValue* js_result = webkit_web_view_call_async_javascript_function_finish( - WEBKIT_WEB_VIEW(source), result, &error); - - std::string json_result; - - if (error != nullptr) { - // Escape the error message for JSON - std::string error_msg = error->message ? error->message : "Unknown error"; - // Simple JSON escaping for the error message - std::string escaped_error; - for (char c : error_msg) { - switch (c) { - case '"': escaped_error += "\\\""; break; - case '\\': escaped_error += "\\\\"; break; - case '\n': escaped_error += "\\n"; break; - case '\r': escaped_error += "\\r"; break; - case '\t': escaped_error += "\\t"; break; - default: escaped_error += c; break; - } - } - json_result = "{\"value\":null,\"error\":\"" + escaped_error + "\"}"; - g_error_free(error); - } else if (js_result != nullptr) { - // Use JSON.stringify on the result via JSC to get proper JSON - JSCContext* context = jsc_value_get_context(js_result); - g_autoptr(JSCValue) json_stringify = jsc_context_evaluate( - context, - "(function(v) { return JSON.stringify({value: v, error: null}); })", - -1); - g_autoptr(JSCValue) json_value = jsc_value_function_call( - json_stringify, JSC_TYPE_VALUE, js_result, G_TYPE_NONE); - - if (json_value != nullptr && jsc_value_is_string(json_value)) { - g_autofree gchar* str = jsc_value_to_string(json_value); - json_result = str ? str : "{\"value\":null,\"error\":null}"; - } else { - json_result = "{\"value\":null,\"error\":null}"; - } - g_object_unref(js_result); - } else { - json_result = "{\"value\":null,\"error\":null}"; - } - - if (data->callback) { - data->callback(json_result); - } - delete data; - }, - cb_data); -} - -void InAppWebView::injectJavascriptFileFromUrl(const std::string& urlFile) { - std::string script = - "(function() {" - " var script = document.createElement('script');" - " script.src = '" + - urlFile + - "';" - " document.head.appendChild(script);" - "})();"; - evaluateJavascript(script, std::nullopt, nullptr); -} - -void InAppWebView::injectCSSCode(const std::string& source) { - // Escape single quotes and newlines in CSS - std::string escaped_source = source; - size_t pos = 0; - while ((pos = escaped_source.find("'", pos)) != std::string::npos) { - escaped_source.replace(pos, 1, "\\'"); - pos += 2; - } - pos = 0; - while ((pos = escaped_source.find("\n", pos)) != std::string::npos) { - escaped_source.replace(pos, 1, "\\n"); - pos += 2; - } - - std::string script = - "(function() {" - " var style = document.createElement('style');" - " style.textContent = '" + - escaped_source + - "';" - " document.head.appendChild(style);" - "})();"; - evaluateJavascript(script, std::nullopt, nullptr); -} - -void InAppWebView::injectCSSFileFromUrl(const std::string& urlFile) { - std::string script = - "(function() {" - " var link = document.createElement('link');" - " link.rel = 'stylesheet';" - " link.href = '" + - urlFile + - "';" - " document.head.appendChild(link);" - "})();"; - evaluateJavascript(script, std::nullopt, nullptr); -} - -// === User Scripts === - -void InAppWebView::addUserScript(std::shared_ptr userScript) { - if (user_content_controller_) { - user_content_controller_->addUserScript(userScript); - } -} - -void InAppWebView::removeUserScriptAt(size_t index, UserScriptInjectionTime injectionTime) { - if (user_content_controller_) { - user_content_controller_->removeUserScriptAt(index, injectionTime); - } -} - -void InAppWebView::removeUserScriptsByGroupName(const std::string& groupName) { - if (user_content_controller_) { - user_content_controller_->removeUserScriptsByGroupName(groupName); - } -} - -void InAppWebView::removeAllUserScripts() { - if (user_content_controller_) { - user_content_controller_->removeAllUserScripts(); - } -} - -// === Web Message Listener === - -void InAppWebView::addWebMessageListener(const std::string& jsObjectName, - const std::vector& allowedOriginRules) { - if (webview_ == nullptr || jsObjectName.empty() || messenger_ == nullptr) { - return; - } - - // Generate a unique ID for this listener - static int64_t listener_counter = 0; - std::string listenerId = std::to_string(g_get_monotonic_time()) + "_" + - std::to_string(++listener_counter); - - // Create the native WebMessageListener with its dedicated channel - // This follows the federated plugin pattern - std::set originRulesSet(allowedOriginRules.begin(), allowedOriginRules.end()); - auto listener = std::make_unique( - messenger_, listenerId, jsObjectName, originRulesSet, this); - - // Store the listener by jsObjectName (so we can find it when JS posts a message) - web_message_listeners_[jsObjectName] = std::move(listener); - - // Build the allowed origin rules JSON array for JavaScript injection - std::string allowedOriginRulesJs = "["; - for (size_t i = 0; i < allowedOriginRules.size(); ++i) { - const std::string& rule = allowedOriginRules[i]; - if (rule == "*") { - allowedOriginRulesJs += "'*'"; - } else { - // Parse the rule to extract scheme, host, port - // Format: scheme://host[:port] - std::string scheme, host; - int port = 0; - - size_t schemeEnd = rule.find("://"); - if (schemeEnd != std::string::npos) { - scheme = rule.substr(0, schemeEnd); - std::string rest = rule.substr(schemeEnd + 3); - - size_t portStart = rest.find(':'); - if (portStart != std::string::npos) { - host = rest.substr(0, portStart); - try { - port = std::stoi(rest.substr(portStart + 1)); - } catch (...) { - port = 0; - } - } else { - host = rest; - } - } - - // Escape single quotes in host - std::string hostEscaped = host; - size_t pos = 0; - while ((pos = hostEscaped.find("'", pos)) != std::string::npos) { - hostEscaped.replace(pos, 1, "\\'"); - pos += 2; - } - - allowedOriginRulesJs += "{scheme: '" + scheme + "', host: "; - if (host.empty()) { - allowedOriginRulesJs += "null"; - } else { - allowedOriginRulesJs += "'" + hostEscaped + "'"; - } - allowedOriginRulesJs += ", port: "; - if (port == 0) { - allowedOriginRulesJs += "null"; - } else { - allowedOriginRulesJs += std::to_string(port); - } - allowedOriginRulesJs += "}"; - } - if (i < allowedOriginRules.size() - 1) { - allowedOriginRulesJs += ", "; - } - } - allowedOriginRulesJs += "]"; - - // Create the JavaScript to inject - std::string jsSource = WebMessageListenerJS::createWebMessageListenerInjectionJs( - jsObjectName, allowedOriginRulesJs); - - // Create a user script for this web message listener - // We use a unique group name to allow removal if needed - std::string groupName = "WebMessageListener-" + jsObjectName; - - auto userScript = std::make_shared( - groupName, - jsSource, - UserScriptInjectionTime::atDocumentStart, - true, // forMainFrameOnly - std::nullopt // allowedOriginRules (already handled in JS) - ); - - // Add the script to the user content controller - if (user_content_controller_) { - user_content_controller_->addUserScript(userScript); - } -} - -// === Web Message Channel === - -void InAppWebView::createWebMessageChannel( - std::function&)> callback) { - if (webview_ == nullptr || messenger_ == nullptr) { - if (callback) callback(std::nullopt); - return; - } - - // Generate a unique channel ID using timestamp and random number - static int64_t channel_counter = 0; - std::string channelId = std::to_string(g_get_monotonic_time()) + "_" + - std::to_string(++channel_counter); - - // Create the JavaScript to create the MessageChannel - std::string js = WebMessageChannelJS::createWebMessageChannelJs(channelId); - - // Capture variables for the callback - InAppWebView* self = this; - FlBinaryMessenger* messenger = messenger_; - - // Execute JavaScript to create the channel - evaluateJavascript(js, std::nullopt, [self, callback, channelId, messenger](const std::optional& result) { - // If we got a result, the channel was created successfully - if (result.has_value()) { - // Create and store the WebMessageChannel object - auto channel = std::make_unique(messenger, channelId, self); - self->web_message_channels_[channelId] = std::move(channel); - - callback(channelId); - } else { - callback(std::nullopt); - } - }); -} - -WebMessageChannel* InAppWebView::getWebMessageChannel(const std::string& channelId) const { - auto it = web_message_channels_.find(channelId); - if (it != web_message_channels_.end()) { - return it->second.get(); - } - return nullptr; -} - -void InAppWebView::postWebMessage(const std::string& messageData, - const std::string& targetOrigin, - int64_t messageType) { - if (webview_ == nullptr) return; - - // Convert message data to JavaScript expression - std::string messageDataJs; - if (messageType == 1) { - // ArrayBuffer - messageData contains comma-separated byte values - messageDataJs = "new Uint8Array([" + messageData + "]).buffer"; - } else { - // String - escape for JavaScript - std::string escaped; - escaped.reserve(messageData.size() * 2); - for (char c : messageData) { - switch (c) { - case '\\': escaped += "\\\\"; break; - case '"': escaped += "\\\""; break; - case '\n': escaped += "\\n"; break; - case '\r': escaped += "\\r"; break; - case '\t': escaped += "\\t"; break; - default: escaped += c; break; - } - } - messageDataJs = "\"" + escaped + "\""; - } - - // Post message to window (no ports for now - ports are handled via channel) - std::string js = WebMessageChannelJS::postWebMessageJs(messageDataJs, targetOrigin, ""); - evaluateJavascript(js, std::nullopt, nullptr); -} - -void InAppWebView::setWebMessageCallback(const std::string& channelId, int portIndex) { - if (webview_ == nullptr || channelId.empty()) return; - - std::string js = WebMessageChannelJS::setWebMessageCallbackJs(channelId, portIndex); - evaluateJavascript(js, std::nullopt, nullptr); -} - -void InAppWebView::postWebMessageOnPort(const std::string& channelId, int portIndex, - const std::string& messageData, int64_t messageType) { - if (webview_ == nullptr || channelId.empty()) return; - - // Convert message data to JavaScript expression - std::string messageDataJs; - if (messageType == 1) { - // ArrayBuffer - messageData contains comma-separated byte values - messageDataJs = "new Uint8Array([" + messageData + "]).buffer"; - } else { - // String - escape for JavaScript - std::string escaped; - escaped.reserve(messageData.size() * 2); - for (char c : messageData) { - switch (c) { - case '\\': escaped += "\\\\"; break; - case '"': escaped += "\\\""; break; - case '\n': escaped += "\\n"; break; - case '\r': escaped += "\\r"; break; - case '\t': escaped += "\\t"; break; - default: escaped += c; break; - } - } - messageDataJs = "\"" + escaped + "\""; - } - - std::string js = WebMessageChannelJS::postMessageJs(channelId, portIndex, messageDataJs); - evaluateJavascript(js, std::nullopt, nullptr); -} - -void InAppWebView::closeWebMessagePort(const std::string& channelId, int portIndex) { - if (webview_ == nullptr || channelId.empty()) return; - - std::string js = WebMessageChannelJS::closePortJs(channelId, portIndex); - evaluateJavascript(js, std::nullopt, nullptr); -} - -void InAppWebView::disposeWebMessageChannel(const std::string& channelId) { - if (channelId.empty()) return; - - // Execute JavaScript to clean up the channel - if (webview_ != nullptr) { - std::string js = WebMessageChannelJS::disposeChannelJs(channelId); - evaluateJavascript(js, std::nullopt, nullptr); - } - - // Remove the channel from our map - web_message_channels_.erase(channelId); -} - -// === HTML Content === - -void InAppWebView::getHtml(std::function&)> callback) { - evaluateJavascript("document.documentElement.outerHTML", std::nullopt, callback); -} - -// === Screenshot === - -void InAppWebView::takeScreenshot(std::function>&)> callback) { - if (webview_ == nullptr || callback == nullptr) { - if (callback) { - callback(std::nullopt); - } - return; - } - - // Get the current pixel buffer dimensions - uint32_t width = 0; - uint32_t height = 0; - size_t buffer_size = GetPixelBufferSize(&width, &height); - - if (buffer_size == 0 || width == 0 || height == 0) { - callback(std::nullopt); - return; - } - - // Allocate a temporary buffer for the pixel data - std::vector pixel_data(buffer_size); - - if (!CopyPixelBufferTo(pixel_data.data(), buffer_size, &width, &height)) { - callback(std::nullopt); - return; - } - - // Create a Cairo surface from the RGBA pixel data - // Note: WPE provides RGBA data, but Cairo uses ARGB (pre-multiplied alpha in native byte order) - // We need to convert RGBA -> ARGB32 format - - // Allocate buffer for Cairo ARGB32 format (same size) - std::vector argb_data(width * height * 4); - - // Convert RGBA -> ARGB32 (Cairo's native format) - // Cairo ARGB32 format on little-endian: BGRA in memory - for (uint32_t i = 0; i < width * height; ++i) { - uint8_t r = pixel_data[i * 4 + 0]; - uint8_t g = pixel_data[i * 4 + 1]; - uint8_t b = pixel_data[i * 4 + 2]; - uint8_t a = pixel_data[i * 4 + 3]; - - // Cairo ARGB32 on little-endian = BGRA in memory - argb_data[i * 4 + 0] = b; - argb_data[i * 4 + 1] = g; - argb_data[i * 4 + 2] = r; - argb_data[i * 4 + 3] = a; - } - - // Create Cairo surface from the ARGB data - cairo_surface_t* surface = cairo_image_surface_create_for_data( - argb_data.data(), - CAIRO_FORMAT_ARGB32, - static_cast(width), - static_cast(height), - static_cast(width * 4) // stride - ); - - if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { - cairo_surface_destroy(surface); - callback(std::nullopt); - return; - } - - // Write PNG to a memory buffer using cairo_surface_write_to_png_stream - std::vector png_data; - - cairo_status_t status = cairo_surface_write_to_png_stream( - surface, - [](void* closure, const unsigned char* data, unsigned int length) -> cairo_status_t { - auto* output = static_cast*>(closure); - output->insert(output->end(), data, data + length); - return CAIRO_STATUS_SUCCESS; - }, - &png_data - ); - - cairo_surface_destroy(surface); - - if (status != CAIRO_STATUS_SUCCESS || png_data.empty()) { - callback(std::nullopt); - return; - } - - callback(png_data); -} - -// === Session State === - -std::optional> InAppWebView::saveState() const { - if (webview_ == nullptr) { - return std::nullopt; - } - - // Get the current session state from WPE WebKit - WebKitWebViewSessionState* session_state = webkit_web_view_get_session_state(webview_); - if (session_state == nullptr) { - return std::nullopt; - } - - // Serialize the session state to GBytes - GBytes* bytes = webkit_web_view_session_state_serialize(session_state); - webkit_web_view_session_state_unref(session_state); - - if (bytes == nullptr) { - return std::nullopt; - } - - // Copy the data to a vector - gsize size = 0; - gconstpointer data = g_bytes_get_data(bytes, &size); - - if (data == nullptr || size == 0) { - g_bytes_unref(bytes); - return std::nullopt; - } - - std::vector result(static_cast(data), - static_cast(data) + size); - - g_bytes_unref(bytes); - return result; -} - -bool InAppWebView::restoreState(const std::vector& stateData) { - if (webview_ == nullptr || stateData.empty()) { - return false; - } - - // Create GBytes from the state data - GBytes* bytes = g_bytes_new(stateData.data(), stateData.size()); - if (bytes == nullptr) { - return false; - } - - // Create session state from the serialized data - WebKitWebViewSessionState* session_state = webkit_web_view_session_state_new(bytes); - g_bytes_unref(bytes); - - if (session_state == nullptr) { - return false; - } - - // Restore the session state - webkit_web_view_restore_session_state(webview_, session_state); - webkit_web_view_session_state_unref(session_state); - - return true; -} - -// === Zoom === - -double InAppWebView::getZoomScale() const { - if (webview_ == nullptr) - return 1.0; - return webkit_web_view_get_zoom_level(webview_); -} - -void InAppWebView::setZoomScale(double zoomScale) { - if (webview_ == nullptr) - return; - webkit_web_view_set_zoom_level(webview_, zoomScale); -} - -// === Scroll === - -void InAppWebView::scrollTo(int64_t x, int64_t y, bool animated) { - std::string script = - animated ? "window.scrollTo({top: " + std::to_string(y) + ", left: " + std::to_string(x) + - ", behavior: 'smooth'});" - : "window.scrollTo(" + std::to_string(x) + ", " + std::to_string(y) + ");"; - evaluateJavascript(script, std::nullopt, nullptr); -} - -void InAppWebView::scrollBy(int64_t x, int64_t y, bool animated) { - std::string script = - animated ? "window.scrollBy({top: " + std::to_string(y) + ", left: " + std::to_string(x) + - ", behavior: 'smooth'});" - : "window.scrollBy(" + std::to_string(x) + ", " + std::to_string(y) + ");"; - evaluateJavascript(script, std::nullopt, nullptr); -} - -void InAppWebView::getScrollX(std::function callback) { - if (webview_ == nullptr || callback == nullptr) { - if (callback) callback(0); - return; - } - - evaluateJavascript( - "window.scrollX || window.pageXOffset || document.documentElement.scrollLeft || 0", - std::nullopt, - [callback](const std::optional& result) { - int64_t scrollX = 0; - if (result.has_value()) { - try { - scrollX = std::stoll(*result); - } catch (...) { - scrollX = 0; - } - } - callback(scrollX); - }); -} - -void InAppWebView::getScrollY(std::function callback) { - if (webview_ == nullptr || callback == nullptr) { - if (callback) callback(0); - return; - } - - evaluateJavascript( - "window.scrollY || window.pageYOffset || document.documentElement.scrollTop || 0", - std::nullopt, - [callback](const std::optional& result) { - int64_t scrollY = 0; - if (result.has_value()) { - try { - scrollY = std::stoll(*result); - } catch (...) { - scrollY = 0; - } - } - callback(scrollY); - }); -} - -void InAppWebView::canScrollVertically(std::function callback) { - if (webview_ == nullptr || callback == nullptr) { - if (callback) callback(false); - return; - } - - evaluateJavascript( - "document.documentElement.scrollHeight > document.documentElement.clientHeight", - std::nullopt, - [callback](const std::optional& result) { - bool canScroll = false; - if (result.has_value() && *result == "true") { - canScroll = true; - } - callback(canScroll); - }); -} - -void InAppWebView::canScrollHorizontally(std::function callback) { - if (webview_ == nullptr || callback == nullptr) { - if (callback) callback(false); - return; - } - - evaluateJavascript( - "document.documentElement.scrollWidth > document.documentElement.clientWidth", - std::nullopt, - [callback](const std::optional& result) { - bool canScroll = false; - if (result.has_value() && *result == "true") { - canScroll = true; - } - callback(canScroll); - }); -} - -// === Content Dimensions === - -void InAppWebView::getContentHeight(std::function callback) { - if (callback == nullptr) { - return; - } - - // Use JavaScript to get the document's scroll height - evaluateJavascript( - "Math.max(document.body.scrollHeight, document.documentElement.scrollHeight)", - std::nullopt, - [callback](const std::optional& result) { - if (result.has_value()) { - try { - int64_t height = std::stoll(result.value()); - callback(height); - return; - } catch (...) { - // Fall through to default - } - } - callback(0); - }); -} - -void InAppWebView::getContentWidth(std::function callback) { - if (callback == nullptr) { - return; - } - - // Use JavaScript to get the document's scroll width - evaluateJavascript( - "Math.max(document.body.scrollWidth, document.documentElement.scrollWidth)", - std::nullopt, - [callback](const std::optional& result) { - if (result.has_value()) { - try { - int64_t width = std::stoll(result.value()); - callback(width); - return; - } catch (...) { - // Fall through to default - } - } - callback(0); - }); -} - -// === Settings === - -FlValue* InAppWebView::getSettings() const { - if (settings_) { - return settings_->toFlValue(); - } - return fl_value_new_null(); -} - -void InAppWebView::setSettings(const std::shared_ptr newSettings, - FlValue* newSettingsMap) { - if (newSettings && webview_) { - // Check if contentBlockers changed - FlValue* newContentBlockers = newSettings->contentBlockers; - - // Apply content blockers if they have been updated - if (content_blocker_handler_ != nullptr) { - // If new settings have contentBlockers, apply them - // This will replace any existing content blockers - content_blocker_handler_->setContentBlockers(newContentBlockers, nullptr); - } - - settings_ = newSettings; - settings_->applyToWebView(webview_); -#ifdef HAVE_WPE_PLATFORM - // Apply WPE Platform settings (dark mode, font settings, etc.) - if (wpe_display_ != nullptr) { - settings_->applyWpePlatformSettings(wpe_display_); - } -#endif - } -} - -// === Size Management === - -void InAppWebView::setSize(int width, int height) { - if (width == width_ && height == height_) - return; - - // Hide all popups on resize - HideAllPopups(); - - width_ = width; - height_ = height; - - // Resize the WPE backend -#ifdef HAVE_WPE_PLATFORM - if (wpe_toplevel_ != nullptr) { - wpe_toplevel_resize(wpe_toplevel_, width_, height_); - } -#elif defined(HAVE_WPE_BACKEND_LEGACY) - if (wpe_backend_ != nullptr) { - wpe_view_backend_dispatch_set_size(wpe_backend_, width_, height_); - } -#endif -} - -void InAppWebView::setScaleFactor(double scale_factor) { - if (scale_factor == scale_factor_) - return; - scale_factor_ = scale_factor; - - // WPE uses device scale factor -#ifdef HAVE_WPE_PLATFORM - // WPEPlatform: Notify the toplevel about scale changes - // This is needed for proper HiDPI rendering when scale changes dynamically - if (wpe_toplevel_ != nullptr) { - wpe_toplevel_scale_changed(wpe_toplevel_, scale_factor_); - } -#endif -#ifdef HAVE_WPE_BACKEND_LEGACY - if (wpe_backend_ != nullptr) { - wpe_view_backend_dispatch_set_device_scale_factor(wpe_backend_, scale_factor_); - } -#endif -} - -// === Activity State Management (like Cog browser) === - -void InAppWebView::setFocused(bool focused) { - if (focused == is_focused_) - return; - is_focused_ = focused; - - // Hide all popups when WebView loses focus - if (!focused) { - HideAllPopups(); - } - -#ifdef HAVE_WPE_PLATFORM - // WPEPlatform: Use wpe_view_focus_in/out API - if (wpe_view_ != nullptr) { - if (focused) { - wpe_view_focus_in(wpe_view_); - } else { - wpe_view_focus_out(wpe_view_); - } - } -#elif defined(HAVE_WPE_BACKEND_LEGACY) - if (wpe_backend_ != nullptr) { - if (focused) { - // Add focused state - also ensure visible and in_window are set - wpe_view_backend_add_activity_state(wpe_backend_, wpe_view_activity_state_focused); - wpe_view_backend_add_activity_state(wpe_backend_, wpe_view_activity_state_visible); - wpe_view_backend_add_activity_state(wpe_backend_, wpe_view_activity_state_in_window); - } else { - // Remove only the focused state, keep visible and in_window so the webview - // continues to render and process basic events - wpe_view_backend_remove_activity_state(wpe_backend_, wpe_view_activity_state_focused); - } - } -#endif -} - -void InAppWebView::setVisible(bool visible) { - if (visible == is_visible_) - return; - is_visible_ = visible; - -#ifdef HAVE_WPE_PLATFORM - // WPEPlatform: Use wpe_view_set_visible and map/unmap - if (wpe_view_ != nullptr) { - wpe_view_set_visible(wpe_view_, visible); - if (visible) { - wpe_view_map(wpe_view_); - } else { - wpe_view_unmap(wpe_view_); - } - } -#elif defined(HAVE_WPE_BACKEND_LEGACY) - if (wpe_backend_ != nullptr) { - if (visible) { - wpe_view_backend_add_activity_state(wpe_backend_, wpe_view_activity_state_visible); - wpe_view_backend_add_activity_state(wpe_backend_, wpe_view_activity_state_in_window); - } else { - wpe_view_backend_remove_activity_state(wpe_backend_, wpe_view_activity_state_visible); - wpe_view_backend_remove_activity_state(wpe_backend_, wpe_view_activity_state_in_window); - } - } -#endif -} - -uint32_t InAppWebView::getActivityState() const { -#ifdef HAVE_WPE_BACKEND_LEGACY - if (wpe_backend_ != nullptr) { - return wpe_view_backend_get_activity_state(wpe_backend_); - } -#endif - // WPEPlatform doesn't expose activity state in the same way - return 0; -} - -// === Refresh Rate Management === - -void InAppWebView::setTargetRefreshRate(uint32_t rate) { - target_refresh_rate_ = rate; -#ifdef HAVE_WPE_PLATFORM - if (wpe_view_ != nullptr) { - WPEScreen* screen = wpe_view_get_screen(wpe_view_); - if (screen != nullptr) { - wpe_screen_set_refresh_rate(screen, static_cast(rate)); - } - } -#endif -#ifdef HAVE_WPE_BACKEND_LEGACY - if (wpe_backend_ != nullptr) { - wpe_view_backend_set_target_refresh_rate(wpe_backend_, rate); - } -#endif -} - -uint32_t InAppWebView::getTargetRefreshRate() const { -#ifdef HAVE_WPE_PLATFORM - if (wpe_view_ != nullptr) { - WPEScreen* screen = wpe_view_get_screen(wpe_view_); - if (screen != nullptr) { - int refreshRate = wpe_screen_get_refresh_rate(screen); - if (refreshRate > 0) { - return static_cast(refreshRate); - } - } - } -#endif -#ifdef HAVE_WPE_BACKEND_LEGACY - if (wpe_backend_ != nullptr) { - return wpe_view_backend_get_target_refresh_rate(wpe_backend_); - } -#endif - return target_refresh_rate_; -} - -// === Screen Scale Management === - -double InAppWebView::getScreenScale() const { -#ifdef HAVE_WPE_PLATFORM - if (wpe_view_ != nullptr) { - WPEScreen* screen = wpe_view_get_screen(wpe_view_); - if (screen != nullptr) { - return wpe_screen_get_scale(screen); - } - } -#endif - // Legacy backend doesn't have screen scale API - return 1.0; -} - -void InAppWebView::setScreenScale(double scale) { -#ifdef HAVE_WPE_PLATFORM - if (wpe_view_ != nullptr) { - WPEScreen* screen = wpe_view_get_screen(wpe_view_); - if (screen != nullptr) { - wpe_screen_set_scale(screen, scale); - } - } -#endif - // Legacy backend doesn't have screen scale API -} - -// === Visibility Management === - -bool InAppWebView::isVisible() const { -#ifdef HAVE_WPE_PLATFORM - if (wpe_view_ != nullptr) { - return wpe_view_get_visible(wpe_view_); - } -#endif - // Legacy backend: return cached visibility state - return is_visible_; -} - -// === Fullscreen Control === - -void InAppWebView::requestEnterFullscreen() { -#ifdef HAVE_WPE_BACKEND_LEGACY - if (wpe_backend_ != nullptr) { - wpe_view_backend_dispatch_request_enter_fullscreen(wpe_backend_); - } -#endif - // Note: WPEPlatform uses WebKit enter-fullscreen/leave-fullscreen signals -} - -void InAppWebView::requestExitFullscreen() { -#ifdef HAVE_WPE_BACKEND_LEGACY - if (wpe_backend_ != nullptr) { - wpe_view_backend_dispatch_request_exit_fullscreen(wpe_backend_); - } -#endif - // Note: WPEPlatform uses WebKit enter-fullscreen/leave-fullscreen signals -} - -// === Pointer Lock Support (for games/immersive apps) === - -void InAppWebView::setPointerLockHandler(std::function handler) { - pointer_lock_handler_ = std::move(handler); - -#ifdef HAVE_WPE_BACKEND_LEGACY - if (wpe_backend_ != nullptr) { - wpe_view_backend_set_pointer_lock_handler( - wpe_backend_, - [](void* data, bool lock) -> bool { - auto* self = static_cast(data); - return self->OnPointerLockRequest(lock); - }, - this); - } -#endif - // Note: WPEPlatform uses wpe_view_lock_pointer/unlock_pointer APIs -} - -bool InAppWebView::OnPointerLockRequest(bool lock) { - if (pointer_lock_handler_) { - bool result = pointer_lock_handler_(lock); - if (result) { - pointer_locked_ = lock; - } - return result; - } - // Default: allow pointer lock - pointer_locked_ = lock; - return true; -} - -bool InAppWebView::requestPointerLock() { -#ifdef HAVE_WPE_PLATFORM - if (wpe_view_ != nullptr) { - bool result = wpe_view_lock_pointer(wpe_view_); - if (result) { - pointer_locked_ = true; - } - return result; - } -#elif defined(HAVE_WPE_BACKEND_LEGACY) - if (wpe_backend_ != nullptr) { - bool result = wpe_view_backend_request_pointer_lock(wpe_backend_); - if (result) { - pointer_locked_ = true; - } - return result; - } -#endif - return false; -} - -bool InAppWebView::requestPointerUnlock() { -#ifdef HAVE_WPE_PLATFORM - if (wpe_view_ != nullptr) { - bool result = wpe_view_unlock_pointer(wpe_view_); - if (result) { - pointer_locked_ = false; - } - return result; - } -#elif defined(HAVE_WPE_BACKEND_LEGACY) - if (wpe_backend_ != nullptr) { - bool result = wpe_view_backend_request_pointer_unlock(wpe_backend_); - if (result) { - pointer_locked_ = false; - } - return result; - } -#endif - return false; -} - -// === DOM Fullscreen Handler (like Cog browser on_dom_fullscreen_request) === - -bool InAppWebView::OnDomFullscreenRequest(bool fullscreen) { - // This is called when JavaScript requests fullscreen via Element.requestFullscreen() - // or exits via Document.exitFullscreen() - - if (waiting_fullscreen_notify_) { - // Already processing a fullscreen transition - return false; - } - - if (fullscreen == is_fullscreen_) { - // Already in the requested state - dispatch the event immediately - // This handles cases where DOM fullscreen requests are mixed with - // system fullscreen commands -#ifdef HAVE_WPE_BACKEND_LEGACY - if (wpe_backend_ != nullptr) { - if (is_fullscreen_) { - wpe_view_backend_dispatch_did_enter_fullscreen(wpe_backend_); - } else { - wpe_view_backend_dispatch_did_exit_fullscreen(wpe_backend_); - } - } -#endif - return true; - } - - waiting_fullscreen_notify_ = true; - is_fullscreen_ = fullscreen; - - // Notify the Dart side about the fullscreen request - // The Dart side should handle the actual fullscreen transition - if (channel_delegate_) { - if (fullscreen) { - channel_delegate_->onEnterFullscreen(); - } else { - channel_delegate_->onExitFullscreen(); - } - } - - // Dispatch the fullscreen state to WPE -#ifdef HAVE_WPE_BACKEND_LEGACY - if (wpe_backend_ != nullptr) { - if (fullscreen) { - wpe_view_backend_dispatch_did_enter_fullscreen(wpe_backend_); - } else { - wpe_view_backend_dispatch_did_exit_fullscreen(wpe_backend_); - } - } -#endif - - waiting_fullscreen_notify_ = false; - - return true; -} - -// === Input Handling === - -void InAppWebView::SetTextureOffset(double x, double y) { - texture_offset_x_ = x; - texture_offset_y_ = y; -} - -void InAppWebView::SetCursorPos(double x, double y) { - // Store logical coordinates - cursor_x_ = x; - cursor_y_ = y; - -#ifdef HAVE_WPE_PLATFORM - // Send pointer motion event using WPEPlatform API - if (wpe_view_ != nullptr) { - // Include button_state_ in modifiers so dragging (text selection) works correctly - WPEModifiers modifiers = static_cast(current_modifiers_ | button_state_); - WPEEvent* event = wpe_event_pointer_move_new( - WPE_EVENT_POINTER_MOVE, - wpe_view_, - WPE_INPUT_SOURCE_MOUSE, - static_cast(g_get_monotonic_time() / 1000), - modifiers, - x, // Scale to physical pixels - y, - 0.0, // delta_x (no delta for absolute position) - 0.0 // delta_y - ); - wpe_view_event(wpe_view_, event); - wpe_event_unref(event); - } -#elif defined(HAVE_WPE_BACKEND_LEGACY) - // Send pointer motion event with scaled coordinates (logical -> physical) - if (wpe_backend_ != nullptr) { - struct wpe_input_pointer_event event = {}; - event.type = wpe_input_pointer_event_type_motion; - event.time = g_get_monotonic_time() / 1000; // Convert to milliseconds - // Scale coordinates from logical to physical pixels - event.x = static_cast(x * scale_factor_); - event.y = static_cast(y * scale_factor_); - event.state = 0; // No button state change for motion events - event.modifiers = current_modifiers_ | button_state_; // Include pressed button modifiers - wpe_view_backend_dispatch_pointer_event(wpe_backend_, &event); - } -#endif -} - -void InAppWebView::SetPointerButton(int kind, int button, int clickCount) { - // Hide all popups on any button DOWN (kind=1 is Down per WpePointerEventKind enum) - if (kind == static_cast(WpePointerEventKind::Down)) { - HideAllPopups(); - } - -#ifdef HAVE_WPE_PLATFORM - if (wpe_view_ == nullptr) - return; - - // No need to scale coordinates from logical to physical pixels as WPEPlatform handles this internally. - double scaled_x = cursor_x_; - double scaled_y = cursor_y_; - - // Map button: Flutter uses 0=none, 1=primary, 2=secondary, 3=tertiary - // WPE/GDK uses: 1=Left, 2=Middle, 3=Right - guint wpe_button; - switch (button) { - case 1: - wpe_button = 1; - break; // Primary -> Left - case 2: - wpe_button = 3; - break; // Secondary -> Right (context menu) - case 3: - wpe_button = 2; - break; // Tertiary -> Middle - default: - wpe_button = 1; - break; // Default to primary - } - - // WPEPlatform button modifier bits: WPE_MODIFIER_POINTER_BUTTON1 = 1 << 8, etc. - // Button 1 -> bit 8, Button 2 -> bit 9, Button 3 -> bit 10 - const uint32_t button_modifier_bit = 1u << (7 + wpe_button); - - guint32 time = static_cast(g_get_monotonic_time() / 1000); - WPEEventType event_type; - - switch (static_cast(kind)) { - case WpePointerEventKind::Down: - event_type = WPE_EVENT_POINTER_DOWN; - // Update button state BEFORE creating the event - button_state_ |= button_modifier_bit; - break; - case WpePointerEventKind::Up: - event_type = WPE_EVENT_POINTER_UP; - // Update button state AFTER the event (but include in modifiers) - break; - default: - // Ignore enter/leave/cancel etc for button events - return; - } - - // Include button state in modifiers for proper drag detection - WPEModifiers modifiers = static_cast(current_modifiers_ | button_state_); - - // First send a motion event to ensure WebKit has the correct cursor position - WPEEvent* motion_event = wpe_event_pointer_move_new( - WPE_EVENT_POINTER_MOVE, - wpe_view_, - WPE_INPUT_SOURCE_MOUSE, - time, - modifiers, - scaled_x, - scaled_y, - 0.0, - 0.0 - ); - wpe_view_event(wpe_view_, motion_event); - wpe_event_unref(motion_event); - - // Send button event - // CRITICAL: press_count must be 0 for UP events, only non-zero for DOWN events - // (WPEPlatform assertion: !pressCount || type == WPE_EVENT_POINTER_DOWN) - guint press_count = (event_type == WPE_EVENT_POINTER_DOWN) - ? static_cast(clickCount) - : 0; - - WPEEvent* button_event = wpe_event_pointer_button_new( - event_type, - wpe_view_, - WPE_INPUT_SOURCE_MOUSE, - time, - modifiers, - wpe_button, - scaled_x, - scaled_y, - press_count - ); - wpe_view_event(wpe_view_, button_event); - wpe_event_unref(button_event); - - // Clear button state AFTER sending the UP event - if (event_type == WPE_EVENT_POINTER_UP) { - button_state_ &= ~button_modifier_bit; - } - -#elif defined(HAVE_WPE_BACKEND_LEGACY) - if (wpe_backend_ == nullptr) - return; - - // Scale coordinates from logical to physical pixels - int scaled_x = static_cast(cursor_x_ * scale_factor_); - int scaled_y = static_cast(cursor_y_ * scale_factor_); - - // Map button: Flutter uses 0=none, 1=primary, 2=secondary, 3=tertiary - // WPE/WebKit uses: 1=Left, 2=Right, 3=Middle (see WebEventFactory.cpp) - // This is a 1:1 mapping for Flutter -> WPE - uint32_t wpe_button; - switch (button) { - case 1: - wpe_button = 1; - break; // Primary -> Left - case 2: - wpe_button = 2; - break; // Secondary -> Right (context menu) - case 3: - wpe_button = 3; - break; // Tertiary -> Middle - default: - wpe_button = 1; - break; // Default to primary - } - - // WPE button modifier bits for tracking pressed buttons in modifiers field - // See wpe_input_pointer_modifier_button* in wpe/input.h: button1=1<<20, button2=1<<21, - // button3=1<<22 - const uint32_t button_modifier_bit = 1u << (19 + wpe_button); - - // First send a motion event to ensure WebKit has the correct cursor position - // This is important because the button event needs to know where the click occurred - { - struct wpe_input_pointer_event motion_event = {}; - motion_event.type = wpe_input_pointer_event_type_motion; - motion_event.time = g_get_monotonic_time() / 1000; - motion_event.x = scaled_x; - motion_event.y = scaled_y; - motion_event.button = 0; - motion_event.state = 0; - motion_event.modifiers = current_modifiers_ | button_state_; - wpe_view_backend_dispatch_pointer_event(wpe_backend_, &motion_event); - } - - struct wpe_input_pointer_event event = {}; - event.time = g_get_monotonic_time() / 1000; - event.x = scaled_x; - event.y = scaled_y; - event.button = wpe_button; - - switch (static_cast(kind)) { - case WpePointerEventKind::Down: - event.type = wpe_input_pointer_event_type_button; - // state=1 means button is pressed (see WebEventFactory: event->state ? MouseDown : MouseUp) - event.state = 1; - button_state_ |= button_modifier_bit; - event.modifiers = current_modifiers_ | button_state_; - break; - case WpePointerEventKind::Up: - event.type = wpe_input_pointer_event_type_button; - // state=0 means button is released - event.state = 0; - button_state_ &= ~button_modifier_bit; - event.modifiers = current_modifiers_ | button_state_; - break; - default: - // Ignore enter/leave/cancel etc for button events - return; - } - - wpe_view_backend_dispatch_pointer_event(wpe_backend_, &event); -#endif -} - -void InAppWebView::SetScrollDelta(double dx, double dy) { - // Hide all popups when scrolling - HideAllPopups(); - -#ifdef HAVE_WPE_PLATFORM - if (wpe_view_ == nullptr) - return; - - // No need to scale coordinates from logical to physical pixels as WPEPlatform handles this internally. - double scaled_x = cursor_x_; - double scaled_y = cursor_y_; - - WPEModifiers modifiers = static_cast(current_modifiers_); - guint32 time = static_cast(g_get_monotonic_time() / 1000); - - // Flutter provides delta in logical pixels. - // No need to scale coordinates from logical to physical pixels as WPEPlatform handles this internally. - double delta_x = dx; - double delta_y = dy; - - WPEEvent* event = wpe_event_scroll_new( - wpe_view_, - WPE_INPUT_SOURCE_MOUSE, - time, - modifiers, - delta_x, - delta_y, - TRUE, // precise_deltas - we have exact pixel values - FALSE, // is_stop - this is not a scroll stop event - scaled_x, - scaled_y - ); - wpe_view_event(wpe_view_, event); - wpe_event_unref(event); - -#elif defined(HAVE_WPE_BACKEND_LEGACY) - if (wpe_backend_ == nullptr) - return; - - // Scale coordinates from logical to physical pixels - int scaled_x = static_cast(cursor_x_ * scale_factor_); - int scaled_y = static_cast(cursor_y_ * scale_factor_); - - // Use the 2D axis event with smooth scrolling for proper pixel-based scrolling - // The wpe_input_axis_2d_event provides x_axis and y_axis as doubles - // With wpe_input_axis_event_type_motion_smooth | wpe_input_axis_event_type_mask_2d, - // WebKit will use the raw pixel values for smooth scrolling - - struct wpe_input_axis_2d_event event = {}; - event.base.type = static_cast(wpe_input_axis_event_type_motion_smooth | - wpe_input_axis_event_type_mask_2d); - event.base.time = g_get_monotonic_time() / 1000; - event.base.x = scaled_x; - event.base.y = scaled_y; - event.base.modifiers = current_modifiers_; - - // Flutter provides delta in logical pixels, scale to physical and apply sensitivity - // The scale factor converts logical to physical pixels - event.x_axis = dx * scale_factor_; - event.y_axis = dy * scale_factor_; - - wpe_view_backend_dispatch_axis_event(wpe_backend_, &event.base); -#endif -} - -void InAppWebView::SendKeyEvent(int type, int64_t keyCode, int scanCode, int modifiers, - const std::string& characters) { - // Intercept clipboard shortcuts on key down (type=0) - // Modifiers: Control=1, Shift=2, Alt=4, Meta=8 - const bool isCtrl = (modifiers & 1) != 0; - const bool isShift = (modifiers & 2) != 0; - const bool isKeyDown = (type == 0); - - if (isCtrl && isKeyDown && webview_ != nullptr) { - // Check for clipboard and common editing shortcuts - // keyCode is XKB keysym, lowercase letters are 0x61-0x7a - switch (keyCode) { - case 0x63: // 'c' - Copy - copyToClipboard(); - return; // Don't send the key event to WebKit - case 0x78: // 'x' - Cut - cutToClipboard(); - return; - case 0x76: // 'v' - Paste (Ctrl+Shift+V = paste as plain text) - if (isShift) { - pasteAsPlainText(); - } else { - pasteFromClipboard(); - } - return; - case 0x61: // 'a' - Select All - selectAll(); - return; - case 0x7a: // 'z' - Undo (Ctrl+Shift+Z = Redo on some systems) - if (isShift) { - redo(); - } else { - undo(); - } - return; - case 0x79: // 'y' - Redo - redo(); - return; - } - } - - current_modifiers_ = static_cast(modifiers); - -#ifdef HAVE_WPE_PLATFORM - if (wpe_view_ == nullptr) - return; - - WPEModifiers wpe_modifiers = static_cast(current_modifiers_); - guint32 time = static_cast(g_get_monotonic_time() / 1000); - - // type: 0=down, 1=up, 2=repeat - WPEEventType event_type; - switch (type) { - case 0: // down - case 2: // repeat (also treated as key down in WPE) - event_type = WPE_EVENT_KEYBOARD_KEY_DOWN; - break; - case 1: // up - event_type = WPE_EVENT_KEYBOARD_KEY_UP; - break; - default: - return; - } - - WPEEvent* event = wpe_event_keyboard_new( - event_type, - wpe_view_, - WPE_INPUT_SOURCE_KEYBOARD, - time, - wpe_modifiers, - static_cast(scanCode), // hardware keycode - static_cast(keyCode) // keyval (XKB keysym) - ); - wpe_view_event(wpe_view_, event); - wpe_event_unref(event); - -#elif defined(HAVE_WPE_BACKEND_LEGACY) - if (wpe_backend_ == nullptr) - return; - - struct wpe_input_keyboard_event event = {}; - event.time = g_get_monotonic_time() / 1000; - event.key_code = static_cast(keyCode); - event.hardware_key_code = static_cast(scanCode); - // type: 0=down, 1=up, 2=repeat - event.pressed = (type == 0 || type == 2); - - // Modifiers from Dart are already in WPE format: - // Control=1, Shift=2, Alt=4, Meta=8 - event.modifiers = current_modifiers_; - - wpe_view_backend_dispatch_keyboard_event(wpe_backend_, &event); -#endif -} - -void InAppWebView::SendTouchEvent( - int type, int id, double x, double y, - const std::vector>& touchPoints) { -#ifdef HAVE_WPE_PLATFORM - if (wpe_view_ == nullptr) - return; - - WPEModifiers modifiers = static_cast(current_modifiers_); - guint32 time = static_cast(g_get_monotonic_time() / 1000); - - // Map Dart touch event types to WPE types - // Dart: 0=down, 1=up, 2=move, 3=cancel - WPEEventType event_type; - switch (type) { - case 0: - event_type = WPE_EVENT_TOUCH_DOWN; - break; - case 1: - event_type = WPE_EVENT_TOUCH_UP; - break; - case 2: - event_type = WPE_EVENT_TOUCH_MOVE; - break; - case 3: - event_type = WPE_EVENT_TOUCH_CANCEL; - break; - default: - return; - } - - // For WPEPlatform, we send individual touch events for each point. - // The main touch point is the one that triggered this event. - // No need to scale coordinates from logical to physical pixels as WPEPlatform handles this internally. - double scaled_x = x; - double scaled_y = y; - - WPEEvent* event = wpe_event_touch_new( - event_type, - wpe_view_, - WPE_INPUT_SOURCE_TOUCHSCREEN, - time, - modifiers, - static_cast(id), - scaled_x, - scaled_y - ); - wpe_view_event(wpe_view_, event); - wpe_event_unref(event); - -#elif defined(HAVE_WPE_BACKEND_LEGACY) - if (wpe_backend_ == nullptr) - return; - - // Map Dart touch event types to WPE types - // Dart: 0=down, 1=up, 2=move, 3=cancel - // WPE: wpe_input_touch_event_type_down=1, up=3, motion=2 - enum wpe_input_touch_event_type wpe_type; - switch (type) { - case 0: - wpe_type = wpe_input_touch_event_type_down; - break; - case 1: - wpe_type = wpe_input_touch_event_type_up; - break; - case 2: - wpe_type = wpe_input_touch_event_type_motion; - break; - default: - wpe_type = wpe_input_touch_event_type_null; - break; // cancel - } - - // Build the raw touchpoints array - std::vector raw_points; - raw_points.reserve(touchPoints.size()); - - for (const auto& point : touchPoints) { - struct wpe_input_touch_event_raw raw = {}; - raw.id = std::get<0>(point); - raw.x = static_cast(std::get<1>(point) * scale_factor_); - raw.y = static_cast(std::get<2>(point) * scale_factor_); - - // Map point type - int pointType = std::get<3>(point); - switch (pointType) { - case 0: - raw.type = wpe_input_touch_event_type_down; - break; - case 1: - raw.type = wpe_input_touch_event_type_up; - break; - case 2: - raw.type = wpe_input_touch_event_type_motion; - break; - default: - raw.type = wpe_input_touch_event_type_null; - break; - } - raw.time = g_get_monotonic_time() / 1000; - - raw_points.push_back(raw); - } - - // Build the touch event - struct wpe_input_touch_event event = {}; - event.touchpoints = raw_points.data(); - event.touchpoints_length = raw_points.size(); - event.type = wpe_type; - event.id = id; - event.time = g_get_monotonic_time() / 1000; - event.modifiers = current_modifiers_; - - wpe_view_backend_dispatch_touch_event(wpe_backend_, &event); -#endif -} - -// === Pixel Buffer Access === - -size_t InAppWebView::GetPixelBufferSize(uint32_t* out_width, uint32_t* out_height) const { - // With WPE + FDO, we typically use DMA-BUF export instead of CPU copy - // This is a fallback for when DMA-BUF is not available - std::lock_guard lock(buffer_swap_mutex_); - - size_t read_idx = read_buffer_index_.load(std::memory_order_acquire); - const auto& buffer = pixel_buffers_[read_idx]; - - if (out_width) - *out_width = static_cast(buffer.width); - if (out_height) - *out_height = static_cast(buffer.height); - - return buffer.data.size(); -} - -bool InAppWebView::CopyPixelBufferTo(uint8_t* dst, size_t dst_size, uint32_t* out_width, - uint32_t* out_height) const { - std::lock_guard lock(buffer_swap_mutex_); - - size_t read_idx = read_buffer_index_.load(std::memory_order_acquire); - const auto& buffer = pixel_buffers_[read_idx]; - - if (buffer.data.empty() || dst_size < buffer.data.size()) { - return false; - } - - // Use SIMD-optimized memory copy for better performance - FastMemcpy(dst, buffer.data.data(), buffer.data.size()); - - if (out_width) - *out_width = static_cast(buffer.width); - if (out_height) - *out_height = static_cast(buffer.height); - - return true; -} - -bool InAppWebView::HasDmaBufExport() const { -#ifdef HAVE_WPE_PLATFORM - std::lock_guard lock(wpe_buffer_mutex_); - return current_egl_image_ != nullptr; -#elif defined(HAVE_WPE_BACKEND_LEGACY) - std::lock_guard lock(exported_image_mutex_); - return exported_image_ != nullptr; -#else - return false; -#endif -} - -bool InAppWebView::GetDmaBufFd(int* fd, uint32_t* stride, uint32_t* width, uint32_t* height) const { -#ifdef HAVE_WPE_BACKEND_LEGACY - std::lock_guard lock(exported_image_mutex_); - if (exported_image_ == nullptr) { - return false; - } - - // Get DMA-BUF file descriptor from the exported image - // This allows zero-copy sharing with Flutter's texture system - // Note: The actual API depends on the WPE version - // This is a simplified version - - if (width) - *width = static_cast(width_); - if (height) - *height = static_cast(height_); - - // In a real implementation, you'd get the DMA-BUF FD from the EGL image - // For now, return false to indicate not implemented - return false; -#else - // WPEPlatform uses a different rendering model - return false; -#endif -} - -void* InAppWebView::GetCurrentEglImage(uint32_t* out_width, uint32_t* out_height) const { -#ifdef HAVE_WPE_PLATFORM - // WPEPlatform: Return the EGL image from our buffer-rendered callback - std::lock_guard lock(wpe_buffer_mutex_); - - if (current_egl_image_ == nullptr) { - if (out_width) - *out_width = 0; - if (out_height) - *out_height = 0; - return nullptr; - } - - if (out_width) - *out_width = current_buffer_width_; - if (out_height) - *out_height = current_buffer_height_; - - return current_egl_image_; - -#elif defined(HAVE_WPE_BACKEND_LEGACY) - // Protect exported_image_ access - OnExportDmaBuf may be called from WPE's thread - std::lock_guard lock(exported_image_mutex_); - - if (exported_image_ == nullptr) { - if (out_width) - *out_width = 0; - if (out_height) - *out_height = 0; - return nullptr; - } - - // Get dimensions from the exported image - uint32_t img_width = wpe_fdo_egl_exported_image_get_width(exported_image_); - uint32_t img_height = wpe_fdo_egl_exported_image_get_height(exported_image_); - - if (out_width) - *out_width = img_width; - if (out_height) - *out_height = img_height; - - // Return the EGL image handle (EGLImageKHR) - return wpe_fdo_egl_exported_image_get_egl_image(exported_image_); -#else - // No backend available - if (out_width) - *out_width = 0; - if (out_height) - *out_height = 0; - return nullptr; -#endif -} - -void InAppWebView::SetOnFrameAvailable(std::function callback) { - on_frame_available_ = std::move(callback); - -#ifdef HAVE_WPE_PLATFORM - // Force WPE to render a new frame by triggering a resize. - // This is needed because: - // 1. The first frame may have been rendered before this callback was set - // 2. We release buffers immediately in OnWpePlatformBufferRendered, so - // old EGL images may be invalid - // 3. A resize notification causes WPE to re-render with the current content - // - // We use g_idle_add to defer this slightly, ensuring the texture registration - // is complete before we trigger the new frame. - if (on_frame_available_ && wpe_toplevel_ != nullptr) { - WPEToplevel* toplevel = wpe_toplevel_; - int w = width_; - int h = height_; - g_idle_add_full(G_PRIORITY_HIGH, [](gpointer user_data) -> gboolean { - auto* data = static_cast*>(user_data); - WPEToplevel* tl = std::get<0>(*data); - int width = std::get<1>(*data); - int height = std::get<2>(*data); - // Trigger a resize to force WPE to render a new frame - if (tl != nullptr) { - wpe_toplevel_resize(tl, width, height); - } - delete data; - return G_SOURCE_REMOVE; - }, new std::tuple(toplevel, w, h), nullptr); - } -#endif -} - -void InAppWebView::SetOnCursorChanged(std::function callback) { - on_cursor_changed_ = std::move(callback); -} - -void InAppWebView::SetOnProgressChanged(std::function callback) { - on_progress_changed_ = std::move(callback); -} - -void InAppWebView::SetOnNavigationStateChanged(std::function callback) { - on_navigation_state_changed_ = std::move(callback); -} - -void InAppWebView::OnShouldOverrideUrlLoadingDecision(int64_t decision_id, bool allow) { - auto it = pending_policy_decisions_.find(decision_id); - if (it == pending_policy_decisions_.end()) { - return; - } - - WebKitPolicyDecision* decision = it->second; - if (allow) { - webkit_policy_decision_use(decision); - } else { - webkit_policy_decision_ignore(decision); - } - - g_object_unref(decision); - pending_policy_decisions_.erase(it); -} - -// === WebKit Signal Handlers === - -void InAppWebView::OnLoadChanged(WebKitWebView* web_view, WebKitLoadEvent load_event, - gpointer user_data) { - auto* self = static_cast(user_data); - - // Check if WebView is still valid (WebProcess may have crashed) - if (!WEBKIT_IS_WEB_VIEW(web_view)) { - return; - } - - if (self->channel_delegate_ == nullptr) { - return; - } - - switch (load_event) { - case WEBKIT_LOAD_STARTED: { - // Hide all popups when a new page starts loading - self->HideAllPopups(); - - std::string current_url = self->getUrl().value_or(""); - self->channel_delegate_->onLoadStart(current_url); - break; - } - case WEBKIT_LOAD_REDIRECTED: - // Redirects are handled internally by WebKit - break; - case WEBKIT_LOAD_COMMITTED: - // Notify that page content is starting to be visible - self->channel_delegate_->onPageCommitVisible(self->getUrl().value_or("")); - break; - case WEBKIT_LOAD_FINISHED: - self->channel_delegate_->onLoadStop(self->getUrl().value_or("")); - break; - default: - break; - } -} - -gboolean InAppWebView::OnDecidePolicy(WebKitWebView* web_view, WebKitPolicyDecision* decision, - WebKitPolicyDecisionType decision_type, gpointer user_data) { - auto* self = static_cast(user_data); - - // Handle response policy decisions (for onNavigationResponse and downloads) - if (decision_type == WEBKIT_POLICY_DECISION_TYPE_RESPONSE) { - auto* response_decision = WEBKIT_RESPONSE_POLICY_DECISION(decision); - - // Get response information for onNavigationResponse - WebKitURIResponse* response = webkit_response_policy_decision_get_response(response_decision); - gboolean is_mime_type_supported = webkit_response_policy_decision_is_mime_type_supported(response_decision); - gboolean is_main_frame = webkit_response_policy_decision_is_main_frame_main_resource(response_decision); - - const gchar* uri = webkit_uri_response_get_uri(response); - const gchar* mimeType = webkit_uri_response_get_mime_type(response); - gint64 contentLength = webkit_uri_response_get_content_length(response); - guint statusCode = webkit_uri_response_get_status_code(response); - - // If channel_delegate exists and settings permit, send onNavigationResponse event - if (self->channel_delegate_ && self->settings_ && self->settings_->useOnNavigationResponse) { - // Keep decision alive for async callback - g_object_ref(decision); - - auto callback = std::make_unique(); - - callback->nonNullSuccess = [self, decision, is_mime_type_supported](int action) -> bool { - // NavigationResponseAction: CANCEL=0, ALLOW=1, DOWNLOAD=2 - switch (action) { - case 0: // CANCEL - webkit_policy_decision_ignore(decision); - break; - case 2: // DOWNLOAD - webkit_policy_decision_download(decision); - break; - case 1: // ALLOW (default) - default: - if (!is_mime_type_supported && self->settings_ && self->settings_->useOnDownloadStart) { - // WebKit can't display this - convert to download - webkit_policy_decision_download(decision); - } else { - webkit_policy_decision_use(decision); - } - break; - } - g_object_unref(decision); - return false; // Don't run defaultBehaviour - }; - - callback->defaultBehaviour = [decision, is_mime_type_supported, self](const std::optional& action) { - // Default: allow navigation (or download if MIME not supported and download enabled) - if (!is_mime_type_supported && self->settings_ && self->settings_->useOnDownloadStart) { - webkit_policy_decision_download(decision); - } else { - webkit_policy_decision_use(decision); - } - g_object_unref(decision); - }; - - callback->error = [decision, is_mime_type_supported, self](const std::string& code, const std::string& message) { - debugLog("Error in onNavigationResponse: " + code + " - " + message); - // On error, allow navigation - if (!is_mime_type_supported && self->settings_ && self->settings_->useOnDownloadStart) { - webkit_policy_decision_download(decision); - } else { - webkit_policy_decision_use(decision); - } - g_object_unref(decision); - }; - - self->channel_delegate_->onNavigationResponse( - uri != nullptr ? std::string(uri) : "", - mimeType != nullptr ? std::optional(mimeType) : std::nullopt, - contentLength, - static_cast(statusCode), - is_main_frame != FALSE, - is_mime_type_supported != FALSE, - std::move(callback)); - - return TRUE; // We're handling this asynchronously - } - - // Fallback: check if the response should trigger a download (no onNavigationResponse handler) - // This happens when: - // 1. Content-Disposition header is "attachment" - // 2. WebKit can't display the MIME type - if (!is_mime_type_supported) { - // WebKit can't display this MIME type - convert to download - // This will trigger the download-started signal on NetworkSession - if (self->settings_ && self->settings_->useOnDownloadStart) { - webkit_policy_decision_download(decision); - return TRUE; - } - } - - return FALSE; // Let WebKit handle the response normally - } - - if (decision_type != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION) { - return FALSE; // Let WebKit handle other decision types - } - - auto* nav_decision = WEBKIT_NAVIGATION_POLICY_DECISION(decision); - auto* nav_action = webkit_navigation_policy_decision_get_navigation_action(nav_decision); - auto* request = webkit_navigation_action_get_request(nav_action); - const gchar* uri = webkit_uri_request_get_uri(request); - - if (self->settings_ && self->settings_->useShouldOverrideUrlLoading) { - if (self->channel_delegate_) { - int64_t decision_id = self->next_decision_id_++; - g_object_ref(decision); - self->pending_policy_decisions_[decision_id] = decision; - - // Best-effort main frame detection: frame name is usually null/empty for main frame. - bool is_for_main_frame = true; - const gchar* frame_name = webkit_navigation_action_get_frame_name(nav_action); - if (frame_name != nullptr && frame_name[0] != '\0') { - is_for_main_frame = false; - } - - // Create URLRequest - auto urlRequest = std::make_shared( - uri != nullptr ? std::optional(uri) : std::nullopt, - std::optional("GET"), - std::nullopt, // headers - std::nullopt // body - ); - - // Map WebKit navigation type to our enum - WebKitNavigationType nav_type = webkit_navigation_action_get_navigation_type(nav_action); - std::optional navActionType; - switch (nav_type) { - case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED: - navActionType = NavigationActionType::linkActivated; - break; - case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD: - navActionType = NavigationActionType::backForward; - break; - case WEBKIT_NAVIGATION_TYPE_RELOAD: - navActionType = NavigationActionType::reload; - break; - default: - navActionType = NavigationActionType::other; - break; - } - - // Create NavigationAction - auto navigationAction = std::make_shared( - urlRequest, is_for_main_frame, - std::nullopt, // isRedirect - not easily available in WebKit - navActionType); - - // Create callback to handle the response - auto callback = std::make_unique(); - - // CRITICAL: Set error handler to prevent navigation from being blocked on channel errors - // Allow navigation on error to prevent page from being stuck - callback->error = [self, decision_id](const std::string& code, const std::string& message) { - g_warning("shouldOverrideUrlLoading channel error: %s - %s", code.c_str(), message.c_str()); - // Allow navigation on error to prevent page from being stuck - self->OnShouldOverrideUrlLoadingDecision(decision_id, true); - }; - - callback->defaultBehaviour = - [self, decision_id](const std::optional result) { - bool allow = result.has_value() && result.value() == NavigationActionPolicy::allow; - self->OnShouldOverrideUrlLoadingDecision(decision_id, allow); - }; - - // Notify Dart side with callback - self->channel_delegate_->shouldOverrideUrlLoading(navigationAction, std::move(callback)); - - return TRUE; // We're handling this asynchronously - } - } - - return FALSE; // Let WebKit proceed with navigation -} - -void InAppWebView::OnNotifyEstimatedLoadProgress(GObject* object, GParamSpec* pspec, - gpointer user_data) { - auto* self = static_cast(user_data); - - double progress = webkit_web_view_get_estimated_load_progress(WEBKIT_WEB_VIEW(object)); - int progress_percent = static_cast(progress * 100); - - // Notify Dart via channel delegate - if (self->channel_delegate_) { - self->channel_delegate_->onProgressChanged(progress_percent); - } - - // Notify native progress callback (for InAppBrowser) - if (self->on_progress_changed_) { - self->on_progress_changed_(progress); - } -} - -void InAppWebView::OnNotifyTitle(GObject* object, GParamSpec* pspec, gpointer user_data) { - auto* self = static_cast(user_data); - if (self->channel_delegate_ == nullptr) - return; - - const gchar* title = webkit_web_view_get_title(WEBKIT_WEB_VIEW(object)); - if (title != nullptr) { - self->channel_delegate_->onTitleChanged(std::string(title)); - } -} - -void InAppWebView::OnNotifyUri(GObject* object, GParamSpec* pspec, gpointer user_data) { - auto* self = static_cast(user_data); - if (self->channel_delegate_ == nullptr) - return; - - const gchar* uri = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(object)); - std::optional url = uri ? std::optional(uri) : std::nullopt; - - // isReload is not easily detectable - pass false by default - self->channel_delegate_->onUpdateVisitedHistory(url, false); -} - -gboolean InAppWebView::OnLoadFailed(WebKitWebView* web_view, WebKitLoadEvent load_event, - gchar* failing_uri, GError* error, gpointer user_data) { - auto* self = static_cast(user_data); - - if (self->channel_delegate_ == nullptr) - return FALSE; - - // Create WebResourceRequest for the failing URL - auto request = std::make_shared( - failing_uri ? std::optional(failing_uri) : std::nullopt, - std::optional("GET"), // Default method - std::nullopt, // headers - std::optional(true) // isForMainFrame - load failures are typically main frame - ); - - // Create WebResourceError from GError - auto webError = - std::make_shared(error ? std::string(error->message) : "Unknown error", - error ? static_cast(error->code) : -1); - - self->channel_delegate_->onReceivedError(request, webError); - - return FALSE; -} - -gboolean InAppWebView::OnLoadFailedWithTlsErrors(WebKitWebView* web_view, gchar* failing_uri, - GTlsCertificate* certificate, - GTlsCertificateFlags errors, gpointer user_data) { - auto* self = static_cast(user_data); - - if (!self->channel_delegate_) { - return FALSE; - } - - // Create the challenge from TLS error info - auto challenge = ServerTrustChallenge::fromTlsError( - std::string(failing_uri != nullptr ? failing_uri : ""), - certificate, errors); - - // Keep a reference to the certificate and web view for later use - g_object_ref(certificate); - g_object_ref(web_view); - - auto callback = std::make_unique(); - callback->nonNullSuccess = [web_view, failing_uri, certificate]( - const ServerTrustAuthResponse& response) -> bool { - if (response.action == ServerTrustAuthResponseAction::PROCEED) { - // Allow the certificate for this host - // Extract host from failing_uri - std::string host = get_host_from_url(std::string(failing_uri != nullptr ? failing_uri : "")); - if (!host.empty()) { - // Get the network session from the web view - WebKitNetworkSession* network_session = webkit_web_view_get_network_session(web_view); - webkit_network_session_allow_tls_certificate_for_host(network_session, certificate, host.c_str()); - // Reload the page to retry with the allowed certificate - webkit_web_view_reload(web_view); - } - } - g_object_unref(certificate); - g_object_unref(web_view); - return false; - }; - - callback->defaultBehaviour = [certificate, web_view](const std::optional& response) { - // Default: cancel the request (do nothing, WebKit will handle the error) - g_object_unref(certificate); - g_object_unref(web_view); - }; - - callback->error = [certificate, web_view](const std::string& code, const std::string& message) { - debugLog("Error in onReceivedServerTrustAuthRequest: " + code + " - " + message); - g_object_unref(certificate); - g_object_unref(web_view); - }; - - self->channel_delegate_->onReceivedServerTrustAuthRequest(std::move(challenge), std::move(callback)); - - // Return TRUE to indicate we're handling this asynchronously - return TRUE; -} - -void InAppWebView::OnCloseRequest(WebKitWebView* web_view, gpointer user_data) { - auto* self = static_cast(user_data); - if (self->channel_delegate_) { - self->channel_delegate_->onCloseWindow(); - } -} - -// WPE WebKit create signal handler - returns WebKitWebView* (not GtkWidget*) -// -// In WPE WebKit, creating a new WebView requires a WebKitWebViewBackend which -// is tightly coupled with the WPE FDO exportable pipeline. Unlike WebKitGTK, -// we cannot easily create a related view without the full backend setup. -// -// Multi-Window Support -// -// When JavaScript calls window.open() or a link has target="_blank", WebKit emits -// the "create" signal. We must create a new WebView that shares the web process -// with the parent (for session/cookies) and return it to WebKit. -// -// The pattern used here: -// 1. Get a window ID from the manager -// 2. Create a new InAppWebView with the parent webview as "related view" -// 3. Store the InAppWebView in windowWebViews for later attachment by Dart -// 4. Notify Dart via onCreateWindow callback -// 5. Return the new WebKitWebView* to WebKit (so window.open() returns a real window) -// -// If Dart doesn't handle it, the default behaviour loads the URL in the parent view. -WebKitWebView* InAppWebView::OnCreateWebView(WebKitWebView* web_view, - WebKitNavigationAction* navigation_action, - gpointer user_data) { - auto* self = static_cast(user_data); - - // Check if JavaScript can open windows automatically - if (!self->settings_ || !self->settings_->javaScriptCanOpenWindowsAutomatically) { - // Default to allowing navigation in current window - WebKitURIRequest* request = webkit_navigation_action_get_request(navigation_action); - if (request != nullptr) { - const gchar* uri = webkit_uri_request_get_uri(request); - if (uri != nullptr && self->webview_ != nullptr) { - webkit_web_view_load_uri(self->webview_, uri); - } - } - return nullptr; - } - - // Get window ID from manager - int64_t windowId = 0; - if (self->manager_ != nullptr) { - windowId = self->manager_->GetNextWindowId(); - } else { - // Fallback to static counter if no manager - static int64_t window_autoincrement_id = 0; - windowId = ++window_autoincrement_id; - } - - // Get the URL from the navigation action - WebKitURIRequest* request = webkit_navigation_action_get_request(navigation_action); - std::optional url_to_load; - if (request != nullptr) { - const gchar* uri = webkit_uri_request_get_uri(request); - if (uri != nullptr) { - url_to_load = std::string(uri); - } - } - - // Create a new InAppWebView that shares the web process with the parent - // This is the key difference from the old implementation - we actually create - // a real WebView that WebKit can use for the popup window - InAppWebViewCreationParams windowParams; - windowParams.id = windowId; - windowParams.gtkWindow = self->gtk_window_; - windowParams.flView = self->fl_view_; // Pass FlView for focus restoration - windowParams.manager = self->manager_; - windowParams.initialSettings = self->settings_; // Share parent settings - windowParams.windowId = windowId; - windowParams.relatedWebView = self->webview_; // Share web process with parent - - // Create the new InAppWebView for the popup window - auto windowWebView = std::make_unique( - self->registrar_, nullptr, windowId, windowParams); - - // Get the WebKitWebView* to return to WebKit BEFORE moving the unique_ptr - WebKitWebView* newWebKitWebView = windowWebView->webview(); - - if (newWebKitWebView == nullptr) { - errorLog("InAppWebView::OnCreateWebView: Failed to create popup WebView"); - // Fall back to loading in parent - if (url_to_load.has_value() && self->webview_ != nullptr) { - webkit_web_view_load_uri(self->webview_, url_to_load.value().c_str()); - } - return nullptr; - } - - // Store the InAppWebView in the manager for later attachment by Dart - if (self->manager_ != nullptr) { - auto transport = std::make_unique(std::move(windowWebView), url_to_load); - self->manager_->AddWindowWebView(windowId, std::move(transport)); - } - - auto createWindowAction = - std::make_unique(navigation_action, windowId, nullptr); - - auto callback = std::make_unique(); - - callback->nonNullSuccess = [](bool handledByClient) { return !handledByClient; }; - - // Capture for cleanup on default behaviour - auto* manager = self->manager_; - auto* parentWebview = self->webview_; - std::string captured_url = url_to_load.value_or(""); - int64_t capturedWindowId = windowId; - - callback->defaultBehaviour = [manager, parentWebview, captured_url, capturedWindowId](std::optional) { - // If the Dart side doesn't handle the window, clean up and load in current view - if (manager != nullptr) { - manager->RemoveWindowWebView(capturedWindowId); - } - // Load the URL in the parent view instead - if (!captured_url.empty() && parentWebview != nullptr) { - webkit_web_view_load_uri(parentWebview, captured_url.c_str()); - } - }; - - if (self->channel_delegate_) { - self->channel_delegate_->onCreateWindow(std::move(createWindowAction), std::move(callback)); - } else { - callback->defaultBehaviour(std::nullopt); - } - - // Return the new WebKitWebView* to WebKit - // This allows window.open() to return a real window object to JavaScript - return newWebKitWebView; -} - -gboolean InAppWebView::OnScriptDialog(WebKitWebView* web_view, WebKitScriptDialog* dialog, - gpointer user_data) { - auto* self = static_cast(user_data); - - WebKitScriptDialogType dialogType = webkit_script_dialog_get_dialog_type(dialog); - const gchar* message = webkit_script_dialog_get_message(dialog); - - if (!self->channel_delegate_) { - return FALSE; // Use default WebKit dialog handling - } - - std::optional url; - const gchar* uri = webkit_web_view_get_uri(web_view); - if (uri != nullptr) { - url = std::string(uri); - } - - std::string messageStr = message ? std::string(message) : ""; - - // Keep a reference to the dialog for async handling - webkit_script_dialog_ref(dialog); - int64_t dialogId = self->next_dialog_id_++; - self->pending_script_dialogs_[dialogId] = dialog; - - switch (dialogType) { - case WEBKIT_SCRIPT_DIALOG_ALERT: { - auto request = std::make_unique(url, messageStr, true); - auto callback = std::make_unique(); - - auto* pendingDialogs = &self->pending_script_dialogs_; - int64_t capturedId = dialogId; - - callback->nonNullSuccess = [](JsAlertResponse response) { return !response.handledByClient; }; - - callback->defaultBehaviour = [pendingDialogs, capturedId](std::optional) { - auto it = pendingDialogs->find(capturedId); - if (it != pendingDialogs->end()) { - webkit_script_dialog_close(it->second); - webkit_script_dialog_unref(it->second); - pendingDialogs->erase(it); - } - }; - - self->channel_delegate_->onJsAlert(std::move(request), std::move(callback)); - break; - } - - case WEBKIT_SCRIPT_DIALOG_CONFIRM: { - auto request = std::make_unique(url, messageStr, true); - auto callback = std::make_unique(); - - auto* pendingDialogs = &self->pending_script_dialogs_; - int64_t capturedId = dialogId; - - callback->nonNullSuccess = [pendingDialogs, capturedId](JsConfirmResponse response) { - auto it = pendingDialogs->find(capturedId); - if (it != pendingDialogs->end()) { - webkit_script_dialog_confirm_set_confirmed( - it->second, response.action == JsConfirmResponseAction::CONFIRM); - webkit_script_dialog_close(it->second); - webkit_script_dialog_unref(it->second); - pendingDialogs->erase(it); - } - return false; - }; - - callback->defaultBehaviour = [pendingDialogs, capturedId](std::optional) { - auto it = pendingDialogs->find(capturedId); - if (it != pendingDialogs->end()) { - webkit_script_dialog_confirm_set_confirmed(it->second, FALSE); - webkit_script_dialog_close(it->second); - webkit_script_dialog_unref(it->second); - pendingDialogs->erase(it); - } - }; - - self->channel_delegate_->onJsConfirm(std::move(request), std::move(callback)); - break; - } - - case WEBKIT_SCRIPT_DIALOG_PROMPT: { - const gchar* defaultValue = webkit_script_dialog_prompt_get_default_text(dialog); - std::optional defaultValueStr; - if (defaultValue != nullptr) { - defaultValueStr = std::string(defaultValue); - } - - auto request = std::make_unique(url, messageStr, defaultValueStr, true); - auto callback = std::make_unique(); - - auto* pendingDialogs = &self->pending_script_dialogs_; - int64_t capturedId = dialogId; - - callback->nonNullSuccess = [pendingDialogs, capturedId](JsPromptResponse response) { - auto it = pendingDialogs->find(capturedId); - if (it != pendingDialogs->end()) { - if (response.action == JsPromptResponseAction::CONFIRM && response.value.has_value()) { - webkit_script_dialog_prompt_set_text(it->second, response.value.value().c_str()); - } - webkit_script_dialog_close(it->second); - webkit_script_dialog_unref(it->second); - pendingDialogs->erase(it); - } - return false; - }; - - callback->defaultBehaviour = [pendingDialogs, capturedId](std::optional) { - auto it = pendingDialogs->find(capturedId); - if (it != pendingDialogs->end()) { - webkit_script_dialog_close(it->second); - webkit_script_dialog_unref(it->second); - pendingDialogs->erase(it); - } - }; - - self->channel_delegate_->onJsPrompt(std::move(request), std::move(callback)); - break; - } - - case WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM: { - auto callback = std::make_unique(); - - auto* pendingDialogs = &self->pending_script_dialogs_; - int64_t capturedId = dialogId; - - callback->nonNullSuccess = [pendingDialogs, capturedId](JsBeforeUnloadResponse response) { - auto it = pendingDialogs->find(capturedId); - if (it != pendingDialogs->end()) { - webkit_script_dialog_confirm_set_confirmed(it->second, response.shouldAllowNavigation); - webkit_script_dialog_close(it->second); - webkit_script_dialog_unref(it->second); - pendingDialogs->erase(it); - } - return false; - }; - - callback->defaultBehaviour = [pendingDialogs, - capturedId](std::optional) { - auto it = pendingDialogs->find(capturedId); - if (it != pendingDialogs->end()) { - webkit_script_dialog_confirm_set_confirmed(it->second, TRUE); - webkit_script_dialog_close(it->second); - webkit_script_dialog_unref(it->second); - pendingDialogs->erase(it); - } - }; - - self->channel_delegate_->onJsBeforeUnload( - url, messageStr.empty() ? std::nullopt : std::make_optional(messageStr), - std::move(callback)); - break; - } - - default: - // Unknown dialog type, let WebKit handle it - webkit_script_dialog_unref(dialog); - self->pending_script_dialogs_.erase(dialogId); - return FALSE; - } - - return TRUE; // We're handling the dialog -} - -gboolean InAppWebView::OnPermissionRequest(WebKitWebView* web_view, - WebKitPermissionRequest* request, gpointer user_data) { - auto* self = static_cast(user_data); - - if (!self->channel_delegate_) { - webkit_permission_request_deny(request); - return TRUE; - } - - auto resourceTypes = PermissionRequest::getResourceTypes(request); - if (resourceTypes.empty()) { - webkit_permission_request_deny(request); - return TRUE; - } - - std::optional origin; - const gchar* uri = webkit_web_view_get_uri(web_view); - if (uri != nullptr) { - origin = std::string(uri); - } - - auto permRequest = std::make_unique(origin, resourceTypes); - - // Keep reference to the WebKit request - g_object_ref(request); - int64_t requestId = self->next_permission_id_++; - self->pending_permission_requests_[requestId] = request; - - auto callback = std::make_unique(); - - auto* pendingRequests = &self->pending_permission_requests_; - int64_t capturedId = requestId; - - callback->nonNullSuccess = [pendingRequests, capturedId](PermissionResponse response) { - auto it = pendingRequests->find(capturedId); - if (it != pendingRequests->end()) { - if (response.action == PermissionResponseAction::GRANT) { - webkit_permission_request_allow(it->second); - } else { - webkit_permission_request_deny(it->second); - } - g_object_unref(it->second); - pendingRequests->erase(it); - } - return false; - }; - - callback->defaultBehaviour = [pendingRequests, capturedId](std::optional) { - auto it = pendingRequests->find(capturedId); - if (it != pendingRequests->end()) { - webkit_permission_request_deny(it->second); - g_object_unref(it->second); - pendingRequests->erase(it); - } - }; - - self->channel_delegate_->onPermissionRequest(std::move(permRequest), std::move(callback)); - - return TRUE; // We're handling the request -} - -gboolean InAppWebView::OnAuthenticate(WebKitWebView* web_view, WebKitAuthenticationRequest* request, - gpointer user_data) { - auto* self = static_cast(user_data); - - if (!self->channel_delegate_) { - webkit_authentication_request_cancel(request); - return TRUE; - } - - const gchar* host = webkit_authentication_request_get_host(request); - guint port = webkit_authentication_request_get_port(request); - const gchar* realm = webkit_authentication_request_get_realm(request); - WebKitAuthenticationScheme scheme = webkit_authentication_request_get_scheme(request); - gboolean isProxy = webkit_authentication_request_is_for_proxy(request); - gboolean isRetry = webkit_authentication_request_is_retry(request); - - // Build protection space for URL credential lookup - URLProtectionSpace protectionSpace(host ? std::string(host) : "", static_cast(port), - std::nullopt, // protocol not directly available - realm ? std::make_optional(std::string(realm)) : std::nullopt, - URLProtectionSpace::fromWebKitScheme(scheme), isProxy); - - // Check if this is a client certificate request - if (scheme == WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_REQUESTED) { - // Handle client certificate request - auto challenge = std::make_unique(protectionSpace, isProxy); - - // Keep reference to the request - g_object_ref(request); - int64_t requestId = self->next_auth_id_++; - self->pending_auth_requests_[requestId] = request; - - auto callback = std::make_unique(); - - auto* pendingRequests = &self->pending_auth_requests_; - int64_t capturedId = requestId; - - callback->nonNullSuccess = [pendingRequests, capturedId](ClientCertResponse response) { - auto it = pendingRequests->find(capturedId); - if (it != pendingRequests->end()) { - switch (response.action) { - case ClientCertResponseAction::PROCEED: { - // WPE WebKit's webkit_credential_new_for_certificate() API (since 2.34) - // allows providing a client certificate. - // GTlsCertificate constructors (from docs.gtk.org/gio/class.TlsCertificate.html): - // - g_tls_certificate_new_from_file: PEM file containing cert + optionally private key - // - g_tls_certificate_new_from_file_with_password: Password-protected file (since 2.72) - // - g_tls_certificate_new_from_files: Separate cert and key files - // - g_tls_certificate_new_from_pkcs12: PKCS#12 data with password (since 2.72) - if (response.certificatePath.has_value() && !response.certificatePath->empty()) { - GError* error = nullptr; - GTlsCertificate* cert = nullptr; - - std::string keyStoreType = response.keyStoreType.value_or(""); - std::string certPath = response.certificatePath.value(); - std::optional password = response.certificatePassword; - - if (keyStoreType == "PKCS12" || keyStoreType == "pkcs12") { - // For PKCS12, we need to read the file and use g_tls_certificate_new_from_pkcs12 - // which requires GLib 2.72+ - #if GLIB_CHECK_VERSION(2, 72, 0) - // Read the PKCS12 file - gchar* data = nullptr; - gsize length = 0; - if (g_file_get_contents(certPath.c_str(), &data, &length, &error)) { - cert = g_tls_certificate_new_from_pkcs12( - reinterpret_cast(data), - length, - password.has_value() ? password->c_str() : nullptr, - &error); - g_free(data); - } - #else - debugLog("PKCS12 certificates require GLib 2.72+. Trying PEM fallback..."); - // Fallback to trying as PEM - cert = g_tls_certificate_new_from_file(certPath.c_str(), &error); - #endif - } else if (password.has_value() && !password->empty()) { - // Password-protected file (e.g., encrypted PEM) - requires GLib 2.72+ - #if GLIB_CHECK_VERSION(2, 72, 0) - cert = g_tls_certificate_new_from_file_with_password( - certPath.c_str(), - password->c_str(), - &error); - #else - debugLog("Password-protected certificates require GLib 2.72+. Trying without password..."); - cert = g_tls_certificate_new_from_file(certPath.c_str(), &error); - #endif - } else { - // Standard PEM file (certificate + optional private key in same file) - cert = g_tls_certificate_new_from_file(certPath.c_str(), &error); - } - - if (cert != nullptr) { - // Create credential from certificate - WebKitCredential* credential = webkit_credential_new_for_certificate( - cert, WEBKIT_CREDENTIAL_PERSISTENCE_FOR_SESSION); - webkit_authentication_request_authenticate(it->second, credential); - webkit_credential_free(credential); - g_object_unref(cert); - } else { - if (error != nullptr) { - debugLog("Failed to load client certificate: " + std::string(error->message)); - g_error_free(error); - } - webkit_authentication_request_cancel(it->second); - } - } else { - // No certificate path provided, cancel - debugLog("Client certificate PROCEED without certificate path - canceling"); - webkit_authentication_request_cancel(it->second); - } - break; - } - - case ClientCertResponseAction::IGNORE: - // Ignore means don't handle this request (let WebKit handle or retry later) - webkit_authentication_request_cancel(it->second); - break; - - case ClientCertResponseAction::CANCEL: - default: - webkit_authentication_request_cancel(it->second); - break; - } - - g_object_unref(it->second); - pendingRequests->erase(it); - } - return false; - }; - - callback->defaultBehaviour = [pendingRequests, capturedId](std::optional) { - auto it = pendingRequests->find(capturedId); - if (it != pendingRequests->end()) { - webkit_authentication_request_cancel(it->second); - g_object_unref(it->second); - pendingRequests->erase(it); - } - }; - - self->channel_delegate_->onReceivedClientCertRequest(std::move(challenge), std::move(callback)); - - return TRUE; // We're handling the request - } - - // Build ProtectionSpace for libsecret lookup (for HTTP auth) - ProtectionSpace credProtectionSpace; - credProtectionSpace.host = host ? std::string(host) : ""; - credProtectionSpace.port = static_cast(port); - credProtectionSpace.realm = realm ? std::make_optional(std::string(realm)) : std::nullopt; - // Map scheme to protocol for libsecret - if (scheme == WEBKIT_AUTHENTICATION_SCHEME_HTTP_BASIC || - scheme == WEBKIT_AUTHENTICATION_SCHEME_HTTP_DIGEST || - scheme == WEBKIT_AUTHENTICATION_SCHEME_DEFAULT) { - credProtectionSpace.protocol = "http"; - } - - auto challenge = std::make_unique(protectionSpace, isRetry); - - // Keep reference to the request - g_object_ref(request); - int64_t requestId = self->next_auth_id_++; - self->pending_auth_requests_[requestId] = request; - - auto callback = std::make_unique(); - - auto* pendingRequests = &self->pending_auth_requests_; - int64_t capturedId = requestId; - ProtectionSpace capturedPs = credProtectionSpace; - PluginInstance* capturedPlugin = self->plugin_; - - callback->nonNullSuccess = [pendingRequests, capturedId, capturedPs, capturedPlugin](HttpAuthResponse response) { - auto it = pendingRequests->find(capturedId); - if (it != pendingRequests->end()) { - switch (response.action) { - case HttpAuthResponseAction::PROCEED: - if (response.username.has_value() && response.password.has_value()) { - WebKitCredential* credential = webkit_credential_new( - response.username.value().c_str(), response.password.value().c_str(), - response.permanentPersistence ? WEBKIT_CREDENTIAL_PERSISTENCE_PERMANENT - : WEBKIT_CREDENTIAL_PERSISTENCE_FOR_SESSION); - webkit_authentication_request_authenticate(it->second, credential); - - // Save credential to libsecret if permanent persistence requested - if (response.permanentPersistence) { - auto* credDb = capturedPlugin ? capturedPlugin->credentialDatabase : nullptr; - if (credDb != nullptr) { - Credential cred(response.username.value(), response.password.value()); - credDb->setHttpAuthCredential(capturedPs, cred); - } - } - - webkit_credential_free(credential); - } else { - webkit_authentication_request_cancel(it->second); - } - break; - - case HttpAuthResponseAction::USE_SAVED_CREDENTIAL: { - // Look up credential from our secure storage - auto* credDb = capturedPlugin ? capturedPlugin->credentialDatabase : nullptr; - std::optional savedCred = std::nullopt; - - if (credDb != nullptr) { - // Try to get a saved credential - savedCred = credDb->lookupFirstCredential(capturedPs); - } - - // Fall back to WebKit's proposed credential if we don't have one - if (!savedCred.has_value()) { - WebKitCredential* proposed = webkit_authentication_request_get_proposed_credential(it->second); - if (proposed != nullptr) { - const gchar* username = webkit_credential_get_username(proposed); - const gchar* password = webkit_credential_get_password(proposed); - if (username != nullptr && password != nullptr) { - savedCred = Credential(username, password); - } - webkit_credential_free(proposed); - } - } - - if (savedCred.has_value()) { - WebKitCredential* credential = webkit_credential_new( - savedCred->username.c_str(), - savedCred->password.c_str(), - WEBKIT_CREDENTIAL_PERSISTENCE_FOR_SESSION); - webkit_authentication_request_authenticate(it->second, credential); - webkit_credential_free(credential); - } else { - // No saved credential found, cancel - webkit_authentication_request_cancel(it->second); - } - break; - } - - case HttpAuthResponseAction::CANCEL: - default: - webkit_authentication_request_cancel(it->second); - break; - } - - g_object_unref(it->second); - pendingRequests->erase(it); - } - return false; - }; - - callback->defaultBehaviour = [pendingRequests, capturedId](std::optional) { - auto it = pendingRequests->find(capturedId); - if (it != pendingRequests->end()) { - webkit_authentication_request_cancel(it->second); - g_object_unref(it->second); - pendingRequests->erase(it); - } - }; - - self->channel_delegate_->onReceivedHttpAuthRequest(std::move(challenge), std::move(callback)); - - return TRUE; // We're handling the request -} - -// NOTE: WPE WebKit renders offscreen without a GDK window. -// We use the Flutter window's GDK window to display the native GTK context menu. - -gboolean InAppWebView::OnContextMenu(WebKitWebView* web_view, WebKitContextMenu* context_menu, - WebKitHitTestResult* hit_test_result, gpointer user_data) { - auto* self = static_cast(user_data); - - // Disable context menu if setting is enabled - if (self->settings_ && self->settings_->disableContextMenu) { - return TRUE; // Suppress context menu - } - - // Store the context menu and hit test result for native menu display - // We need to ref these because WebKit may release them after this callback returns - if (self->pending_context_menu_ != nullptr) { - g_object_unref(self->pending_context_menu_); - } - self->pending_context_menu_ = context_menu; - g_object_ref(context_menu); - - if (self->pending_hit_test_result_ != nullptr) { - g_object_unref(self->pending_hit_test_result_); - } - self->pending_hit_test_result_ = hit_test_result; - if (hit_test_result != nullptr) { - g_object_ref(hit_test_result); - } - - // Notify Dart side that context menu is being created - if (self->channel_delegate_) { - HitTestResult hitTestResult = HitTestResult::fromWebKitHitTestResult(self->pending_hit_test_result_); - self->channel_delegate_->onCreateContextMenu(hitTestResult); - } - - // Store the current cursor position for the context menu - self->context_menu_x_ = self->cursor_x_; - self->context_menu_y_ = self->cursor_y_; - - // Show the context menu - self->ShowNativeContextMenu(); - - // Return TRUE to suppress WebKit's default context menu handling - return TRUE; -} - -void InAppWebView::OnContextMenuDismissed(WebKitWebView* web_view, gpointer user_data) { - auto* self = static_cast(user_data); - - // Hide our custom context menu popup when WebKit signals dismissal - self->HideContextMenu(); -} - -void InAppWebView::ShowNativeContextMenu() { - // Use cached GTK window for the popup menu - if (gtk_window_ == nullptr) { - errorLog("InAppWebView: Cannot show context menu - no window available"); - return; - } - - // Create context menu popup if needed - if (!context_menu_popup_) { - context_menu_popup_ = std::make_unique(gtk_window_); - - // Set up callbacks - context_menu_popup_->SetItemCallback( - [this](const std::string& id, const std::string& title) { - // Try to execute the action directly using WebKit APIs - int action_id = 0; - try { - action_id = std::stoi(id); - } catch (...) { - action_id = 0; - } - - if (action_id > 0 && webview_ != nullptr) { - // Execute stock actions directly via WebKit API - WebKitContextMenuAction action = static_cast(action_id); - switch (action) { - case WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION: - // No action, used by separator menu items - break; - - // === Link Actions === - case WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK: - // Open the link in current view - if (pending_hit_test_result_ != nullptr) { - const gchar* uri = webkit_hit_test_result_get_link_uri(pending_hit_test_result_); - if (uri != nullptr) { - webkit_web_view_load_uri(webview_, uri); - } - } - break; - - case WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW: - // Open link in new window - notify Dart side to handle - if (pending_hit_test_result_ != nullptr && channel_delegate_) { - const gchar* uri = webkit_hit_test_result_get_link_uri(pending_hit_test_result_); - if (uri != nullptr) { - // For now, just open in current view (Dart can handle new window logic) - webkit_web_view_load_uri(webview_, uri); - } - } - break; - - case WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK: - // Download link - trigger download - if (pending_hit_test_result_ != nullptr) { - const gchar* uri = webkit_hit_test_result_get_link_uri(pending_hit_test_result_); - if (uri != nullptr) { - webkit_web_view_download_uri(webview_, uri); - } - } - break; - - case WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD: - // Copy link URI to both system and WebView clipboard - if (pending_hit_test_result_ != nullptr) { - const gchar* uri = webkit_hit_test_result_get_link_uri(pending_hit_test_result_); - if (uri != nullptr) { - copyTextToClipboard(uri); - } - } - break; - - // === Image Actions === - case WEBKIT_CONTEXT_MENU_ACTION_OPEN_IMAGE_IN_NEW_WINDOW: - // Open image in new window - if (pending_hit_test_result_ != nullptr) { - const gchar* uri = webkit_hit_test_result_get_image_uri(pending_hit_test_result_); - if (uri != nullptr) { - webkit_web_view_load_uri(webview_, uri); - } - } - break; - - case WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_IMAGE_TO_DISK: - // Download image - if (pending_hit_test_result_ != nullptr) { - const gchar* uri = webkit_hit_test_result_get_image_uri(pending_hit_test_result_); - if (uri != nullptr) { - webkit_web_view_download_uri(webview_, uri); - } - } - break; - - case WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_TO_CLIPBOARD: - // Copy image URI to both system and WebView clipboard - if (pending_hit_test_result_ != nullptr) { - const gchar* uri = webkit_hit_test_result_get_image_uri(pending_hit_test_result_); - if (uri != nullptr) { - copyTextToClipboard(uri); - } - } - break; - - // === Frame Actions === - case WEBKIT_CONTEXT_MENU_ACTION_OPEN_FRAME_IN_NEW_WINDOW: - // Open frame in new window - use GAction fallback - break; - - // === Navigation Actions === - case WEBKIT_CONTEXT_MENU_ACTION_GO_BACK: - webkit_web_view_go_back(webview_); - break; - - case WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD: - webkit_web_view_go_forward(webview_); - break; - - case WEBKIT_CONTEXT_MENU_ACTION_STOP: - webkit_web_view_stop_loading(webview_); - break; - - case WEBKIT_CONTEXT_MENU_ACTION_RELOAD: - webkit_web_view_reload(webview_); - break; - - // === Editing Actions === - // These use the clipboard methods that sync WPE WebKit with system clipboard - case WEBKIT_CONTEXT_MENU_ACTION_COPY: - copyToClipboard(); - break; - - case WEBKIT_CONTEXT_MENU_ACTION_CUT: - cutToClipboard(); - break; - - case WEBKIT_CONTEXT_MENU_ACTION_PASTE: - pasteFromClipboard(); - break; - - // === Spelling Actions === - case WEBKIT_CONTEXT_MENU_ACTION_SPELLING_GUESS: - // Spelling suggestion - use GAction fallback - break; - - case WEBKIT_CONTEXT_MENU_ACTION_NO_GUESSES_FOUND: - // No spelling guesses - informational only - break; - - case WEBKIT_CONTEXT_MENU_ACTION_IGNORE_SPELLING: - // Ignore spelling - use GAction fallback - break; - - case WEBKIT_CONTEXT_MENU_ACTION_LEARN_SPELLING: - // Learn spelling - use GAction fallback - break; - - case WEBKIT_CONTEXT_MENU_ACTION_IGNORE_GRAMMAR: - // Ignore grammar - use GAction fallback - break; - - // === Font Actions === - case WEBKIT_CONTEXT_MENU_ACTION_FONT_MENU: - // Font submenu - use GAction fallback - break; - - case WEBKIT_CONTEXT_MENU_ACTION_BOLD: - webkit_web_view_execute_editing_command(webview_, "Bold"); - break; - - case WEBKIT_CONTEXT_MENU_ACTION_ITALIC: - webkit_web_view_execute_editing_command(webview_, "Italic"); - break; - - case WEBKIT_CONTEXT_MENU_ACTION_UNDERLINE: - webkit_web_view_execute_editing_command(webview_, "Underline"); - break; - - case WEBKIT_CONTEXT_MENU_ACTION_OUTLINE: - // Outline - use GAction fallback - break; - - // === Developer Tools === - case WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT: - // Inspect element - not available in WPE WebKit without GTK inspector - // Fall through to GAction fallback - break; - - // === Video Actions === - case WEBKIT_CONTEXT_MENU_ACTION_OPEN_VIDEO_IN_NEW_WINDOW: - if (pending_hit_test_result_ != nullptr) { - const gchar* uri = webkit_hit_test_result_get_media_uri(pending_hit_test_result_); - if (uri != nullptr) { - webkit_web_view_load_uri(webview_, uri); - } - } - break; - - case WEBKIT_CONTEXT_MENU_ACTION_COPY_VIDEO_LINK_TO_CLIPBOARD: - // Copy video URI to both system and WebView clipboard - if (pending_hit_test_result_ != nullptr) { - const gchar* uri = webkit_hit_test_result_get_media_uri(pending_hit_test_result_); - if (uri != nullptr) { - copyTextToClipboard(uri); - } - } - break; - - case WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_VIDEO_TO_DISK: - if (pending_hit_test_result_ != nullptr) { - const gchar* uri = webkit_hit_test_result_get_media_uri(pending_hit_test_result_); - if (uri != nullptr) { - webkit_web_view_download_uri(webview_, uri); - } - } - break; - - // === Audio Actions === - case WEBKIT_CONTEXT_MENU_ACTION_OPEN_AUDIO_IN_NEW_WINDOW: - if (pending_hit_test_result_ != nullptr) { - const gchar* uri = webkit_hit_test_result_get_media_uri(pending_hit_test_result_); - if (uri != nullptr) { - webkit_web_view_load_uri(webview_, uri); - } - } - break; - - case WEBKIT_CONTEXT_MENU_ACTION_COPY_AUDIO_LINK_TO_CLIPBOARD: - // Copy audio URI to both system and WebView clipboard - if (pending_hit_test_result_ != nullptr) { - const gchar* uri = webkit_hit_test_result_get_media_uri(pending_hit_test_result_); - if (uri != nullptr) { - copyTextToClipboard(uri); - } - } - break; - - case WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_AUDIO_TO_DISK: - if (pending_hit_test_result_ != nullptr) { - const gchar* uri = webkit_hit_test_result_get_media_uri(pending_hit_test_result_); - if (uri != nullptr) { - webkit_web_view_download_uri(webview_, uri); - } - } - break; - - // === Media Control Actions === - case WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_CONTROLS: - // Toggle media controls - use JavaScript - evaluateJavascript( - "if(document.activeElement && document.activeElement.controls !== undefined) {" - " document.activeElement.controls = !document.activeElement.controls;" - "}", - std::nullopt, - nullptr); - break; - - case WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_LOOP: - // Toggle media loop - use JavaScript - evaluateJavascript( - "if(document.activeElement && document.activeElement.loop !== undefined) {" - " document.activeElement.loop = !document.activeElement.loop;" - "}", - std::nullopt, - nullptr); - break; - - case WEBKIT_CONTEXT_MENU_ACTION_ENTER_VIDEO_FULLSCREEN: - // Enter video fullscreen - use JavaScript - evaluateJavascript( - "if(document.activeElement && document.activeElement.requestFullscreen) {" - " document.activeElement.requestFullscreen();" - "} else if(document.activeElement && document.activeElement.webkitEnterFullscreen) {" - " document.activeElement.webkitEnterFullscreen();" - "}", - std::nullopt, - nullptr); - break; - - case WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PLAY: - // Play media - use JavaScript - evaluateJavascript( - "if(document.activeElement && document.activeElement.play) {" - " document.activeElement.play();" - "}", - std::nullopt, - nullptr); - break; - - case WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PAUSE: - // Pause media - use JavaScript - evaluateJavascript( - "if(document.activeElement && document.activeElement.pause) {" - " document.activeElement.pause();" - "}", - std::nullopt, - nullptr); - break; - - case WEBKIT_CONTEXT_MENU_ACTION_MEDIA_MUTE: - // Toggle mute - use JavaScript - evaluateJavascript( - "if(document.activeElement && document.activeElement.muted !== undefined) {" - " document.activeElement.muted = !document.activeElement.muted;" - "}", - std::nullopt, - nullptr); - break; - - // === Custom Actions === - case WEBKIT_CONTEXT_MENU_ACTION_CUSTOM: - // Custom action - handled by Dart side - break; - - default: - // For any unhandled actions, try the GAction approach as fallback - if (pending_context_menu_ != nullptr) { - GList* items = webkit_context_menu_get_items(pending_context_menu_); - for (GList* l = items; l != nullptr; l = l->next) { - WebKitContextMenuItem* webkit_item = WEBKIT_CONTEXT_MENU_ITEM(l->data); - WebKitContextMenuAction stock_action = - webkit_context_menu_item_get_stock_action(webkit_item); - if (static_cast(stock_action) == action_id) { - GAction* gaction = webkit_context_menu_item_get_gaction(webkit_item); - if (gaction != nullptr && g_action_get_enabled(gaction)) { - g_action_activate(gaction, nullptr); - } - break; - } - } - } - break; - } - } - - // Notify Dart side about the menu item click - if (channel_delegate_) { - channel_delegate_->onContextMenuActionItemClicked(id, title); - } - }); - - context_menu_popup_->SetDismissedCallback([this]() { - // Only notify if the popup was actually visible (prevents duplicate notifications) - if (context_menu_popup_ && context_menu_popup_->IsVisible() && channel_delegate_) { - channel_delegate_->onHideContextMenu(); - } - }); - } - - // Clear and rebuild the menu - context_menu_popup_->Clear(); - - // Get context menu settings - bool hideDefaultItems = false; - if (context_menu_config_ != nullptr) { - hideDefaultItems = context_menu_config_->settings.hideDefaultSystemContextMenuItems; - } - - bool hasItems = false; - - // Add items from the WebKit context menu if available and not hiding default items - if (pending_context_menu_ != nullptr && !hideDefaultItems) { - GList* items = webkit_context_menu_get_items(pending_context_menu_); - for (GList* l = items; l != nullptr; l = l->next) { - WebKitContextMenuItem* webkit_item = WEBKIT_CONTEXT_MENU_ITEM(l->data); - - // Get the stock action to determine the menu item type - WebKitContextMenuAction stock_action = webkit_context_menu_item_get_stock_action(webkit_item); - - // Skip separator and custom actions for now - if (stock_action == WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION) { - context_menu_popup_->AddSeparator(); - continue; - } - - // Get action using GAction API (WPE WebKit uses GAction, not GtkAction) - GAction* gaction = webkit_context_menu_item_get_gaction(webkit_item); - bool enabled = (gaction != nullptr) ? g_action_get_enabled(gaction) : true; - - // Map stock actions to labels - const char* stock_label = nullptr; - switch (stock_action) { - case WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK: - stock_label = "Open Link"; - break; - case WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW: - stock_label = "Open Link in New Window"; - break; - case WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK: - stock_label = "Download Link"; - break; - case WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD: - stock_label = "Copy Link"; - break; - case WEBKIT_CONTEXT_MENU_ACTION_OPEN_IMAGE_IN_NEW_WINDOW: - stock_label = "Open Image in New Window"; - break; - case WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_IMAGE_TO_DISK: - stock_label = "Download Image"; - break; - case WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_TO_CLIPBOARD: - stock_label = "Copy Image"; - break; - case WEBKIT_CONTEXT_MENU_ACTION_GO_BACK: - stock_label = "Back"; - break; - case WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD: - stock_label = "Forward"; - break; - case WEBKIT_CONTEXT_MENU_ACTION_STOP: - stock_label = "Stop"; - break; - case WEBKIT_CONTEXT_MENU_ACTION_RELOAD: - stock_label = "Reload"; - break; - case WEBKIT_CONTEXT_MENU_ACTION_COPY: - stock_label = "Copy"; - break; - case WEBKIT_CONTEXT_MENU_ACTION_CUT: - stock_label = "Cut"; - break; - case WEBKIT_CONTEXT_MENU_ACTION_PASTE: - stock_label = "Paste"; - break; - case WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT: - stock_label = "Inspect Element"; - break; - default: - continue; - } - - if (stock_label != nullptr) { - context_menu_popup_->AddItem(std::to_string(static_cast(stock_action)), stock_label, - enabled); - hasItems = true; - } - } - } - - // Add custom menu items from context_menu_config_ - if (context_menu_config_ != nullptr && !context_menu_config_->menuItems.empty()) { - if (hasItems) { - context_menu_popup_->AddSeparator(); - } - - for (const auto& customItem : context_menu_config_->menuItems) { - if (!customItem.title.empty()) { - context_menu_popup_->AddItem(customItem.getIdAsString(), customItem.title, true); - hasItems = true; - } - } - } - - if (!hasItems) { - return; - } - - // Get screen position of the cursor using the pointer device - // This works reliably on both X11 and Wayland - gint screen_x = 0, screen_y = 0; - - GdkDisplay* gdk_display = gdk_display_get_default(); - if (gdk_display != nullptr) { - GdkSeat* seat = gdk_display_get_default_seat(gdk_display); - if (seat != nullptr) { - GdkDevice* pointer = gdk_seat_get_pointer(seat); - if (pointer != nullptr) { - gdk_device_get_position(pointer, nullptr, &screen_x, &screen_y); - } - } - } - - context_menu_popup_->Show(screen_x, screen_y); -} - -void InAppWebView::HideContextMenu() { - // Check if context menu is actually visible before proceeding - bool wasVisible = context_menu_popup_ && context_menu_popup_->IsVisible(); - - // Hide the context menu popup - if (context_menu_popup_) { - context_menu_popup_->Hide(); - } - - // Clean up pending menu references - if (pending_context_menu_ != nullptr) { - g_object_unref(pending_context_menu_); - pending_context_menu_ = nullptr; - } - - if (pending_hit_test_result_ != nullptr) { - g_object_unref(pending_hit_test_result_); - pending_hit_test_result_ = nullptr; - } - - // Notify Dart side only if context menu was actually visible - if (wasVisible && channel_delegate_) { - channel_delegate_->onHideContextMenu(); - } -} - -// === Color Picker for === -// WPE WebKit doesn't have the run-color-chooser signal that WebKitGTK has, -// so we implement color input support via JavaScript interception and a native GTK3 dialog. - -// Helper function to parse hex color string to GdkRGBA -static bool ParseHexColor(const std::string& hexColor, GdkRGBA* rgba) { - if (hexColor.empty() || hexColor[0] != '#') { - return false; - } - - std::string hex = hexColor.substr(1); // Remove '#' - - unsigned int r = 0, g = 0, b = 0, a = 255; - - if (hex.length() == 6) { - // #RRGGBB - if (sscanf(hex.c_str(), "%02x%02x%02x", &r, &g, &b) != 3) { - return false; - } - } else if (hex.length() == 8) { - // #RRGGBBAA - if (sscanf(hex.c_str(), "%02x%02x%02x%02x", &r, &g, &b, &a) != 4) { - return false; - } - } else if (hex.length() == 3) { - // #RGB (shorthand) - if (sscanf(hex.c_str(), "%1x%1x%1x", &r, &g, &b) != 3) { - return false; - } - r = r * 17; // Expand 0-15 to 0-255 - g = g * 17; - b = b * 17; - } else { - return false; - } - - rgba->red = r / 255.0; - rgba->green = g / 255.0; - rgba->blue = b / 255.0; - rgba->alpha = a / 255.0; - - return true; -} - -// Helper function to convert GdkRGBA to hex color string -static std::string RgbaToHexColor(const GdkRGBA* rgba, bool includeAlpha) { - int r = static_cast(rgba->red * 255.0 + 0.5); - int g = static_cast(rgba->green * 255.0 + 0.5); - int b = static_cast(rgba->blue * 255.0 + 0.5); - int a = static_cast(rgba->alpha * 255.0 + 0.5); - - // Clamp values - r = std::max(0, std::min(255, r)); - g = std::max(0, std::min(255, g)); - b = std::max(0, std::min(255, b)); - a = std::max(0, std::min(255, a)); - - char hexColor[10]; - if (includeAlpha && a != 255) { - snprintf(hexColor, sizeof(hexColor), "#%02X%02X%02X%02X", r, g, b, a); - } else { - snprintf(hexColor, sizeof(hexColor), "#%02X%02X%02X", r, g, b); - } - - return std::string(hexColor); -} - -// Static callback for non-blocking color dialog response -static void OnColorDialogResponse(GtkDialog* dialog, gint response_id, gpointer user_data) { - auto* self = static_cast(user_data); - - // Capture and clear reply before resolving (to prevent use after cleanup) - WebKitScriptMessageReply* reply = self->pending_color_reply_; - self->pending_color_reply_ = nullptr; - - if (reply == nullptr) { - // No reply object - just cleanup - gtk_widget_destroy(GTK_WIDGET(dialog)); - g_object_unref(dialog); - self->active_color_dialog_ = nullptr; - self->color_dialog_show_time_ = 0; - return; - } - - if (response_id == GTK_RESPONSE_OK) { - // User selected a color - GdkRGBA selectedRgba; - gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &selectedRgba); - - std::string hexColor = RgbaToHexColor(&selectedRgba, self->active_color_alpha_enabled_); - // Resolve the Promise with the selected color via webkit reply - self->ResolveInternalHandlerWithReply(reply, "\"" + hexColor + "\""); - } else { - // User cancelled or closed the dialog - resolve with null - self->ResolveInternalHandlerWithReply(reply, "null"); - } - - // Cleanup - gtk_widget_destroy(GTK_WIDGET(dialog)); - g_object_unref(dialog); // Release our extra reference - self->active_color_dialog_ = nullptr; - self->color_dialog_show_time_ = 0; -} - -void InAppWebView::ShowColorPicker(const std::string& initialColor, int x, int y, - const std::vector& predefinedColors, - bool alphaEnabled, - const std::string& colorSpace) { - (void)x; // Position not used for non-modal dialog - (void)y; - (void)colorSpace; // GTK3 color chooser doesn't support color spaces - - // Close any existing color dialog first - if (active_color_dialog_ != nullptr) { - gtk_widget_destroy(active_color_dialog_); - g_object_unref(active_color_dialog_); - active_color_dialog_ = nullptr; - } - - // Store the initial color for cancel restoration - pending_color_input_value_ = initialColor; - active_color_alpha_enabled_ = alphaEnabled; - - // Create the color chooser dialog with parent window - GtkWidget* dialog = gtk_color_chooser_dialog_new("Select Color", gtk_window_); - active_color_dialog_ = dialog; - - // Set dialog as transient for parent (floats above but doesn't block) - if (gtk_window_) { - gtk_window_set_transient_for(GTK_WINDOW(dialog), gtk_window_); - } - - // Take an extra reference to prevent premature destruction - g_object_ref(dialog); - - GtkColorChooser* chooser = GTK_COLOR_CHOOSER(dialog); - - // Set the initial color - GdkRGBA initialRgba = {0.0, 0.0, 0.0, 1.0}; // Default to black - if (ParseHexColor(initialColor, &initialRgba)) { - gtk_color_chooser_set_rgba(chooser, &initialRgba); - } - - // Enable/disable alpha channel - gtk_color_chooser_set_use_alpha(chooser, alphaEnabled ? TRUE : FALSE); - - // Add predefined colors if provided - if (!predefinedColors.empty()) { - std::vector rgbaColors; - rgbaColors.reserve(predefinedColors.size()); - - for (const auto& hexColor : predefinedColors) { - GdkRGBA rgba; - if (ParseHexColor(hexColor, &rgba)) { - rgbaColors.push_back(rgba); - } - } - - if (!rgbaColors.empty()) { - gtk_color_chooser_add_palette(chooser, GTK_ORIENTATION_HORIZONTAL, - static_cast(rgbaColors.size()), - static_cast(rgbaColors.size()), - rgbaColors.data()); - } - } - - // Connect to response signal for non-blocking behavior - g_signal_connect(dialog, "response", G_CALLBACK(OnColorDialogResponse), this); - - // Show the dialog and all its children (non-blocking) - gtk_widget_show_all(dialog); - - // Record show time to prevent immediate close by pointer events - color_dialog_show_time_ = g_get_monotonic_time(); -} - -void InAppWebView::HideColorPicker() { - // Don't hide the color dialog when called from HideAllPopups during focus changes. - // The color dialog is a separate GTK window that should remain open until the user - // explicitly closes it (OK/Cancel). The dialog's response handler will clean up properly. - // This is intentionally a no-op - the dialog manages its own lifecycle. -} - -void InAppWebView::HideFileChooser() { - if (active_file_dialog_ != nullptr) { - // Don't close the dialog if it was just shown (within 200ms) - // This prevents the click that triggered the file chooser from immediately closing it - int64_t now = g_get_monotonic_time(); - int64_t elapsed_us = now - file_dialog_show_time_; - if (elapsed_us < 200000) { - return; - } - - // Cancel the WebKit request if we have context - if (file_chooser_context_ != nullptr) { - auto* context = static_cast(file_chooser_context_); - // Disconnect the signal handler to prevent callback from being called - if (context->response_handler_id != 0) { - g_signal_handler_disconnect(active_file_dialog_, context->response_handler_id); - context->response_handler_id = 0; - } - // Cancel the WebKit request so future file chooser signals work - webkit_file_chooser_request_cancel(context->request); - delete context; - file_chooser_context_ = nullptr; - } - - gtk_widget_destroy(active_file_dialog_); - g_object_unref(active_file_dialog_); - active_file_dialog_ = nullptr; - file_dialog_show_time_ = 0; - } -} - -void InAppWebView::HideOptionMenu() { - if (option_menu_popup_ && option_menu_popup_->IsVisible()) { - option_menu_popup_->Hide(); - } -} - -void InAppWebView::HideAllPopups() { - // Hide all custom popups - add new popup types here as they are implemented - HideContextMenu(); - HideColorPicker(); - HideFileChooser(); - HideOptionMenu(); - HideDatePicker(); -} - -void InAppWebView::ResolveInternalHandlerWithReply(WebKitScriptMessageReply* reply, const std::string& jsonResult) { - if (reply == nullptr) { - debugLog("ResolveInternalHandlerWithReply: reply is NULL, cannot respond"); - return; - } - - // Create a JSCContext to build the reply value - JSCContext* context = jsc_context_new(); - if (context == nullptr) { - webkit_script_message_reply_return_error_message(reply, "Failed to create JSC context"); - webkit_script_message_reply_unref(reply); - return; - } - - // Parse the JSON result and create a JSCValue - JSCValue* replyValue = nullptr; - - if (jsonResult == "null" || jsonResult.empty()) { - replyValue = jsc_value_new_null(context); - } else if (jsonResult[0] == '"') { - // It's a quoted string - evaluate it to get the actual string value - replyValue = jsc_context_evaluate(context, jsonResult.c_str(), -1); - } else { - // Parse as JSON - std::string parseScript = "(" + jsonResult + ")"; - replyValue = jsc_context_evaluate(context, parseScript.c_str(), -1); - } - - if (replyValue == nullptr) { - // Fallback: return the raw string - replyValue = jsc_value_new_string(context, jsonResult.c_str()); - } - - // Send the reply back to JavaScript - webkit_script_message_reply_return_value(reply, replyValue); - - // Cleanup - g_object_unref(replyValue); - g_object_unref(context); - webkit_script_message_reply_unref(reply); -} - -void InAppWebView::RejectInternalHandlerWithReply(WebKitScriptMessageReply* reply, const std::string& errorMessage) { - if (reply == nullptr) { - return; - } - webkit_script_message_reply_return_error_message(reply, errorMessage.c_str()); - webkit_script_message_reply_unref(reply); -} - -// === Date/Time Picker Methods === -// WPE WebKit doesn't have date picker support, so we handle = 1 && *month <= 12) { - *day = 1; - return true; - } - - // Try YYYY-Www format (week) - int week = 0; - if (sscanf(isoDate.c_str(), "%d-W%d", year, &week) == 2) { - // Set to first day of the week - *month = 1; - *day = 1 + (week - 1) * 7; // Approximate - return true; - } - - return false; -} - -// Context struct for date dialog callback -struct DateDialogContext { - InAppWebView* webview; - std::string inputType; - GtkWidget* calendar; // GtkCalendar widget (may be null for time-only) - GtkWidget* hourSpin; // Hour spinner (for time/datetime-local) - GtkWidget* minuteSpin; // Minute spinner (for time/datetime-local) - GtkWidget* dialog; // Reference to the dialog for validation - // Min/max constraints (parsed) - int minYear, minMonth, minDay, minHour, minMinute; - int maxYear, maxMonth, maxDay, maxHour, maxMinute; - bool hasMin, hasMax; -}; - -// Helper to compare dates -static int CompareDates(int y1, int m1, int d1, int y2, int m2, int d2) { - if (y1 != y2) return y1 - y2; - if (m1 != m2) return m1 - m2; - return d1 - d2; -} - -// Helper to compare times (for future use with time validation) -[[maybe_unused]] -static int CompareTimes(int h1, int m1, int h2, int m2) { - if (h1 != h2) return h1 - h2; - return m1 - m2; -} - -// Callback for calendar day selection to validate against min/max -static void OnCalendarDaySelected(GtkCalendar* calendar, gpointer user_data) { - auto* ctx = static_cast(user_data); - - guint year, month, day; - gtk_calendar_get_date(calendar, &year, &month, &day); - month += 1; // GtkCalendar months are 0-based - - bool valid = true; - - // Check min constraint - if (ctx->hasMin) { - if (CompareDates(static_cast(year), static_cast(month), static_cast(day), - ctx->minYear, ctx->minMonth, ctx->minDay) < 0) { - valid = false; - } - } - - // Check max constraint - if (ctx->hasMax) { - if (CompareDates(static_cast(year), static_cast(month), static_cast(day), - ctx->maxYear, ctx->maxMonth, ctx->maxDay) > 0) { - valid = false; - } - } - - // Enable/disable OK button based on validity - if (ctx->dialog) { - gtk_dialog_set_response_sensitive(GTK_DIALOG(ctx->dialog), GTK_RESPONSE_OK, valid ? TRUE : FALSE); - } -} - -// Static callback for date dialog response -static void OnDateDialogResponse(GtkDialog* dialog, gint response_id, gpointer user_data) { - auto* ctx = static_cast(user_data); - InAppWebView* self = ctx->webview; - - // Capture and clear reply before resolving (to prevent use after cleanup) - WebKitScriptMessageReply* reply = self->pending_date_reply_; - self->pending_date_reply_ = nullptr; - - // Helper lambda for cleanup - auto cleanup = [&]() { - delete ctx; - gtk_widget_destroy(GTK_WIDGET(dialog)); - g_object_unref(dialog); - self->active_date_dialog_ = nullptr; - self->date_dialog_show_time_ = 0; - }; - - if (reply == nullptr) { - // No reply object - just cleanup - cleanup(); - return; - } - - if (response_id == GTK_RESPONSE_OK) { - std::string result; - - if (ctx->inputType == "time") { - // Time only - int hour = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ctx->hourSpin)); - int minute = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ctx->minuteSpin)); - char buf[16]; - snprintf(buf, sizeof(buf), "%02d:%02d", hour, minute); - result = buf; - } else if (ctx->calendar != nullptr) { - // Get date from calendar - guint year, month, day; - gtk_calendar_get_date(GTK_CALENDAR(ctx->calendar), &year, &month, &day); - month += 1; // GtkCalendar months are 0-based - - if (ctx->inputType == "date") { - char buf[16]; - snprintf(buf, sizeof(buf), "%04d-%02d-%02d", year, month, day); - result = buf; - } else if (ctx->inputType == "datetime-local") { - int hour = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ctx->hourSpin)); - int minute = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ctx->minuteSpin)); - char buf[32]; - snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d", year, month, day, hour, minute); - result = buf; - } else if (ctx->inputType == "month") { - char buf[16]; - snprintf(buf, sizeof(buf), "%04d-%02d", year, month); - result = buf; - } else if (ctx->inputType == "week") { - // Calculate ISO week number - GDateTime* dt = g_date_time_new_local(year, month, day, 0, 0, 0); - if (dt) { - int isoYear = g_date_time_get_year(dt); - int weekNum = g_date_time_get_week_of_year(dt); - g_date_time_unref(dt); - char buf[16]; - snprintf(buf, sizeof(buf), "%04d-W%02d", isoYear, weekNum); - result = buf; - } - } - } - - if (!result.empty()) { - // Resolve the Promise with the selected value via webkit reply - self->ResolveInternalHandlerWithReply(reply, "\"" + result + "\""); - } else { - // No valid result - resolve with null - self->ResolveInternalHandlerWithReply(reply, "null"); - } - } else { - // User cancelled - resolve with null - self->ResolveInternalHandlerWithReply(reply, "null"); - } - - // Cleanup - cleanup(); -} - -void InAppWebView::ShowDatePicker(const std::string& inputType, const std::string& value, - const std::string& min, const std::string& max, - const std::string& step, int x, int y) { - (void)x; // Position not used - GTK handles dialog placement - (void)y; - - // Close any existing date dialog - if (active_date_dialog_ != nullptr) { - gtk_widget_destroy(active_date_dialog_); - g_object_unref(active_date_dialog_); - active_date_dialog_ = nullptr; - } - - pending_date_input_value_ = value; - pending_date_input_type_ = inputType; - pending_date_input_min_ = min; - pending_date_input_max_ = max; - - // Determine dialog title - std::string title; - if (inputType == "date") title = "Select Date"; - else if (inputType == "datetime-local") title = "Select Date and Time"; - else if (inputType == "time") title = "Select Time"; - else if (inputType == "month") title = "Select Month"; - else if (inputType == "week") title = "Select Week"; - else title = "Select Date"; - - // Create a dialog with the parent window - GtkWidget* dialog = gtk_dialog_new_with_buttons( - title.c_str(), - gtk_window_, - GTK_DIALOG_DESTROY_WITH_PARENT, - "_Cancel", GTK_RESPONSE_CANCEL, - "_OK", GTK_RESPONSE_OK, - nullptr); - - active_date_dialog_ = dialog; - g_object_ref(dialog); - - // Set dialog as transient for parent (floats above but doesn't block) - if (gtk_window_) { - gtk_window_set_transient_for(GTK_WINDOW(dialog), gtk_window_); - } - - // Make the window non-resizable - gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); - - GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); - gtk_container_set_border_width(GTK_CONTAINER(content_area), 10); - - // Create context for callback - auto* ctx = new DateDialogContext(); - ctx->webview = this; - ctx->inputType = inputType; - ctx->calendar = nullptr; - ctx->hourSpin = nullptr; - ctx->minuteSpin = nullptr; - ctx->dialog = dialog; - - // Parse min/max constraints - ctx->hasMin = ParseIsoDate(min, &ctx->minYear, &ctx->minMonth, &ctx->minDay, &ctx->minHour, &ctx->minMinute); - ctx->hasMax = ParseIsoDate(max, &ctx->maxYear, &ctx->maxMonth, &ctx->maxDay, &ctx->maxHour, &ctx->maxMinute); - - // Parse step value for time inputs (step is in seconds) - int stepMinutes = 1; // Default minute step - if (!step.empty()) { - int stepSeconds = std::atoi(step.c_str()); - if (stepSeconds >= 60) { - stepMinutes = stepSeconds / 60; - } - } - - // Parse initial value - int initialYear = 2024, initialMonth = 1, initialDay = 1; - int initialHour = 12, initialMinute = 0; - ParseIsoDate(value, &initialYear, &initialMonth, &initialDay, &initialHour, &initialMinute); - - // Add calendar for date-related types - if (inputType == "date" || inputType == "datetime-local" || - inputType == "month" || inputType == "week") { - GtkWidget* calendar = gtk_calendar_new(); - ctx->calendar = calendar; - - // Set initial date (GtkCalendar months are 0-based) - gtk_calendar_select_month(GTK_CALENDAR(calendar), initialMonth - 1, initialYear); - gtk_calendar_select_day(GTK_CALENDAR(calendar), initialDay); - - // For month picker, hide day selection styling (user can still click but day isn't important) - if (inputType == "month") { - gtk_calendar_set_display_options(GTK_CALENDAR(calendar), - static_cast( - GTK_CALENDAR_SHOW_HEADING | GTK_CALENDAR_SHOW_DAY_NAMES)); - } - - // For week picker, show week numbers - if (inputType == "week") { - gtk_calendar_set_display_options(GTK_CALENDAR(calendar), - static_cast( - GTK_CALENDAR_SHOW_HEADING | GTK_CALENDAR_SHOW_DAY_NAMES | - GTK_CALENDAR_SHOW_WEEK_NUMBERS)); - } - - gtk_box_pack_start(GTK_BOX(content_area), calendar, TRUE, TRUE, 5); - - // Connect day-selected signal to validate against min/max - g_signal_connect(calendar, "day-selected", G_CALLBACK(OnCalendarDaySelected), ctx); - - // Add constraint info label if min or max is set - if (ctx->hasMin || ctx->hasMax) { - std::string constraintText; - if (ctx->hasMin && ctx->hasMax) { - char buf[64]; - snprintf(buf, sizeof(buf), "Range: %04d-%02d-%02d to %04d-%02d-%02d", - ctx->minYear, ctx->minMonth, ctx->minDay, - ctx->maxYear, ctx->maxMonth, ctx->maxDay); - constraintText = buf; - } else if (ctx->hasMin) { - char buf[32]; - snprintf(buf, sizeof(buf), "Min: %04d-%02d-%02d", ctx->minYear, ctx->minMonth, ctx->minDay); - constraintText = buf; - } else { - char buf[32]; - snprintf(buf, sizeof(buf), "Max: %04d-%02d-%02d", ctx->maxYear, ctx->maxMonth, ctx->maxDay); - constraintText = buf; - } - GtkWidget* constraintLabel = gtk_label_new(constraintText.c_str()); - gtk_widget_set_opacity(constraintLabel, 0.7); - gtk_box_pack_start(GTK_BOX(content_area), constraintLabel, FALSE, FALSE, 2); - } - - // For date type with no time, double-click on day to confirm quickly - if (inputType == "date") { - g_signal_connect(calendar, "day-selected-double-click", - G_CALLBACK(+[](GtkCalendar*, gpointer user_data) { - auto* dialog = GTK_DIALOG(user_data); - gtk_dialog_response(dialog, GTK_RESPONSE_OK); - }), dialog); - } - } - - // Add time spinners for time-related types - if (inputType == "time" || inputType == "datetime-local") { - GtkWidget* timeBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); - gtk_widget_set_halign(timeBox, GTK_ALIGN_CENTER); - - // Hour spinner - GtkAdjustment* hourAdj = gtk_adjustment_new(initialHour, 0, 23, 1, 1, 0); - GtkWidget* hourSpin = gtk_spin_button_new(hourAdj, 1, 0); - gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(hourSpin), TRUE); - gtk_entry_set_width_chars(GTK_ENTRY(hourSpin), 2); - ctx->hourSpin = hourSpin; - - // Separator - GtkWidget* separator = gtk_label_new(":"); - - // Minute spinner (use step if provided) - GtkAdjustment* minuteAdj = gtk_adjustment_new(initialMinute, 0, 59, stepMinutes, stepMinutes * 5, 0); - GtkWidget* minuteSpin = gtk_spin_button_new(minuteAdj, 1, 0); - gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(minuteSpin), TRUE); - gtk_entry_set_width_chars(GTK_ENTRY(minuteSpin), 2); - gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(minuteSpin), stepMinutes > 1 ? TRUE : FALSE); - ctx->minuteSpin = minuteSpin; - - gtk_box_pack_start(GTK_BOX(timeBox), gtk_label_new("Time:"), FALSE, FALSE, 5); - gtk_box_pack_start(GTK_BOX(timeBox), hourSpin, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(timeBox), separator, FALSE, FALSE, 2); - gtk_box_pack_start(GTK_BOX(timeBox), minuteSpin, FALSE, FALSE, 0); - - gtk_box_pack_start(GTK_BOX(content_area), timeBox, FALSE, FALSE, 10); - - // Add time constraint info for time-only input - if (inputType == "time" && (ctx->hasMin || ctx->hasMax)) { - std::string timeConstraint; - if (ctx->hasMin && ctx->hasMax) { - char buf[32]; - snprintf(buf, sizeof(buf), "Range: %02d:%02d to %02d:%02d", - ctx->minHour, ctx->minMinute, ctx->maxHour, ctx->maxMinute); - timeConstraint = buf; - } else if (ctx->hasMin) { - char buf[16]; - snprintf(buf, sizeof(buf), "Min: %02d:%02d", ctx->minHour, ctx->minMinute); - timeConstraint = buf; - } else { - char buf[16]; - snprintf(buf, sizeof(buf), "Max: %02d:%02d", ctx->maxHour, ctx->maxMinute); - timeConstraint = buf; - } - GtkWidget* timeConstraintLabel = gtk_label_new(timeConstraint.c_str()); - gtk_widget_set_opacity(timeConstraintLabel, 0.7); - gtk_box_pack_start(GTK_BOX(content_area), timeConstraintLabel, FALSE, FALSE, 2); - } - } - - // Connect response signal - g_signal_connect(dialog, "response", G_CALLBACK(OnDateDialogResponse), ctx); - - // Handle focus-out to auto-close (like a dropdown) - g_signal_connect(dialog, "focus-out-event", - G_CALLBACK(+[](GtkWidget* widget, GdkEventFocus*, gpointer) -> gboolean { - // Don't auto-close - let user interact freely - // They can click Cancel or click outside to dismiss - (void)widget; - return FALSE; // Don't consume the event - }), nullptr); - - // Show the dialog and all its children - gtk_widget_show_all(dialog); - - date_dialog_show_time_ = g_get_monotonic_time(); -} - -void InAppWebView::HideDatePicker() { - if (active_date_dialog_ != nullptr) { - int64_t now = g_get_monotonic_time(); - int64_t elapsed_us = now - date_dialog_show_time_; - if (elapsed_us < 200000) { - return; // Don't close if just shown - } - - // Capture and clear reply before resolving - WebKitScriptMessageReply* reply = pending_date_reply_; - pending_date_reply_ = nullptr; - - // Resolve the pending Promise with null when hiding the picker - if (reply != nullptr) { - ResolveInternalHandlerWithReply(reply, "null"); - } - - gtk_widget_destroy(active_date_dialog_); - g_object_unref(active_date_dialog_); - active_date_dialog_ = nullptr; - date_dialog_show_time_ = 0; - } -} - -// === Clipboard Operations === -// WPE WebKit runs offscreen and doesn't share clipboard with the system by default. -// These methods sync WebKit's internal clipboard with the GTK/system clipboard. - -void InAppWebView::getSelectedText(std::function&)> callback) { - if (webview_ == nullptr || callback == nullptr) { - if (callback) callback(std::nullopt); - return; - } - - evaluateJavascript( - "window.getSelection().toString()", - std::nullopt, - [callback](const std::optional& result) { - if (!result.has_value() || result->empty() || *result == "null") { - callback(std::nullopt); - return; - } - - std::string text = *result; - - // Parse JSON string result using nlohmann/json - try { - auto parsed = json::parse(text); - if (parsed.is_string()) { - text = parsed.get(); - } - } catch (const json::exception&) { - // If parsing fails, try manual unquoting for simple cases - if (text.size() >= 2 && text.front() == '"' && text.back() == '"') { - text = text.substr(1, text.size() - 2); - } - } - - if (text.empty()) { - callback(std::nullopt); - } else { - callback(text); - } - }); -} - -void InAppWebView::isSecureContext(std::function callback) { - if (webview_ == nullptr || callback == nullptr) { - if (callback) callback(false); - return; - } - - evaluateJavascript("window.isSecureContext", - std::nullopt, - [callback](const std::optional& result) { - bool isSecure = false; - if (result.has_value() && *result == "true") { - isSecure = true; - } - callback(isSecure); - }); -} - -// === Media Playback Control === - -void InAppWebView::pauseAllMediaPlayback() { - if (webview_ == nullptr) return; - - // Pause all audio and video elements in the page - const char* script = R"( - (function() { - var mediaElements = document.querySelectorAll('audio, video'); - mediaElements.forEach(function(el) { - if (!el.paused) { - el.pause(); - } - }); - })(); - )"; - evaluateJavascript(script, std::nullopt, nullptr); -} - -void InAppWebView::setAllMediaPlaybackSuspended(bool suspended) { - if (webview_ == nullptr) return; - - // Suspend or resume all media elements - // When suspended=true, pause all and mark with a data attribute - // When suspended=false, resume only those that were playing before - std::string script; - if (suspended) { - script = R"( - (function() { - var mediaElements = document.querySelectorAll('audio, video'); - mediaElements.forEach(function(el) { - if (!el.paused) { - el.dataset.wasPlaying = 'true'; - el.pause(); - } else { - el.dataset.wasPlaying = 'false'; - } - }); - })(); - )"; - } else { - script = R"( - (function() { - var mediaElements = document.querySelectorAll('audio, video'); - mediaElements.forEach(function(el) { - if (el.dataset.wasPlaying === 'true') { - el.play().catch(function() {}); - delete el.dataset.wasPlaying; - } - }); - })(); - )"; - } - evaluateJavascript(script, std::nullopt, nullptr); -} - -void InAppWebView::closeAllMediaPresentations() { - if (webview_ == nullptr) return; - - // Exit fullscreen if any media is in fullscreen, and exit picture-in-picture - const char* script = R"( - (function() { - // Exit fullscreen - if (document.fullscreenElement) { - document.exitFullscreen().catch(function() {}); - } - // Exit picture-in-picture - if (document.pictureInPictureElement) { - document.exitPictureInPicture().catch(function() {}); - } - // Also pause all media - var mediaElements = document.querySelectorAll('audio, video'); - mediaElements.forEach(function(el) { - if (!el.paused) { - el.pause(); - } - }); - })(); - )"; - evaluateJavascript(script, std::nullopt, nullptr); -} - -void InAppWebView::requestMediaPlaybackState(std::function callback) { - if (webview_ == nullptr || callback == nullptr) { - if (callback) callback(0); // NONE - return; - } - - // Use native WPE WebKit API for PLAYING detection (webkit_web_view_is_playing_audio) - // This is more accurate than JavaScript as it's tracked at the browser level - // Returns: 0 = NONE, 1 = PAUSED, 2 = SUSPENDED, 3 = PLAYING - - gboolean isPlayingAudio = webkit_web_view_is_playing_audio(webview_); - - if (isPlayingAudio) { - // Native API confirms audio is playing - return PLAYING immediately - callback(3); // PLAYING - return; - } - - // If not playing, use JavaScript to determine if we have media elements - // and whether they are paused normally or suspended via our API - const char* script = R"( - (function() { - var mediaElements = document.querySelectorAll('audio, video'); - if (mediaElements.length === 0) { - return 0; // NONE - no media elements - } - var hasSuspended = false; - var hasPaused = false; - mediaElements.forEach(function(el) { - if (el.dataset.wasPlaying === 'true') { - hasSuspended = true; - } else if (el.paused || el.ended) { - hasPaused = true; - } - }); - if (hasSuspended) return 2; // SUSPENDED (paused via setAllMediaPlaybackSuspended) - if (hasPaused) return 1; // PAUSED (normal pause) - return 0; // NONE - })(); - )"; - - evaluateJavascript(script, std::nullopt, [callback](const std::optional& result) { - int state = 0; // NONE - if (result.has_value()) { - try { - state = std::stoi(*result); - } catch (...) { - state = 0; - } - } - callback(state); - }); -} - -// === Media Capture State (Camera and Microphone) === - -int InAppWebView::getCameraCaptureState() const { - if (webview_ == nullptr) return 0; // NONE - - // WPE WebKit returns WebKitMediaCaptureState enum: - // WEBKIT_MEDIA_CAPTURE_STATE_NONE = 0 - // WEBKIT_MEDIA_CAPTURE_STATE_ACTIVE = 1 - // WEBKIT_MEDIA_CAPTURE_STATE_MUTED = 2 - WebKitMediaCaptureState state = webkit_web_view_get_camera_capture_state(webview_); - return static_cast(state); -} - -void InAppWebView::setCameraCaptureState(int state) { - if (webview_ == nullptr) return; - - // state: 0 = NONE, 1 = ACTIVE, 2 = MUTED - // Note: Once state is set to NONE, it cannot be changed back (per WPE docs) - // The page can request capture again using mediaDevices API - WebKitMediaCaptureState captureState = static_cast(state); - webkit_web_view_set_camera_capture_state(webview_, captureState); -} - -int InAppWebView::getMicrophoneCaptureState() const { - if (webview_ == nullptr) return 0; // NONE - - WebKitMediaCaptureState state = webkit_web_view_get_microphone_capture_state(webview_); - return static_cast(state); -} - -void InAppWebView::setMicrophoneCaptureState(int state) { - if (webview_ == nullptr) return; - - WebKitMediaCaptureState captureState = static_cast(state); - webkit_web_view_set_microphone_capture_state(webview_, captureState); -} - -// === Theme Color === - -std::optional InAppWebView::getMetaThemeColor() const { - if (webview_ == nullptr) return std::nullopt; - - WebKitColor color; - gboolean hasColor = webkit_web_view_get_theme_color(webview_, &color); - - if (!hasColor) { - return std::nullopt; - } - - // Convert WebKitColor (RGBA in 0.0-1.0 range) to hex string format #RRGGBBAA - // Note: WebKitColor has red, green, blue, alpha as gdouble (0.0-1.0) - int r = static_cast(color.red * 255.0 + 0.5); - int g = static_cast(color.green * 255.0 + 0.5); - int b = static_cast(color.blue * 255.0 + 0.5); - int a = static_cast(color.alpha * 255.0 + 0.5); - - // Clamp values to 0-255 - r = std::max(0, std::min(255, r)); - g = std::max(0, std::min(255, g)); - b = std::max(0, std::min(255, b)); - a = std::max(0, std::min(255, a)); - - char hexColor[10]; - if (a == 255) { - snprintf(hexColor, sizeof(hexColor), "#%02X%02X%02X", r, g, b); - } else { - snprintf(hexColor, sizeof(hexColor), "#%02X%02X%02X%02X", r, g, b, a); - } - - return std::string(hexColor); -} - -// === Audio State (Playing and Mute) === - -bool InAppWebView::isPlayingAudio() const { - if (webview_ == nullptr) return false; - - // WPE WebKit 2.8+ - return webkit_web_view_is_playing_audio(webview_) == TRUE; -} - -bool InAppWebView::isMuted() const { - if (webview_ == nullptr) return false; - - // WPE WebKit 2.30+ - return webkit_web_view_get_is_muted(webview_) == TRUE; -} - -void InAppWebView::setMuted(bool muted) { - if (webview_ == nullptr) return; - - // WPE WebKit 2.30+ - webkit_web_view_set_is_muted(webview_, muted ? TRUE : FALSE); -} - -// === Web Process Control === - -void InAppWebView::terminateWebProcess() { - if (webview_ == nullptr) return; - - // WPE WebKit 2.34+ - // Terminates the web process. The web-process-terminated signal will be emitted - // with WEBKIT_WEB_PROCESS_TERMINATED_BY_API as the reason. - webkit_web_view_terminate_web_process(webview_); -} - -// === Focus Control === - -bool InAppWebView::clearFocus() { - if (webview_ == nullptr) return false; - - // Remove focused state from WPE backend - setFocused(false); - - return true; -} - -bool InAppWebView::requestFocus() { - if (webview_ == nullptr) return false; - - // Add focused state to WPE backend - setFocused(true); - - return true; -} - -// === Web Archive === - -void InAppWebView::saveWebArchive(const std::string& filePath, bool autoname, - std::function&)> callback) { - if (webview_ == nullptr || callback == nullptr) { - if (callback) callback(std::nullopt); - return; - } - - std::string finalPath = filePath; - - // If autoname is true, generate a filename based on the current URL - if (autoname) { - const gchar* uri = webkit_web_view_get_uri(webview_); - if (uri == nullptr) { - callback(std::nullopt); - return; - } - - // Clean the URL to create a valid filename - std::string urlStr(uri); - // Replace invalid filename characters - std::string filename; - for (char c : urlStr) { - if (c == '/' || c == '\\' || c == ':' || c == '*' || - c == '?' || c == '"' || c == '<' || c == '>' || c == '|') { - filename += '_'; - } else { - filename += c; - } - } - - // Limit filename length - if (filename.length() > 200) { - filename = filename.substr(0, 200); - } - - // Append .mht extension (WPE WebKit saves as MHTML) - finalPath = filePath + "/" + filename + ".mht"; - } - - // Create GFile for the destination - GFile* file = g_file_new_for_path(finalPath.c_str()); - if (file == nullptr) { - callback(std::nullopt); - return; - } - - // Create callback data structure - struct SaveCallbackData { - std::function&)> callback; - std::string filePath; - InAppWebView* self; - }; - - auto* data = new SaveCallbackData{callback, finalPath, this}; - - // Use webkit_web_view_save_to_file with MHTML format - webkit_web_view_save_to_file( - webview_, - file, - WEBKIT_SAVE_MODE_MHTML, - nullptr, // GCancellable - [](GObject* source_object, GAsyncResult* result, gpointer user_data) { - auto* callbackData = static_cast(user_data); - WebKitWebView* webView = WEBKIT_WEB_VIEW(source_object); - - GError* error = nullptr; - gboolean success = webkit_web_view_save_to_file_finish(webView, result, &error); - - if (success) { - callbackData->callback(callbackData->filePath); - } else { - if (error != nullptr) { - debugLog("InAppWebView::saveWebArchive failed: " + std::string(error->message)); - g_error_free(error); - } - callbackData->callback(std::nullopt); - } - - delete callbackData; - }, - data - ); - - g_object_unref(file); -} - -void InAppWebView::copyToClipboard() { - if (webview_ == nullptr) return; - - getSelectedText([this](const std::optional& text) { - if (text.has_value() && !text->empty()) { - copyTextToClipboard(*text); - } - }); - - // Also execute WebKit's copy command for internal state - webkit_web_view_execute_editing_command(webview_, WEBKIT_EDITING_COMMAND_COPY); -} - -void InAppWebView::cutToClipboard() { - if (webview_ == nullptr) return; - - getSelectedText([this](const std::optional& text) { - if (text.has_value() && !text->empty()) { - copyTextToClipboard(*text); - } - }); - - // Execute WebKit's cut command to remove the selection - webkit_web_view_execute_editing_command(webview_, WEBKIT_EDITING_COMMAND_CUT); -} - -void InAppWebView::pasteFromClipboard() { - if (webview_ == nullptr) return; - - // Check if JavaScript is disabled - use WebKit's paste command as fallback - bool jsEnabled = settings_ ? settings_->javaScriptEnabled : true; - - // Get text from system clipboard - GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); - gchar* text = gtk_clipboard_wait_for_text(clipboard); - - if (text != nullptr && strlen(text) > 0) { - if (jsEnabled) { - // Use JavaScript to insert text - std::string escaped; - escaped.reserve(strlen(text) * 2); - for (const char* p = text; *p; ++p) { - switch (*p) { - case '\\': escaped += "\\\\"; break; - case '"': escaped += "\\\""; break; - case '\n': escaped += "\\n"; break; - case '\r': escaped += "\\r"; break; - case '\t': escaped += "\\t"; break; - default: escaped += *p; break; - } - } - g_free(text); - - // Insert text at current cursor position using execCommand - std::string js = "document.execCommand('insertText', false, \"" + escaped + "\")"; - evaluateJavascript(js, std::nullopt, nullptr); - } else { - // JavaScript disabled - use WebKit's paste command - g_free(text); - webkit_web_view_execute_editing_command(webview_, WEBKIT_EDITING_COMMAND_PASTE); - } - } else { - if (text) g_free(text); - // If system clipboard is empty, try WebKit's paste (may have its own content) - webkit_web_view_execute_editing_command(webview_, WEBKIT_EDITING_COMMAND_PASTE); - } -} - -void InAppWebView::copyTextToClipboard(const std::string& text) { - if (text.empty()) return; - - // 1. Copy to GTK/system clipboard - GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); - gtk_clipboard_set_text(clipboard, text.c_str(), -1); - gtk_clipboard_store(clipboard); - - // 2. Copy to WebView's internal clipboard using the Clipboard API - // This ensures the text is available for paste within the webview - if (webview_ != nullptr) { - // Escape text for JavaScript - std::string escaped; - escaped.reserve(text.size() * 2); - for (char c : text) { - switch (c) { - case '\\': escaped += "\\\\"; break; - case '"': escaped += "\\\""; break; - case '\n': escaped += "\\n"; break; - case '\r': escaped += "\\r"; break; - case '\t': escaped += "\\t"; break; - case '`': escaped += "\\`"; break; - case '$': escaped += "\\$"; break; - default: escaped += c; break; - } - } - - // Use the modern Clipboard API with fallback - std::string js = R"( - (async function() { - const text = ")" + escaped + R"("; - try { - if (navigator.clipboard && navigator.clipboard.writeText) { - await navigator.clipboard.writeText(text); - } - } catch (e) { - // Fallback: create temporary textarea and use execCommand - const textarea = document.createElement('textarea'); - textarea.value = text; - textarea.style.position = 'fixed'; - textarea.style.opacity = '0'; - document.body.appendChild(textarea); - textarea.select(); - document.execCommand('copy'); - document.body.removeChild(textarea); - } - })(); - )"; - evaluateJavascript(js, std::nullopt, nullptr); - } -} - -void InAppWebView::pasteAsPlainText() { - if (webview_ == nullptr) return; - - // Check if JavaScript is disabled - use WebKit's paste as plain text command as fallback - bool jsEnabled = settings_ ? settings_->javaScriptEnabled : true; - - // Get text from system clipboard - GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); - gchar* text = gtk_clipboard_wait_for_text(clipboard); - - if (text != nullptr && strlen(text) > 0) { - if (jsEnabled) { - // Use JavaScript to insert text (already plain text from gtk_clipboard_wait_for_text) - std::string escaped; - escaped.reserve(strlen(text) * 2); - for (const char* p = text; *p; ++p) { - switch (*p) { - case '\\': escaped += "\\\\"; break; - case '"': escaped += "\\\""; break; - case '\n': escaped += "\\n"; break; - case '\r': escaped += "\\r"; break; - case '\t': escaped += "\\t"; break; - default: escaped += *p; break; - } - } - g_free(text); - - // Insert text at current cursor position using execCommand - std::string js = "document.execCommand('insertText', false, \"" + escaped + "\")"; - evaluateJavascript(js, std::nullopt, nullptr); - } else { - // JavaScript disabled - use WebKit's paste as plain text command - g_free(text); - webkit_web_view_execute_editing_command(webview_, WEBKIT_EDITING_COMMAND_PASTE_AS_PLAIN_TEXT); - } - } else { - if (text) g_free(text); - // If system clipboard is empty, try WebKit's paste as plain text - webkit_web_view_execute_editing_command(webview_, WEBKIT_EDITING_COMMAND_PASTE_AS_PLAIN_TEXT); - } -} - -void InAppWebView::selectAll() { - if (webview_ == nullptr) return; - webkit_web_view_execute_editing_command(webview_, WEBKIT_EDITING_COMMAND_SELECT_ALL); -} - -void InAppWebView::undo() { - if (webview_ == nullptr) return; - webkit_web_view_execute_editing_command(webview_, WEBKIT_EDITING_COMMAND_UNDO); -} - -void InAppWebView::redo() { - if (webview_ == nullptr) return; - webkit_web_view_execute_editing_command(webview_, WEBKIT_EDITING_COMMAND_REDO); -} - -void InAppWebView::insertImage(const std::string& imageUri) { - if (webview_ == nullptr || imageUri.empty()) return; - webkit_web_view_execute_editing_command_with_argument( - webview_, WEBKIT_EDITING_COMMAND_INSERT_IMAGE, imageUri.c_str()); -} - -void InAppWebView::createLink(const std::string& linkUri) { - if (webview_ == nullptr || linkUri.empty()) return; - webkit_web_view_execute_editing_command_with_argument( - webview_, WEBKIT_EDITING_COMMAND_CREATE_LINK, linkUri.c_str()); -} - -gboolean InAppWebView::OnEnterFullscreen(WebKitWebView* web_view, gpointer user_data) { - auto* self = static_cast(user_data); - self->is_fullscreen_ = true; - - // Notify WPE backend that we entered fullscreen -#ifdef HAVE_WPE_BACKEND_LEGACY - if (self->wpe_backend_ != nullptr) { - wpe_view_backend_dispatch_did_enter_fullscreen(self->wpe_backend_); - } -#endif - - if (self->channel_delegate_) { - self->channel_delegate_->onEnterFullscreen(); - } - return TRUE; // We handled the fullscreen request -} - -gboolean InAppWebView::OnLeaveFullscreen(WebKitWebView* web_view, gpointer user_data) { - auto* self = static_cast(user_data); - self->is_fullscreen_ = false; - - // Notify WPE backend that we exited fullscreen -#ifdef HAVE_WPE_BACKEND_LEGACY - if (self->wpe_backend_ != nullptr) { - wpe_view_backend_dispatch_did_exit_fullscreen(self->wpe_backend_); - } -#endif - - if (self->channel_delegate_) { - self->channel_delegate_->onExitFullscreen(); - } - return TRUE; // We handled the fullscreen exit -} - -void InAppWebView::OnMouseTargetChanged(WebKitWebView* web_view, - WebKitHitTestResult* hit_test_result, guint modifiers, - gpointer user_data) { - auto* self = static_cast(user_data); - - // Store the hit test result for getHitTestResult() - // Release previous result and ref new one (if not null) - if (self->last_hit_test_result_ != nullptr) { - g_object_unref(self->last_hit_test_result_); - self->last_hit_test_result_ = nullptr; - } - if (hit_test_result != nullptr) { - self->last_hit_test_result_ = hit_test_result; - g_object_ref(hit_test_result); - } - - // Determine cursor based on hit test result - // Use CSS cursor names which gdk_cursor_new_from_name() supports - std::string cursor_name = "default"; - - if (hit_test_result == nullptr) { - // No hit test result, use default cursor - } else if (webkit_hit_test_result_context_is_link(hit_test_result)) { - cursor_name = "pointer"; // Hand cursor for links - } else if (webkit_hit_test_result_context_is_editable(hit_test_result)) { - cursor_name = "text"; // Text cursor for editable content - } else if (webkit_hit_test_result_context_is_selection(hit_test_result)) { - cursor_name = "text"; // Text cursor for selection - } else if (webkit_hit_test_result_context_is_image(hit_test_result)) { - // Check if image is also a link - if (webkit_hit_test_result_context_is_link(hit_test_result)) { - cursor_name = "pointer"; - } - } else if (webkit_hit_test_result_context_is_media(hit_test_result)) { - cursor_name = "default"; - } else if (webkit_hit_test_result_context_is_scrollbar(hit_test_result)) { - cursor_name = "default"; - } - - // Only emit if cursor changed - if (cursor_name != self->last_cursor_name_) { - self->last_cursor_name_ = cursor_name; - if (self->on_cursor_changed_) { - self->on_cursor_changed_(cursor_name); - } - } -} - -void InAppWebView::OnWebProcessTerminated(WebKitWebView* web_view, - WebKitWebProcessTerminationReason reason, - gpointer user_data) { - auto* self = static_cast(user_data); - - // Determine if this was a crash or a kill - // - WEBKIT_WEB_PROCESS_CRASHED: The web process crashed -> didCrash = true - // - WEBKIT_WEB_PROCESS_EXCEEDED_MEMORY_LIMIT: Killed by system due to memory -> didCrash = false - // - WEBKIT_WEB_PROCESS_TERMINATED_BY_API: Terminated via API call -> didCrash = false - bool didCrash = (reason == WEBKIT_WEB_PROCESS_CRASHED); - - // Log the termination with detailed information - const char* reason_str = "unknown"; - switch (reason) { - case WEBKIT_WEB_PROCESS_CRASHED: - reason_str = "CRASHED"; - break; - case WEBKIT_WEB_PROCESS_EXCEEDED_MEMORY_LIMIT: - reason_str = "EXCEEDED_MEMORY_LIMIT"; - break; - case WEBKIT_WEB_PROCESS_TERMINATED_BY_API: - reason_str = "TERMINATED_BY_API"; - break; - default: - break; - } - - g_warning("InAppWebView[%ld]: WebProcess terminated (reason=%s, didCrash=%s)", - self->id_, reason_str, didCrash ? "true" : "false"); - -#ifdef HAVE_WPE_BACKEND_LEGACY - // IMPORTANT: When WebProcess crashes (especially from "Failed to bind wl_compositor"), - // the WPE FDO connection is broken. We should NOT call any WPE FDO functions here - // as they may cause additional errors or hangs. Simply null out the pointer. - // - // The exported_image_ was being used by the crashed WebProcess, and its underlying - // Wayland resources are now invalid. Calling wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image - // on a broken connection can cause further issues. - { - std::lock_guard lock(self->exported_image_mutex_); - if (self->exported_image_ != nullptr) { - g_message("InAppWebView[%ld]: Nulling stale EGL image %p after WebProcess termination (not releasing via WPE FDO)", - self->id_, (void*)self->exported_image_); - // Don't call WPE FDO release - the connection is broken - self->exported_image_ = nullptr; - } - } -#endif // HAVE_WPE_BACKEND_LEGACY - - if (self->channel_delegate_) { - self->channel_delegate_->onRenderProcessGone(didCrash); - } -} - -// Static callback for non-blocking file chooser dialog response -static void OnFileChooserDialogResponse(GtkDialog* dialog, gint response_id, gpointer user_data) { - auto* context = static_cast(user_data); - - // Check if this dialog is still the active one (prevents double-cleanup) - if (context->webview && context->webview->active_file_dialog_ != GTK_WIDGET(dialog)) { - // Dialog was already cleaned up by HideFileChooser(), just delete context - delete context; - return; - } - - GtkFileChooser* chooser = GTK_FILE_CHOOSER(dialog); - - if (response_id == GTK_RESPONSE_ACCEPT) { - if (context->selectMultiple) { - // Get multiple files - GSList* files = gtk_file_chooser_get_filenames(chooser); - if (files != nullptr) { - std::vector filePaths; - for (GSList* item = files; item != nullptr; item = item->next) { - gchar* filename = static_cast(item->data); - if (filename != nullptr) { - // Convert to file:// URI - gchar* uri = g_filename_to_uri(filename, nullptr, nullptr); - if (uri != nullptr) { - filePaths.push_back(uri); - g_free(uri); - } - g_free(filename); - } - } - g_slist_free(files); - - // Convert to gchar** format for WebKit - std::vector uris; - for (const auto& path : filePaths) { - uris.push_back(path.c_str()); - } - uris.push_back(nullptr); // NULL-terminated - webkit_file_chooser_request_select_files(context->request, uris.data()); - } else { - webkit_file_chooser_request_cancel(context->request); - } - } else { - // Get single file - gchar* filename = gtk_file_chooser_get_filename(chooser); - if (filename != nullptr) { - gchar* uri = g_filename_to_uri(filename, nullptr, nullptr); - if (uri != nullptr) { - const gchar* uris[] = {uri, nullptr}; - webkit_file_chooser_request_select_files(context->request, uris); - g_free(uri); - } else { - webkit_file_chooser_request_cancel(context->request); - } - g_free(filename); - } else { - webkit_file_chooser_request_cancel(context->request); - } - } - } else { - // User cancelled (Cancel button, X button, or Escape key) - webkit_file_chooser_request_cancel(context->request); - } - - // Clear tracking in webview - if (context->webview) { - context->webview->active_file_dialog_ = nullptr; - context->webview->file_dialog_show_time_ = 0; - context->webview->file_chooser_context_ = nullptr; - } - - gtk_widget_destroy(GTK_WIDGET(dialog)); - g_object_unref(dialog); // Release our extra reference - delete context; -} - -// Helper function to show native GTK file chooser dialog (non-blocking) -static void ShowNativeFileChooser(InAppWebView* webview, - WebKitFileChooserRequest* request, - bool selectMultiple, - const std::vector& mimeTypes, - GtkWindow* parentWindow) { - // Close any existing file dialog first - if (webview && webview->active_file_dialog_ != nullptr) { - // Clean up old context if it exists - if (webview->file_chooser_context_ != nullptr) { - auto* old_context = static_cast(webview->file_chooser_context_); - if (old_context->response_handler_id != 0) { - g_signal_handler_disconnect(webview->active_file_dialog_, old_context->response_handler_id); - } - webkit_file_chooser_request_cancel(old_context->request); - delete old_context; - webview->file_chooser_context_ = nullptr; - } - gtk_widget_destroy(webview->active_file_dialog_); - g_object_unref(webview->active_file_dialog_); - webview->active_file_dialog_ = nullptr; - } - - // Create the file chooser dialog with parent window - GtkWidget* dialog = gtk_file_chooser_dialog_new( - "Select File", - parentWindow, - GTK_FILE_CHOOSER_ACTION_OPEN, - "_Cancel", GTK_RESPONSE_CANCEL, - "_Open", GTK_RESPONSE_ACCEPT, - nullptr); - - // Track the dialog in webview - if (webview) { - webview->active_file_dialog_ = dialog; - } - - // Set dialog as transient for parent (floats above but doesn't block) - if (parentWindow) { - gtk_window_set_transient_for(GTK_WINDOW(dialog), parentWindow); - } - - // Take an extra reference to prevent premature destruction - g_object_ref(dialog); - - GtkFileChooser* chooser = GTK_FILE_CHOOSER(dialog); - - // Enable multiple selection if requested - gtk_file_chooser_set_select_multiple(chooser, selectMultiple ? TRUE : FALSE); - - // Add file filters based on MIME types - if (!mimeTypes.empty()) { - GtkFileFilter* filter = gtk_file_filter_new(); - gtk_file_filter_set_name(filter, "Allowed files"); - for (const auto& mimeType : mimeTypes) { - gtk_file_filter_add_mime_type(filter, mimeType.c_str()); - } - gtk_file_chooser_add_filter(chooser, filter); - - // Also add an "All files" filter - GtkFileFilter* allFilter = gtk_file_filter_new(); - gtk_file_filter_set_name(allFilter, "All files"); - gtk_file_filter_add_pattern(allFilter, "*"); - gtk_file_chooser_add_filter(chooser, allFilter); - } - - // Create context for the callback - auto* context = new FileChooserContext(request, selectMultiple, webview); - - // Store context pointer in webview for cleanup in HideFileChooser - if (webview) { - webview->file_chooser_context_ = context; - } - - // Connect to response signal for non-blocking behavior - context->response_handler_id = g_signal_connect(dialog, "response", - G_CALLBACK(OnFileChooserDialogResponse), context); - - // Show the dialog and all its children (non-blocking) - gtk_widget_show_all(dialog); - - // Record show time to prevent immediate close by pointer events - if (webview) { - webview->file_dialog_show_time_ = g_get_monotonic_time(); - } -} - -gboolean InAppWebView::OnRunFileChooser(WebKitWebView* web_view, - WebKitFileChooserRequest* request, - gpointer user_data) { - auto* self = static_cast(user_data); - - // Get file chooser properties - gboolean select_multiple = webkit_file_chooser_request_get_select_multiple(request); - const gchar* const* mime_types = webkit_file_chooser_request_get_mime_types(request); - - // Build accept types list - std::vector acceptTypes; - if (mime_types) { - for (int i = 0; mime_types[i] != nullptr; i++) { - acceptTypes.push_back(mime_types[i]); - } - } - - // If no channel delegate, show native dialog directly - if (!self->channel_delegate_) { - ShowNativeFileChooser(self, request, select_multiple, acceptTypes, self->gtk_window_); - return TRUE; - } - - // Keep request alive during async callback - g_object_ref(request); - - // Determine mode: OPEN or OPEN_MULTIPLE (WPE doesn't have folder/save modes in this API) - int mode = select_multiple ? 1 : 0; // 0 = OPEN, 1 = OPEN_MULTIPLE - - // Capture variables for the lambda - bool selectMultipleCopy = select_multiple; - std::vector acceptTypesCopy = acceptTypes; - GtkWindow* parentWindow = self->gtk_window_; - - self->channel_delegate_->onShowFileChooser( - mode, - acceptTypes, - false, // isCaptureEnabled - not exposed by WPE API - std::nullopt, // title - std::nullopt, // filenameHint - [self, request, selectMultipleCopy, acceptTypesCopy, parentWindow](ShowFileChooserResponse response) { - if (response.handledByClient) { - // Client handled it - use the file paths from Dart - if (response.filePaths.has_value() && !response.filePaths->empty()) { - // Convert to gchar** format - std::vector files; - for (const auto& path : *response.filePaths) { - files.push_back(path.c_str()); - } - files.push_back(nullptr); // NULL-terminated - webkit_file_chooser_request_select_files(request, files.data()); - } else { - // Client handled but no files selected (cancelled) - webkit_file_chooser_request_cancel(request); - } - } else { - // Client didn't handle it - show native GTK file chooser - ShowNativeFileChooser(self, request, selectMultipleCopy, acceptTypesCopy, parentWindow); - } - g_object_unref(request); - }); - - return TRUE; // We handled it -} - -// === Option Menu (HTML support in WPE) - // Show the native color picker popup with optional predefined colors and alpha support - void ShowColorPicker(const std::string& initialColor, int x, int y, - const std::vector& predefinedColors = {}, - bool alphaEnabled = false, - const std::string& colorSpace = "limited-srgb"); - // Hide and cleanup any visible color picker - void HideColorPicker(); - // Hide and cleanup any visible file chooser dialog - void HideFileChooser(); - // Hide and cleanup any visible option menu (HTML support in WPE) - // Show the native date/time picker dialog - void ShowDatePicker(const std::string& inputType, const std::string& value, - const std::string& min, const std::string& max, - const std::string& step, int x, int y); - // Hide and cleanup any visible date picker - void HideDatePicker(); - - // Resolve an internal handler's Promise with a JSON result via WebKitScriptMessageReply - // Used by color/date picker dialogs to send the result back to JavaScript (works for iframes) - void ResolveInternalHandlerWithReply(WebKitScriptMessageReply* reply, const std::string& jsonResult); - - // JavaScript bridge handler using with_reply API (enables iframe support) - // Returns true if handled, false otherwise - bool handleScriptMessageWithReply(const std::string& body, WebKitScriptMessageReply* reply); - - // Reject an internal handler's Promise with an error message via WebKitScriptMessageReply - void RejectInternalHandlerWithReply(WebKitScriptMessageReply* reply, const std::string& errorMessage); - - // Hide all custom popups (context menu, color picker, file chooser, option menu, etc.) - // Use this when the webview state changes (resize, scroll, load, focus loss, etc.) - void HideAllPopups(); - - // Clipboard operations (syncs WPE WebKit clipboard with system clipboard) - void copyToClipboard(); - void cutToClipboard(); - void pasteFromClipboard(); - void pasteAsPlainText(); - void copyTextToClipboard(const std::string& text); // Copy arbitrary text to both clipboards - void getSelectedText(std::function&)> callback); - void isSecureContext(std::function callback); - - // Media playback control - void pauseAllMediaPlayback(); - void setAllMediaPlaybackSuspended(bool suspended); - void closeAllMediaPresentations(); - void requestMediaPlaybackState(std::function callback); - - // Media capture state (camera and microphone) - int getCameraCaptureState() const; - void setCameraCaptureState(int state); - int getMicrophoneCaptureState() const; - void setMicrophoneCaptureState(int state); - - // Theme color (from tag) - std::optional getMetaThemeColor() const; - - // Audio state (mute and playback) - bool isPlayingAudio() const; - bool isMuted() const; - void setMuted(bool muted); - - // Web process control - void terminateWebProcess(); - - // Focus control - bool clearFocus(); - bool requestFocus(); - - // Web archive (save page to file) - void saveWebArchive(const std::string& filePath, bool autoname, - std::function&)> callback); - - // Editing commands (WebKit editing commands) - void selectAll(); - void undo(); - void redo(); - void insertImage(const std::string& imageUri); - void createLink(const std::string& linkUri); - - // Check if WPE WebKit is available on the system - static bool IsWpeWebKitAvailable(); - -#ifdef HAVE_WPE_PLATFORM - // Check if DMA-BUF rendering should be used - // Returns true if DMA-BUF rendering is expected to work, false if SHM should be used - // Note: Environment detection is done at plugin registration via utils/software_rendering.h - static bool PreflightDmaBufSupport(); -#endif - - // === Multi-Window Support === - - // Set the window ID for this webview (used in window.open scenarios) - void setWindowId(int64_t windowId) { window_id_ = windowId; } - - // Get the window ID (null if not set) - std::optional getWindowId() const { return window_id_; } - - // Initialize the window ID JavaScript variable in the webview - // This injects JS to set window._flutter_inappwebview_windowId - void initializeWindowIdJS(); - - // Get the GTK window (for focus restoration after popup dialogs) - GtkWindow* getGtkWindow() const { return gtk_window_; } - - // Get the FlView (for focus restoration after popup dialogs) - FlView* getFlView() const { return fl_view_; } - - private: - PluginInstance* plugin_ = nullptr; // Plugin instance for accessing managers - FlPluginRegistrar* registrar_ = nullptr; - FlBinaryMessenger* messenger_ = nullptr; // Cached messenger from constructor - GtkWindow* gtk_window_ = nullptr; // Cached GTK window for context menu display - FlView* fl_view_ = nullptr; // Cached FlView for focus restoration - InAppWebViewManager* manager_ = nullptr; // Manager reference for multi-window support - int64_t id_ = 0; - int64_t channel_id_ = -1; - std::string string_channel_id_; // String-based channel ID for headless webviews - - // Settings - std::shared_ptr settings_; - - // Context menu configuration - std::shared_ptr context_menu_config_; - - // WPE WebKit view - WebKitWebView* webview_ = nullptr; - -#ifdef HAVE_WPE_PLATFORM - // === WPEPlatform API members (modern) === - WPEDisplay* wpe_display_ = nullptr; // Owned headless display - WPEView* wpe_view_ = nullptr; // From webkit_web_view_get_wpe_view, not owned - WPEToplevel* wpe_toplevel_ = nullptr; // From wpe_view_get_toplevel, not owned - - // Buffer rendering for WPEPlatform - WPEBuffer* current_buffer_ = nullptr; // Current frame buffer (borrowed, not owned) - void* current_egl_image_ = nullptr; // EGL image created from current buffer - uint32_t current_buffer_width_ = 0; // Width of current buffer - uint32_t current_buffer_height_ = 0; // Height of current buffer - gulong buffer_rendered_handler_ = 0; // Signal handler ID for buffer-rendered - gulong scale_changed_handler_ = 0; // Signal handler ID for notify::scale-factor - mutable std::mutex wpe_buffer_mutex_; // Mutex for thread-safe buffer access -#endif - -#ifdef HAVE_WPE_BACKEND_LEGACY - // === WPEBackend-FDO API members (legacy) === - WebKitWebViewBackend* backend_ = nullptr; - struct wpe_view_backend* wpe_backend_ = nullptr; - - // WPE FDO exportable (for DMA-BUF buffer export) - struct wpe_view_backend_exportable_fdo* exportable_ = nullptr; - - // Current EGL image from WPE (for zero-copy GPU texture sharing). - ::wpe_fdo_egl_exported_image* exported_image_ = nullptr; - - // Mutex for protecting exported_image_ access from multiple threads - mutable std::mutex exported_image_mutex_; - - // Flag to indicate the WebProcess has crashed and EGL resources are invalid - // This prevents using stale EGL images after a crash - std::atomic web_process_crashed_{false}; -#endif - - // EGL context for reading back pixels (both APIs) - void* egl_display_ = nullptr; // EGLDisplay - void* egl_context_ = nullptr; // EGLContext for readback - unsigned int fbo_ = 0; // Framebuffer object for EGL image binding - unsigned int readback_texture_ = 0; // Texture for EGL image - - // Triple buffering for pixel data (fallback when DMA-BUF not available) - static constexpr size_t kNumBuffers = 3; - struct PixelBuffer { - std::vector data; - size_t width = 0; - size_t height = 0; - }; - std::array pixel_buffers_; - std::atomic write_buffer_index_{0}; - std::atomic read_buffer_index_{1}; - mutable std::mutex buffer_swap_mutex_; - - // Flag to skip pixel readback when using zero-copy EGL texture mode - // When true, OnExportDmaBuf won't call ReadPixelsFromEglImage - bool skip_pixel_readback_ = false; - - // View dimensions - int width_ = 800; - int height_ = 600; - double scale_factor_ = 1.0; - - // Channel delegate - std::unique_ptr channel_delegate_; - - // User content controller - std::unique_ptr user_content_controller_; - - // Find interaction controller - std::unique_ptr findInteractionController_; - - // Content blocker handler for Safari-style content blocking rules - std::unique_ptr content_blocker_handler_; - - // Web message channels (for WebMessageChannel support) - std::map> web_message_channels_; - - // Web message listeners (for WebMessageListener support - federated plugin pattern) - // Key is jsObjectName, value is the WebMessageListener - std::map> web_message_listeners_; - - // Initial user scripts from params - std::vector> initial_user_scripts_; - - // JavaScript bridge secret for security - std::string js_bridge_secret_; - - // Window ID for multi-window support - std::optional window_id_; - - // Flag to track if javaScriptBridgeEnabled - bool java_script_bridge_enabled_ = true; - - // Pending policy decisions - std::map pending_policy_decisions_; - int64_t next_decision_id_ = 0; - - // Pending script dialogs - std::map pending_script_dialogs_; - int64_t next_dialog_id_ = 0; - - // Pending permission requests - std::map pending_permission_requests_; - int64_t next_permission_id_ = 0; - - // Pending authentication requests - std::map pending_auth_requests_; - int64_t next_auth_id_ = 0; - - // Pending custom scheme requests (for async handling) - std::map pending_custom_scheme_requests_; - - // Frame available callback - std::function on_frame_available_; - - // Cursor change callback - std::function on_cursor_changed_; - std::string last_cursor_name_ = "default"; - - // Progress change callback (for InAppBrowser) - std::function on_progress_changed_; - - // Navigation state change callback (for InAppBrowser back/forward buttons) - std::function on_navigation_state_changed_; - - // InAppBrowser delegate (when embedded in an InAppBrowser) - // This allows WebViewChannelDelegate to forward browser-specific method calls - InAppBrowser* inAppBrowserDelegate_ = nullptr; - - // Last hit test result from mouse-target-changed signal - // Used by getHitTestResult() to return the current element under the cursor - WebKitHitTestResult* last_hit_test_result_ = nullptr; - - // Disposing flag to prevent callbacks during destruction - std::atomic is_disposing_{false}; - - // Mouse state - double cursor_x_ = 0; - double cursor_y_ = 0; - uint32_t button_state_ = 0; - uint32_t current_modifiers_ = 0; // Current keyboard modifiers (shift, ctrl, alt, meta) - - // Scroll multiplier - double scroll_multiplier_ = 1.0; - - // Progress tracking - double last_progress_ = 0.0; - - // Media capture state tracking (for onCameraCaptureStateChanged/onMicrophoneCaptureStateChanged) - int last_camera_capture_state_ = 0; // WebKitMediaCaptureState: NONE=0, ACTIVE=1, MUTED=2 - int last_microphone_capture_state_ = 0; // WebKitMediaCaptureState: NONE=0, ACTIVE=1, MUTED=2 - - // Fullscreen state (for DOM fullscreen requests) - bool is_fullscreen_ = false; - bool waiting_fullscreen_notify_ = false; - - // Activity/focus state - bool is_focused_ = true; - bool is_visible_ = true; - - // Target refresh rate (0 = default) - uint32_t target_refresh_rate_ = 0; - - // Monitor change tracking for refresh rate updates - gulong monitors_changed_handler_id_ = 0; - gulong configure_event_handler_id_ = 0; - - // Download signal handler ID - gulong download_started_handler_id_ = 0; - - // Context menu state - std::unique_ptr context_menu_popup_; - WebKitContextMenu* pending_context_menu_ = nullptr; - WebKitHitTestResult* pending_hit_test_result_ = nullptr; - double context_menu_x_ = 0; // Mouse position when context menu was requested - double context_menu_y_ = 0; - double texture_offset_x_ = 0; // Texture offset within the Flutter window - double texture_offset_y_ = 0; - - // Option menu state (for HTML support in WPE) - // Public because accessed from C-style GTK callback - std::string pending_color_input_value_; // Current color from the input - GtkWidget* active_color_dialog_ = nullptr; // Active color picker dialog (non-blocking) - bool active_color_alpha_enabled_ = false; // Alpha enabled for active dialog - int64_t color_dialog_show_time_ = 0; // Time when dialog was shown (to prevent immediate close) - WebKitScriptMessageReply* pending_color_reply_ = nullptr; // WebKit reply for Promise resolution - - // Date picker state (for support) - // Public because accessed from C-style GTK callback - GtkWidget* active_file_dialog_ = nullptr; // Active file chooser dialog (non-blocking) - int64_t file_dialog_show_time_ = 0; // Time when dialog was shown (to prevent immediate close) - void* file_chooser_context_ = nullptr; // Opaque pointer to FileChooserContext (for cleanup) - - // Option menu state (for HTML elements and handle them - * natively via the JavaScript bridge. - * - * This implementation uses Firefox/Chrome-style behavior: - * - No DOM modifications (no wrapper elements or icon overlays) - * - The entire color input is clickable (like native browsers) - * - Uses document-level event delegation for efficient handling - * - Supports keyboard navigation (Enter/Space) - * - Works with dynamically added inputs automatically - */ -class ColorInputJS { - public: - inline static const std::string COLOR_INPUT_JS_PLUGIN_SCRIPT_GROUP_NAME = - "IN_APP_WEBVIEW_COLOR_INPUT_JS_PLUGIN_SCRIPT"; - - /** - * JavaScript source code for color input interception. - * This code intercepts clicks on color inputs and calls the native handler. - * Supports the 'list' attribute for predefined color swatches. - * - * This script uses Firefox/Chrome-style behavior: - * 1. Injects minimal CSS (cursor:pointer, disabled styling only) - * 2. Uses document-level event delegation to intercept all color input clicks - * 3. Intercepts the ENTIRE color input element (not just an icon area) - * 4. Prevents default browser behavior and opens native GTK color picker - * 5. Supports keyboard accessibility (Enter/Space keys) - * 6. No DOM modifications - keeps the native color swatch appearance - */ - static std::string COLOR_INPUT_JS_SOURCE() { - return R"JS( -(function() { - // Avoid re-registering - if (window._flutterInAppWebViewColorInputInit) return; - window._flutterInAppWebViewColorInputInit = true; - - // CSS to style color inputs like Firefox/Chrome (colored box, not text input) - // WPE WebKit renders color inputs as text fields, so we need to style them properly - var style = document.createElement('style'); - style.textContent = [ - 'input[type="color"] {', - ' -webkit-appearance: none;', - ' appearance: none;', - ' width: 44px;', - ' height: 28px;', - ' padding: 2px;', - ' border: 1px solid #767676;', - ' border-radius: 4px;', - ' cursor: pointer;', - ' background-color: transparent;', - '}', - 'input[type="color"]::-webkit-color-swatch-wrapper {', - ' padding: 0;', - '}', - 'input[type="color"]::-webkit-color-swatch {', - ' border: none;', - ' border-radius: 2px;', - '}', - 'input[type="color"]:disabled {', - ' cursor: not-allowed;', - ' opacity: 0.5;', - '}', - 'input[type="color"]:focus {', - ' outline: 2px solid #4A90D9;', - ' outline-offset: 1px;', - '}' - ].join('\n'); - (document.head || document.documentElement).appendChild(style); - - // Calculate relative luminance of a color (0-1, where 0 is darkest, 1 is lightest) - function getLuminance(hexColor) { - var hex = hexColor.replace('#', ''); - if (hex.length === 3) { - hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; - } - var r = parseInt(hex.substr(0, 2), 16) / 255; - var g = parseInt(hex.substr(2, 2), 16) / 255; - var b = parseInt(hex.substr(4, 2), 16) / 255; - // sRGB luminance formula - r = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4); - g = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4); - b = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4); - return 0.2126 * r + 0.7152 * g + 0.0722 * b; - } - - // Function to apply color as background with contrasting text color - function applyColorBackground(input) { - if (input.attributes.type && input.attributes.type.value === 'color') { - var color = input.value || '#000000'; - input.style.backgroundColor = color; - // Set text color based on luminance for maximum contrast - var luminance = getLuminance(color); - input.style.color = luminance > 0.5 ? '#000000' : '#FFFFFF'; - } - } - - // Update color background when value changes - document.addEventListener('input', function(event) { - if (event.target.tagName === 'INPUT' && event.target.attributes.type && event.target.attributes.type.value === 'color') { - applyColorBackground(event.target); - } - }, true); - - // Apply to existing color inputs - document.querySelectorAll('input[type="color"]').forEach(applyColorBackground); - - // Also apply when new color inputs are added - var colorObserver = new MutationObserver(function(mutations) { - mutations.forEach(function(mutation) { - mutation.addedNodes.forEach(function(node) { - if (node.nodeType === Node.ELEMENT_NODE) { - if (node.tagName === 'INPUT' && node.attributes.type && node.attributes.type.value === 'color') { - applyColorBackground(node); - } else if (node.querySelectorAll) { - node.querySelectorAll('input[type="color"]').forEach(applyColorBackground); - } - } - }); - }); - }); - if (document.body) { - colorObserver.observe(document.body, { childList: true, subtree: true }); - } else { - document.addEventListener('DOMContentLoaded', function() { - document.querySelectorAll('input[type="color"]').forEach(applyColorBackground); - colorObserver.observe(document.body, { childList: true, subtree: true }); - }); - } - - // Function to get element's absolute position - function getElementRect(element) { - var rect = element.getBoundingClientRect(); - return { - x: Math.round(rect.left + window.scrollX), - y: Math.round(rect.top + window.scrollY), - width: Math.round(rect.width), - height: Math.round(rect.height) - }; - } - - // Function to get predefined colors from datalist (list attribute) - function getPredefinedColors(input) { - var colors = []; - var listId = input.getAttribute('list'); - if (listId) { - var datalist = document.getElementById(listId); - if (datalist) { - var options = datalist.querySelectorAll('option'); - for (var i = 0; i < options.length; i++) { - var color = options[i].value || options[i].textContent; - if (color && /^#[0-9A-Fa-f]{6}$/.test(color)) { - colors.push(color.toUpperCase()); - } - } - } - } - return colors; - } - - // Open color picker for an input - function openColorPicker(input) { - // Get element rect for positioning - var elemRect = getElementRect(input); - - // Get current color value (default is #000000) - var currentColor = input.value || '#000000'; - - // Get predefined colors from list attribute - var predefinedColors = getPredefinedColors(input); - - // Detect alpha attribute (HTML boolean attribute) - var alphaEnabled = input.hasAttribute('alpha'); - - // Detect colorspace attribute (limited-srgb or display-p3) - var colorSpace = input.getAttribute('colorspace') || 'limited-srgb'; - - // Use the unified callHandler API through the JavaScript bridge - try { - window.)JS" + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + R"JS(.callHandler('_onColorInputClicked', { - currentColor: currentColor, - elemRect: elemRect, - predefinedColors: predefinedColors, - alphaEnabled: alphaEnabled, - colorSpace: colorSpace - }).then(function(result) { - // Check if the result is a valid color (non-null, non-undefined) - if (result != null && result !== undefined) { - input.value = result; - // Update the background color and text color for contrast - input.style.backgroundColor = result; - var luminance = getLuminance(result); - input.style.color = luminance > 0.5 ? '#000000' : '#FFFFFF'; - // Dispatch input and change events to notify the page - input.dispatchEvent(new Event('input', { bubbles: true })); - input.dispatchEvent(new Event('change', { bubbles: true })); - } - // If result is null/undefined, user cancelled - do nothing - }).catch(function(e) { - console.error('Color picker error:', e); - }); - } catch(e) { - console.error('Failed to open color picker:', e); - } - } - - // Intercept ALL clicks on color inputs using event delegation - // Use capture phase to intercept before the browser's default handler - document.addEventListener('click', function(event) { - var target = event.target; - - // Check if this is a color input - if (target.tagName === 'INPUT' && target.attributes.type && target.attributes.type.value === 'color') { - // Skip if disabled - if (target.disabled) return; - - // Prevent default browser behavior (WPE's basic color UI) - event.preventDefault(); - event.stopPropagation(); - event.stopImmediatePropagation(); - - // Open our native color picker - openColorPicker(target); - } - }, true); // true = capture phase - - // Also intercept mousedown to prevent any focus/selection issues - document.addEventListener('mousedown', function(event) { - var target = event.target; - if (target.tagName === 'INPUT' && target.attributes.type && target.attributes.type.value === 'color' && !target.disabled) { - event.preventDefault(); - } - }, true); - - // Intercept Enter/Space key on focused color inputs for keyboard accessibility - document.addEventListener('keydown', function(event) { - var target = event.target; - if (target.tagName === 'INPUT' && target.attributes.type && target.attributes.type.value === 'color' && !target.disabled) { - if (event.key === 'Enter' || event.key === ' ') { - event.preventDefault(); - event.stopPropagation(); - openColorPicker(target); - } - } - }, true); -})(); -)JS"; - } - - /** - * Creates a PluginScript for color input interception. - */ - static std::unique_ptr COLOR_INPUT_JS_PLUGIN_SCRIPT( - const std::optional>& allowedOriginRules, - bool forMainFrameOnly) { - return std::make_unique( - COLOR_INPUT_JS_PLUGIN_SCRIPT_GROUP_NAME, COLOR_INPUT_JS_SOURCE(), - UserScriptInjectionTime::atDocumentEnd, // Inject after DOM is ready - forMainFrameOnly, - allowedOriginRules, - nullptr, // contentWorld - false, // requiredInAllContentWorlds - std::vector{} // messageHandlerNames - uses existing bridge - ); - } -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_COLOR_INPUT_JS_H_ diff --git a/flutter_inappwebview_linux/linux/plugin_scripts_js/console_log_js.h b/flutter_inappwebview_linux/linux/plugin_scripts_js/console_log_js.h deleted file mode 100644 index f1167e990f..0000000000 --- a/flutter_inappwebview_linux/linux/plugin_scripts_js/console_log_js.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CONSOLE_LOG_JS_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_CONSOLE_LOG_JS_H_ - -#include -#include -#include -#include - -#include "../types/plugin_script.h" -#include "javascript_bridge_js.h" - -namespace flutter_inappwebview_plugin { - -/** - * JavaScript for capturing console.log, console.error, etc. - * - * This script intercepts console methods and forwards them to the native - * side via the JavaScript bridge. This approach is used because WebKit - * (both GTK and WPE) doesn't have a direct "console-message" signal. - */ -class ConsoleLogJS { - public: - inline static const std::string CONSOLE_LOG_JS_PLUGIN_SCRIPT_GROUP_NAME = - "IN_APP_WEBVIEW_CONSOLE_LOG_JS_PLUGIN_SCRIPT"; - - /** - * JavaScript source code for console message interception. - * This code wraps console.log, console.error, console.warn, console.info, - * and console.debug to send messages to native code. - * - * Must match iOS/macOS implementation - uses JavaScript bridge callHandler. - */ - static std::string CONSOLE_LOG_JS_SOURCE() { - // Match iOS ConsoleLogJS.swift implementation exactly - return R"JS( -(function(console) { - - function _callHandler(logLevel, args) { - var message = ''; - for (var i in args) { - try { - message += message === '' ? args[i] : ' ' + args[i]; - } catch(_) {} - } - try { - window.)JS" + - JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + - R"JS(.callHandler('onConsoleMessage', {'level': logLevel, 'message': message}); - } catch(_) {} - } - - var oldLogs = { - 'consoleLog': console.log, - 'consoleDebug': console.debug, - 'consoleError': console.error, - 'consoleInfo': console.info, - 'consoleWarn': console.warn - }; - - for (var k in oldLogs) { - (function(oldLog) { - var logLevel = oldLog.replace('console', '').toLowerCase(); - console[logLevel] = function() { - oldLogs[oldLog].apply(null, arguments); - _callHandler(logLevel, arguments); - } - })(k); - } -})(window.console); -)JS"; - } - - /** - * Creates a PluginScript for console log interception. - * - * Note: This plugin is only for main frame. Using it on non-main frames - * could cause issues such as https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738 - */ - static std::unique_ptr CONSOLE_LOG_JS_PLUGIN_SCRIPT( - const std::optional>& allowedOriginRules) { - return std::make_unique( - CONSOLE_LOG_JS_PLUGIN_SCRIPT_GROUP_NAME, CONSOLE_LOG_JS_SOURCE(), - UserScriptInjectionTime::atDocumentStart, - true, // forMainFrameOnly - allowedOriginRules, - nullptr, // contentWorld - true, // requiredInAllContentWorlds - std::vector{} // no additional message handlers needed - ); - } -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_CONSOLE_LOG_JS_H_ diff --git a/flutter_inappwebview_linux/linux/plugin_scripts_js/cursor_detection_js.h b/flutter_inappwebview_linux/linux/plugin_scripts_js/cursor_detection_js.h deleted file mode 100644 index de5ca65597..0000000000 --- a/flutter_inappwebview_linux/linux/plugin_scripts_js/cursor_detection_js.h +++ /dev/null @@ -1,269 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CURSOR_DETECTION_JS_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_CURSOR_DETECTION_JS_H_ - -#include -#include -#include -#include - -#include "../types/plugin_script.h" -#include "javascript_bridge_js.h" - -namespace flutter_inappwebview_plugin { - -/** - * JavaScript for detecting cursor style changes in the WebView. - * - * This script monitors cursor style changes as the user moves the mouse, - * and reports them to native code. WPE WebKit doesn't expose cursor information - * directly like GTK does, so we use JavaScript to detect CSS cursor properties. - */ -class CursorDetectionJS { - public: - inline static const std::string CURSOR_DETECTION_JS_PLUGIN_SCRIPT_GROUP_NAME = - "IN_APP_WEBVIEW_CURSOR_DETECTION_JS_PLUGIN_SCRIPT"; - - /** - * JavaScript source code for cursor detection. - * - * The script detects the effective cursor style by: - * 1. First checking the computed CSS cursor value - * 2. If "auto", analyzing the element to determine appropriate cursor: - * - Links ( with href) -> pointer - * - Editable elements (input, textarea, contenteditable) -> text - * - Buttons and controls -> pointer - * - Images with onclick/links -> pointer - * 3. Check if the mouse is over a text node's bounding boxes to show text cursor only when - * actually over text characters. - */ - static std::string CURSOR_DETECTION_JS_SOURCE() { - return R"JS( -(function() { - if (window._flutterCursorDetectorInstalled) return; - window._flutterCursorDetectorInstalled = true; - - var lastCursor = ''; - - // Helper to check if element is editable - function isEditable(el) { - if (!el) return false; - var tagName = el.tagName ? el.tagName.toLowerCase() : ''; - - // Input fields (except hidden, button types, etc.) - if (tagName === 'input') { - var type = (el.type || 'text').toLowerCase(); - // These input types should show text cursor - var textTypes = ['text', 'password', 'email', 'number', 'search', - 'tel', 'url', 'date', 'datetime-local', 'month', - 'week', 'time']; - return textTypes.indexOf(type) !== -1; - } - - // Textarea - if (tagName === 'textarea') return true; - - // Contenteditable - if (el.isContentEditable) return true; - - return false; - } - - // Helper to check if element is a clickable control - function isClickable(el) { - if (!el) return false; - var tagName = el.tagName ? el.tagName.toLowerCase() : ''; - - // Links with href - if (tagName === 'a' && el.hasAttribute('href')) return true; - - // Buttons - if (tagName === 'button') return true; - - // Input buttons/submits - if (tagName === 'input') { - var type = (el.type || 'text').toLowerCase(); - if (['button', 'submit', 'reset', 'image', 'file', 'checkbox', 'radio'].indexOf(type) !== -1) { - return true; - } - } - - // Select dropdowns - if (tagName === 'select') return true; - - // Labels (clickable for form controls) - if (tagName === 'label') return true; - - // Summary in details element - if (tagName === 'summary') return true; - - // Elements with onclick handler or role="button" - if (el.onclick || el.getAttribute('role') === 'button' || - el.getAttribute('role') === 'link' || - el.getAttribute('role') === 'menuitem' || - el.getAttribute('role') === 'tab') { - return true; - } - - // Check for click event listeners via data attribute (common pattern) - if (el.dataset && (el.dataset.click || el.dataset.action)) return true; - - return false; - } - - // Determine effective cursor for "auto" mode - function getEffectiveCursor(el, computedCursor, mouseX, mouseY) { - // If cursor is explicitly set (not auto/default), use it - if (computedCursor && computedCursor !== 'auto' && computedCursor !== 'default') { - return computedCursor; - } - - if (!el) return 'default'; - - // Check element and ancestors for context - var current = el; - var maxDepth = 10; // Prevent infinite loops - var depth = 0; - - while (current && current !== document.body && depth < maxDepth) { - // Check if this element provides cursor context - if (isEditable(current)) { - return 'text'; - } - - if (isClickable(current)) { - return 'pointer'; - } - - current = current.parentElement; - depth++; - } - - // Use precise hit-testing to check if mouse is actually over text characters - // This avoids showing text cursor in padding/margin areas - if (isOverActualText(mouseX, mouseY)) { - // Double-check we're not in a clickable context - if (!isClickable(el) && !isClickableAncestor(el)) { - return 'text'; - } - } - - return 'default'; - } - - // Check if any ancestor is clickable (to avoid text cursor on buttons with text) - function isClickableAncestor(el) { - var current = el.parentElement; - var maxDepth = 5; - var depth = 0; - - while (current && current !== document.body && depth < maxDepth) { - if (isClickable(current)) return true; - current = current.parentElement; - depth++; - } - return false; - } - - // Check if mouse coordinates are actually over text characters - // https://stackoverflow.com/questions/10389459/is-there-a-way-to-detect-if-im-hovering-over-text - function isOverActualText(x, y) { - const element = document.elementFromPoint(x, y); - if (element == null) return false; - const nodes = element.childNodes; - for (let i = 0, node; (node = nodes[i++]); ) { - if (node.nodeType === 3) { - const range = document.createRange(); - range.selectNode(node); - const rects = range.getClientRects(); - for (let j = 0, rect; (rect = rects[j++]); ) { - if ( - x > rect.left && - x < rect.right && - y > rect.top && - y < rect.bottom - ) { - if (node.nodeType === Node.TEXT_NODE) return true; - } - } - } - } - return false; - } - - // Report cursor change to native - function reportCursor(cursor) { - if (cursor !== lastCursor) { - lastCursor = cursor; - try { - if (window.)JS" + - JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + - R"JS( && window.)JS" + - JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + - R"JS(.callHandler) { - window.)JS" + - JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + - R"JS(.callHandler('_cursorChanged', cursor); - } - } catch(_) {} - } - } - - // Handle mouse movement - function handleMouseMove(e) { - var el = document.elementFromPoint(e.clientX, e.clientY); - if (!el) { - reportCursor('default'); - return; - } - - // Get computed cursor style - var computedCursor = ''; - try { - computedCursor = window.getComputedStyle(el).cursor; - } catch(_) {} - - // Determine effective cursor (pass mouse coordinates for precise text detection) - var effectiveCursor = getEffectiveCursor(el, computedCursor, e.clientX, e.clientY); - reportCursor(effectiveCursor); - } - - // Use both mousemove and mouseover for comprehensive coverage - document.addEventListener('mousemove', handleMouseMove, { passive: true }); - - // Also handle mouseout to reset cursor when leaving elements - document.addEventListener('mouseout', function(e) { - if (e.relatedTarget === null) { - // Mouse left the document - reportCursor('default'); - } - }, { passive: true }); - -})(); -)JS"; - } - - /** - * Creates a PluginScript for cursor detection. - * - * This plugin runs in the main frame only to avoid performance overhead - * from multiple iframe instances. - */ - static std::unique_ptr CURSOR_DETECTION_JS_PLUGIN_SCRIPT( - const std::optional>& allowedOriginRules, - bool forMainFrameOnly = true) { - return std::make_unique( - CURSOR_DETECTION_JS_PLUGIN_SCRIPT_GROUP_NAME, - CURSOR_DETECTION_JS_SOURCE(), - UserScriptInjectionTime::atDocumentEnd, // Inject after DOM is ready - forMainFrameOnly, - allowedOriginRules, - nullptr, // contentWorld - true, // requiredInAllContentWorlds - std::vector{} // no additional message handlers needed - ); - } -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_CURSOR_DETECTION_JS_H_ diff --git a/flutter_inappwebview_linux/linux/plugin_scripts_js/date_input_js.h b/flutter_inappwebview_linux/linux/plugin_scripts_js/date_input_js.h deleted file mode 100644 index b0bbb1c4a9..0000000000 --- a/flutter_inappwebview_linux/linux/plugin_scripts_js/date_input_js.h +++ /dev/null @@ -1,286 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_DATE_INPUT_JS_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_DATE_INPUT_JS_H_ - -#include -#include -#include -#include - -#include "../types/plugin_script.h" -#include "javascript_bridge_js.h" - -namespace flutter_inappwebview_plugin { - -/** - * JavaScript for intercepting date/time input elements. - * - * WPE WebKit doesn't have built-in date picker support, - * so we intercept clicks on date-related input elements and handle them - * natively via the JavaScript bridge. - * - * Supported input types: - * - date: Full date (YYYY-MM-DD) - * - datetime-local: Date and time (YYYY-MM-DDTHH:MM) - * - time: Time only (HH:MM) - * - month: Year and month (YYYY-MM) - * - week: Year and week (YYYY-Www) - */ -class DateInputJS { - public: - inline static const std::string DATE_INPUT_JS_PLUGIN_SCRIPT_GROUP_NAME = - "IN_APP_WEBVIEW_DATE_INPUT_JS_PLUGIN_SCRIPT"; - - /** - * JavaScript source code for date input interception. - * - * This script: - * 1. Injects CSS to ensure the calendar picker icon is visible and styled - * 2. Only intercepts clicks on the calendar icon (not the text field) - * 3. Allows users to type directly in the input field - * 4. Passes screen coordinates for proper popup positioning - */ - static std::string DATE_INPUT_JS_SOURCE() { - return R"JS( -(function() { - // Avoid re-registering - if (window._flutterInAppWebViewDateInputInit) return; - window._flutterInAppWebViewDateInputInit = true; - - // Supported date input types - var DATE_INPUT_TYPES = ['date', 'datetime-local', 'time', 'month', 'week']; - - // Icon mapping for different input types - var ICON_MAP = { - 'date': '📅', - 'datetime-local': '📅', - 'month': '📅', - 'week': '📅', - 'time': '🕐' - }; - - // Inject CSS to style the date/time inputs with a visible picker icon - // WebKit uses ::-webkit-calendar-picker-indicator for the icon - var style = document.createElement('style'); - style.textContent = [ - // Ensure the picker indicator is visible and clickable - 'input[type="date"]::-webkit-calendar-picker-indicator,', - 'input[type="datetime-local"]::-webkit-calendar-picker-indicator,', - 'input[type="time"]::-webkit-calendar-picker-indicator,', - 'input[type="month"]::-webkit-calendar-picker-indicator,', - 'input[type="week"]::-webkit-calendar-picker-indicator {', - ' cursor: pointer;', - ' opacity: 1;', - ' display: block;', - ' width: 20px;', - ' height: 20px;', - ' background: transparent;', - ' position: relative;', - '}', - // Style for our custom icon overlay - '._flutter_date_picker_icon {', - ' position: absolute;', - ' right: 4px;', - ' top: 50%;', - ' transform: translateY(-50%);', - ' cursor: pointer;', - ' font-size: 16px;', - ' user-select: none;', - ' pointer-events: auto;', - ' z-index: 1;', - ' padding: 2px 4px;', - ' opacity: 0.7;', - ' transition: opacity 0.15s;', - '}', - '._flutter_date_picker_icon:hover {', - ' opacity: 1;', - '}', - '._flutter_date_input_wrapper {', - ' position: relative;', - ' display: inline-block;', - '}', - '._flutter_date_input_wrapped {', - ' padding-right: 28px !important;', - '}' - ].join('\n'); - (document.head || document.documentElement).appendChild(style); - - // Track wrapped inputs to avoid double-wrapping - var wrappedInputs = new WeakSet(); - - // Wrap a date input with our custom icon - function wrapDateInput(input) { - if (wrappedInputs.has(input)) return; - if (input.disabled || input.readOnly) return; - - var inputType = input.attributes.type ? input.attributes.type.value : input.type; - if (DATE_INPUT_TYPES.indexOf(inputType) === -1) return; - - wrappedInputs.add(input); - - // Create wrapper if input is not already wrapped - var parent = input.parentNode; - if (!parent || parent.classList.contains('_flutter_date_input_wrapper')) return; - - // Create wrapper - var wrapper = document.createElement('span'); - wrapper.className = '_flutter_date_input_wrapper'; - wrapper.style.display = getComputedStyle(input).display === 'block' ? 'block' : 'inline-block'; - - // Insert wrapper and move input inside - parent.insertBefore(wrapper, input); - wrapper.appendChild(input); - - // Add padding to input for icon space - input.classList.add('_flutter_date_input_wrapped'); - - // Create icon - var icon = document.createElement('span'); - icon.className = '_flutter_date_picker_icon'; - icon.textContent = ICON_MAP[inputType] || '📅'; - icon.setAttribute('role', 'button'); - icon.setAttribute('aria-label', 'Open ' + inputType + ' picker'); - wrapper.appendChild(icon); - - // Handle icon click - icon.addEventListener('click', function(event) { - event.preventDefault(); - event.stopPropagation(); - openDatePicker(input, event); - }, true); - - // Prevent default on the webkit picker indicator clicks - input.addEventListener('click', function(event) { - var rect = input.getBoundingClientRect(); - var clickX = event.clientX; - // If clicking in the rightmost 30px (icon area), open our picker - if (clickX > rect.right - 30) { - event.preventDefault(); - event.stopPropagation(); - openDatePicker(input, event); - } - // Otherwise let the user type in the field - }, true); - } - - // Function to get element's absolute position (relative to viewport and page) - function getElementRect(element) { - var rect = element.getBoundingClientRect(); - return { - // Position relative to page (with scroll) - x: Math.round(rect.left + window.scrollX), - y: Math.round(rect.top + window.scrollY), - width: Math.round(rect.width), - height: Math.round(rect.height), - // Position relative to viewport (without scroll) - for dialog positioning - viewportX: Math.round(rect.left), - viewportY: Math.round(rect.bottom + 2), // Position just below the input - viewportBottom: Math.round(rect.bottom) - }; - } - - // Open date picker for an input - function openDatePicker(input, event) { - if (input.disabled || input.readOnly) return; - - var inputType = input.attributes.type ? input.attributes.type.value : input.type; - if (DATE_INPUT_TYPES.indexOf(inputType) === -1) return; - - // Get current value - var currentValue = input.value || ''; - - // Get min/max constraints - var minValue = input.min || ''; - var maxValue = input.max || ''; - - // Get step attribute (for time inputs) - var step = input.step || ''; - - // Get element rect with screen coordinates - var elemRect = getElementRect(input); - - // Use the unified callHandler API through the JavaScript bridge - // This uses the with_reply API which works correctly for iframes - try { - window.)JS" + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + R"JS(.callHandler('_onDateInputClicked', { - inputType: inputType, - currentValue: currentValue, - minValue: minValue, - maxValue: maxValue, - step: step, - elemRect: elemRect - }).then(function(result) { - // Check if the result is a valid value (non-null, non-undefined) - if (result != null && result !== undefined) { - input.value = result; - // Dispatch input and change events to notify the page - input.dispatchEvent(new Event('input', { bubbles: true })); - input.dispatchEvent(new Event('change', { bubbles: true })); - } - // If result is null/undefined, user cancelled - do nothing - }).catch(function(e) { - console.error('Date picker error:', e); - }); - } catch(e) { - console.error('Failed to open date picker:', e); - } - } - - // Process existing date inputs on page load - function processExistingInputs() { - DATE_INPUT_TYPES.forEach(function(type) { - document.querySelectorAll('input[type="' + type + '"]').forEach(wrapDateInput); - }); - } - - // Observe for new date inputs added dynamically - var observer = new MutationObserver(function(mutations) { - mutations.forEach(function(mutation) { - mutation.addedNodes.forEach(function(node) { - if (node.nodeType === Node.ELEMENT_NODE) { - if (node.tagName === 'INPUT') { - wrapDateInput(node); - } else if (node.querySelectorAll) { - DATE_INPUT_TYPES.forEach(function(type) { - node.querySelectorAll('input[type="' + type + '"]').forEach(wrapDateInput); - }); - } - } - }); - }); - }); - - // Start observing when DOM is ready - if (document.body) { - processExistingInputs(); - observer.observe(document.body, { childList: true, subtree: true }); - } else { - document.addEventListener('DOMContentLoaded', function() { - processExistingInputs(); - observer.observe(document.body, { childList: true, subtree: true }); - }); - } -})(); -)JS"; - } - - /** - * Creates a PluginScript for date input interception. - */ - static std::unique_ptr DATE_INPUT_JS_PLUGIN_SCRIPT( - const std::optional>& allowedOriginRules, - bool forMainFrameOnly) { - return std::make_unique( - DATE_INPUT_JS_PLUGIN_SCRIPT_GROUP_NAME, DATE_INPUT_JS_SOURCE(), - UserScriptInjectionTime::atDocumentEnd, // Inject after DOM is ready - forMainFrameOnly, - allowedOriginRules, - nullptr, // contentWorld - false, // requiredInAllContentWorlds - std::vector{} // messageHandlerNames - uses existing bridge - ); - } -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_DATE_INPUT_JS_H_ diff --git a/flutter_inappwebview_linux/linux/plugin_scripts_js/intercept_ajax_request_js.h b/flutter_inappwebview_linux/linux/plugin_scripts_js/intercept_ajax_request_js.h deleted file mode 100644 index 4a917e9de6..0000000000 --- a/flutter_inappwebview_linux/linux/plugin_scripts_js/intercept_ajax_request_js.h +++ /dev/null @@ -1,503 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_INTERCEPT_AJAX_REQUEST_JS_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_INTERCEPT_AJAX_REQUEST_JS_H_ - -#include -#include -#include -#include - -#include "../types/plugin_script.h" -#include "javascript_bridge_js.h" - -namespace flutter_inappwebview_plugin { - -/** - * JavaScript for intercepting XMLHttpRequest (AJAX) requests. - * - * This script wraps XMLHttpRequest prototype methods (open, send, setRequestHeader) - * to intercept requests before they're sent and handle response callbacks. - * - * Matches iOS implementation: InterceptAjaxRequestJS.swift - */ -class InterceptAjaxRequestJS { - public: - inline static const std::string INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = - "IN_APP_WEBVIEW_INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT"; - - /** - * Flag variable name used to enable/disable AJAX request interception at runtime. - */ - static std::string FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() { - return "window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + - "._useShouldInterceptAjaxRequest"; - } - - /** - * Flag variable for onAjaxReadyStateChange callback. - */ - static std::string FLAG_VARIABLE_FOR_ON_AJAX_READY_STATE_CHANGE() { - return "window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + - "._useOnAjaxReadyStateChange"; - } - - /** - * Flag variable for onAjaxProgress callback. - */ - static std::string FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS() { - return "window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + - "._useOnAjaxProgress"; - } - - /** - * Flag variable for intercepting only async AJAX requests. - */ - static std::string FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE() { - return "window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + - "._interceptOnlyAsyncAjaxRequests"; - } - - /** - * JavaScript utility variable name reference. - */ - static std::string JAVASCRIPT_UTIL_VAR_NAME() { - return "window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + "._util"; - } - - /** - * JavaScript source code for utility functions needed by AJAX interception. - * This must be injected before the AJAX interception script. - */ - static std::string JAVASCRIPT_UTIL_JS_SOURCE() { - const std::string utilVarName = JAVASCRIPT_UTIL_VAR_NAME(); - - return utilVarName + R"JS( = { - isString: function(variable) { - return typeof variable === 'string' || variable instanceof String; - }, - isBodyFormData: function(bodyString) { - return bodyString.indexOf('------WebKitFormBoundary') === 0; - }, - getFormDataContentType: function(bodyString) { - var boundary = bodyString.split('\r\n')[0].trim(); - var contentType = 'multipart/form-data; boundary=' + boundary.substring(2); - return contentType; - }, - convertBodyRequest: function(body) { - return new Promise(function(resolve, reject) { - if (body == null) { - resolve(null); - return; - } - if (body instanceof ArrayBuffer) { - resolve(Array.from(new Uint8Array(body))); - return; - } - if (ArrayBuffer.isView(body)) { - resolve(Array.from(new Uint8Array(body.buffer))); - return; - } - if (body instanceof Blob) { - var reader = new FileReader(); - reader.addEventListener('loadend', function() { - resolve(Array.from(new Uint8Array(reader.result))); - }); - reader.readAsArrayBuffer(body); - return; - } - if (body instanceof FormData) { - var entries = body.entries(); - var dataString = ''; - var boundary = '------WebKitFormBoundary' + Math.random().toString(36).substring(7); - var entry = entries.next(); - while (!entry.done) { - var name = entry.value[0]; - var value = entry.value[1]; - dataString += boundary + '\r\n'; - if (value instanceof File) { - dataString += 'Content-Disposition: form-data; name="' + name + '"; filename="' + value.name + '"\r\n'; - dataString += 'Content-Type: ' + value.type + '\r\n\r\n'; - dataString += value.data + '\r\n'; - } else { - dataString += 'Content-Disposition: form-data; name="' + name + '"\r\n\r\n'; - dataString += value + '\r\n'; - } - entry = entries.next(); - } - if (dataString.length > 0) { - dataString += boundary + '--\r\n'; - } - resolve(dataString); - return; - } - resolve(body.toString()); - }); - }, - arrayBufferToString: function(arrayBuffer) { - var decoder = new TextDecoder('utf-8'); - return decoder.decode(new Uint8Array(arrayBuffer)); - }, - convertHeadersToJson: function(headers) { - var headersObj = {}; - if (headers instanceof Headers) { - headers.forEach(function(value, key) { - headersObj[key] = value; - }); - } - return headersObj; - }, - convertJsonToHeaders: function(headersObj) { - var headers = new Headers(); - for (var key in headersObj) { - headers.append(key, headersObj[key]); - } - return headers; - }, - convertCredentialsToJson: function(credentials) { - var credentialsObj = {}; - if (window.FederatedCredential != null && credentials instanceof FederatedCredential) { - credentialsObj.type = credentials.type; - credentialsObj.id = credentials.id; - credentialsObj.name = credentials.name; - credentialsObj.protocol = credentials.protocol; - credentialsObj.provider = credentials.provider; - credentialsObj.iconURL = credentials.iconURL; - } else if (window.PasswordCredential != null && credentials instanceof PasswordCredential) { - credentialsObj.type = credentials.type; - credentialsObj.id = credentials.id; - credentialsObj.name = credentials.name; - credentialsObj.password = credentials.password; - credentialsObj.iconURL = credentials.iconURL; - } else { - credentialsObj.type = 'default'; - credentialsObj.value = credentials; - } - return credentialsObj; - }, - convertJsonToCredential: function(credentialsJson) { - var credentials; - if (window.FederatedCredential != null && credentialsJson.type === 'federated') { - credentials = new FederatedCredential({ - id: credentialsJson.id, - name: credentialsJson.name, - protocol: credentialsJson.protocol, - provider: credentialsJson.provider, - iconURL: credentialsJson.iconURL - }); - } else if (window.PasswordCredential != null && credentialsJson.type === 'password') { - credentials = new PasswordCredential({ - id: credentialsJson.id, - name: credentialsJson.name, - password: credentialsJson.password, - iconURL: credentialsJson.iconURL - }); - } else { - credentials = credentialsJson.value == null ? undefined : credentialsJson.value; - } - return credentials; - } -}; -)JS"; - } - - /** - * JavaScript source code for AJAX request interception. - * Wraps XMLHttpRequest prototype methods to intercept requests. - * - * Matches iOS InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_SOURCE() - * - * @param initialUseOnAjaxReadyStateChange Initial value for onAjaxReadyStateChange flag. - * @param initialUseOnAjaxProgress Initial value for onAjaxProgress flag. - */ - static std::string INTERCEPT_AJAX_REQUEST_JS_SOURCE(bool initialUseOnAjaxReadyStateChange, - bool initialUseOnAjaxProgress) { - const std::string flagShouldIntercept = FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE(); - const std::string flagReadyStateChange = FLAG_VARIABLE_FOR_ON_AJAX_READY_STATE_CHANGE(); - const std::string flagProgress = FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS(); - const std::string flagOnlyAsync = FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE(); - const std::string utilVarName = JAVASCRIPT_UTIL_VAR_NAME(); - const std::string bridgeName = JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME(); - - return JAVASCRIPT_UTIL_JS_SOURCE() + - flagShouldIntercept + " = true;\n" + - flagReadyStateChange + " = " + (initialUseOnAjaxReadyStateChange ? "true" : "false") + ";\n" + - flagProgress + " = " + (initialUseOnAjaxProgress ? "true" : "false") + ";\n" + - flagOnlyAsync + " = true;\n" + - R"JS( -(function(ajax) { - var send = ajax.prototype.send; - var open = ajax.prototype.open; - var setRequestHeader = ajax.prototype.setRequestHeader; - ajax.prototype._flutter_inappwebview_url = null; - ajax.prototype._flutter_inappwebview_method = null; - ajax.prototype._flutter_inappwebview_isAsync = null; - ajax.prototype._flutter_inappwebview_user = null; - ajax.prototype._flutter_inappwebview_password = null; - ajax.prototype._flutter_inappwebview_already_onreadystatechange_wrapped = false; - ajax.prototype._flutter_inappwebview_request_headers = {}; - - function convertRequestResponse(request, callback) { - if (request.response != null && request.responseType != null) { - switch (request.responseType) { - case 'arraybuffer': - callback(Array.from(new Uint8Array(request.response))); - return; - case 'blob': - var reader = new FileReader(); - reader.addEventListener('loadend', function() { - callback(Array.from(new Uint8Array(reader.result))); - }); - reader.readAsArrayBuffer(request.response); - return; - case 'document': - callback(request.response.documentElement.outerHTML); - return; - case 'json': - callback(request.response); - return; - } - } - callback(null); - } - - ajax.prototype.open = function(method, url, isAsync, user, password) { - isAsync = (isAsync != null) ? isAsync : true; - this._flutter_inappwebview_url = url; - this._flutter_inappwebview_method = method; - this._flutter_inappwebview_isAsync = isAsync; - this._flutter_inappwebview_user = user; - this._flutter_inappwebview_password = password; - this._flutter_inappwebview_request_headers = {}; - open.call(this, method, url, isAsync, user, password); - }; - - ajax.prototype.setRequestHeader = function(header, value) { - this._flutter_inappwebview_request_headers[header] = value; - setRequestHeader.call(this, header, value); - }; - - function handleEvent(e) { - if ()JS" + flagShouldIntercept + R"JS( === false || )JS" + flagProgress + R"JS( == null || )JS" + flagProgress + R"JS( === false) { - return; - } - var self = this; - if ()JS" + flagShouldIntercept + R"JS( == null || )JS" + flagShouldIntercept + R"JS( == true) { - var headers = this.getAllResponseHeaders(); - var responseHeaders = {}; - if (headers != null) { - var arr = headers.trim().split(/[\r\n]+/); - arr.forEach(function (line) { - var parts = line.split(': '); - var header = parts.shift(); - var value = parts.join(': '); - responseHeaders[header] = value; - }); - } - convertRequestResponse(this, function(response) { - var ajaxRequest = { - method: self._flutter_inappwebview_method, - url: self._flutter_inappwebview_url, - isAsync: self._flutter_inappwebview_isAsync, - user: self._flutter_inappwebview_user, - password: self._flutter_inappwebview_password, - withCredentials: self.withCredentials, - headers: self._flutter_inappwebview_request_headers, - readyState: self.readyState, - status: self.status, - responseURL: self.responseURL, - responseType: self.responseType, - response: response, - responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null, - responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null, - statusText: self.statusText, - responseHeaders: responseHeaders, - event: { - type: e.type, - loaded: e.loaded, - lengthComputable: e.lengthComputable, - total: e.total - } - }; - window.)JS" + bridgeName + R"JS(.callHandler('onAjaxProgress', ajaxRequest).then(function(result) { - if (result != null) { - try { - result = JSON.parse(result); - } catch(e) {} - if (result === 0) { - self.abort(); - return; - } - } - }); - }); - } - } - - ajax.prototype.send = function(data) { - var self = this; - var canBeIntercepted = self._flutter_inappwebview_isAsync || )JS" + flagOnlyAsync + R"JS( === false; - if (canBeIntercepted && ()JS" + flagShouldIntercept + R"JS( == null || )JS" + flagShouldIntercept + R"JS( == true)) { - if ()JS" + flagReadyStateChange + R"JS( === true && !this._flutter_inappwebview_already_onreadystatechange_wrapped) { - this._flutter_inappwebview_already_onreadystatechange_wrapped = true; - var realOnreadystatechange = this.onreadystatechange; - this.onreadystatechange = function() { - if ()JS" + flagShouldIntercept + R"JS( == null || )JS" + flagShouldIntercept + R"JS( == true) { - var headers = this.getAllResponseHeaders(); - var responseHeaders = {}; - if (headers != null) { - var arr = headers.trim().split(/[\r\n]+/); - arr.forEach(function (line) { - var parts = line.split(': '); - var header = parts.shift(); - var value = parts.join(': '); - responseHeaders[header] = value; - }); - } - convertRequestResponse(this, function(response) { - var ajaxRequest = { - method: self._flutter_inappwebview_method, - url: self._flutter_inappwebview_url, - isAsync: self._flutter_inappwebview_isAsync, - user: self._flutter_inappwebview_user, - password: self._flutter_inappwebview_password, - withCredentials: self.withCredentials, - headers: self._flutter_inappwebview_request_headers, - readyState: self.readyState, - status: self.status, - responseURL: self.responseURL, - responseType: self.responseType, - response: response, - responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null, - responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null, - statusText: self.statusText, - responseHeaders: responseHeaders - }; - window.)JS" + bridgeName + R"JS(.callHandler('onAjaxReadyStateChange', ajaxRequest).then(function(result) { - if (result != null) { - try { - result = JSON.parse(result); - } catch(e) {} - if (result === 0) { - self.abort(); - return; - } - } - if (realOnreadystatechange != null) { - realOnreadystatechange(); - } - }); - }); - } else if (realOnreadystatechange != null) { - realOnreadystatechange(); - } - }; - } - this.addEventListener('loadstart', handleEvent); - this.addEventListener('load', handleEvent); - this.addEventListener('loadend', handleEvent); - this.addEventListener('progress', handleEvent); - this.addEventListener('error', handleEvent); - this.addEventListener('abort', handleEvent); - this.addEventListener('timeout', handleEvent); - - )JS" + utilVarName + R"JS(.convertBodyRequest(data).then(function(convertedData) { - var ajaxRequest = { - data: convertedData, - method: self._flutter_inappwebview_method, - url: self._flutter_inappwebview_url, - isAsync: self._flutter_inappwebview_isAsync, - user: self._flutter_inappwebview_user, - password: self._flutter_inappwebview_password, - withCredentials: self.withCredentials, - headers: self._flutter_inappwebview_request_headers, - responseType: self.responseType - }; - window.)JS" + bridgeName + R"JS(.callHandler('shouldInterceptAjaxRequest', ajaxRequest).then(function(result) { - if (result != null) { - try { - result = JSON.parse(result); - } catch(e) {} - if (result === 0) { - self.abort(); - return; - } - if (result.data != null && !)JS" + utilVarName + R"JS(.isString(result.data) && result.data.length > 0) { - var bodyString = )JS" + utilVarName + R"JS(.arrayBufferToString(result.data); - if ()JS" + utilVarName + R"JS(.isBodyFormData(bodyString)) { - var formDataContentType = )JS" + utilVarName + R"JS(.getFormDataContentType(bodyString); - if (result.headers != null) { - result.headers['Content-Type'] = result.headers['Content-Type'] == null ? formDataContentType : result.headers['Content-Type']; - } else { - result.headers = { 'Content-Type': formDataContentType }; - } - } - } - if ()JS" + utilVarName + R"JS(.isString(result.data) || result.data == null) { - convertedData = result.data; - } else if (result.data.length > 0) { - convertedData = new Uint8Array(result.data); - } - self.withCredentials = result.withCredentials; - if (result.responseType != null && self._flutter_inappwebview_isAsync) { - self.responseType = result.responseType; - } - if (result.headers != null) { - for (var header in result.headers) { - var value = result.headers[header]; - var flutter_inappwebview_value = self._flutter_inappwebview_request_headers[header]; - if (flutter_inappwebview_value == null) { - self._flutter_inappwebview_request_headers[header] = value; - } else { - self._flutter_inappwebview_request_headers[header] += ', ' + value; - } - setRequestHeader.call(self, header, value); - } - } - if ((self._flutter_inappwebview_method != result.method && result.method != null) || - (self._flutter_inappwebview_url != result.url && result.url != null) || - (self._flutter_inappwebview_isAsync != result.isAsync && result.isAsync != null) || - (self._flutter_inappwebview_user != result.user && result.user != null) || - (self._flutter_inappwebview_password != result.password && result.password != null)) { - self.abort(); - self.open(result.method, result.url, result.isAsync, result.user, result.password); - } - } - send.call(self, convertedData); - }); - }); - } else { - send.call(this, data); - } - }; -})(window.XMLHttpRequest); -)JS"; - } - - /** - * Creates a PluginScript for AJAX request interception. - * - * @param allowedOriginRules Optional list of origin rules to restrict script injection. - * @param forMainFrameOnly Whether to inject only in main frame. - * @param initialUseOnAjaxReadyStateChange Initial value for onAjaxReadyStateChange flag. - * @param initialUseOnAjaxProgress Initial value for onAjaxProgress flag. - */ - static std::unique_ptr INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT( - const std::optional>& allowedOriginRules, - bool forMainFrameOnly, - bool initialUseOnAjaxReadyStateChange = false, - bool initialUseOnAjaxProgress = false) { - return std::make_unique( - INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, - INTERCEPT_AJAX_REQUEST_JS_SOURCE(initialUseOnAjaxReadyStateChange, initialUseOnAjaxProgress), - UserScriptInjectionTime::atDocumentStart, - forMainFrameOnly, - allowedOriginRules, - nullptr, // contentWorld - true, // requiredInAllContentWorlds - std::vector{} // no additional message handlers needed - ); - } -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_INTERCEPT_AJAX_REQUEST_JS_H_ diff --git a/flutter_inappwebview_linux/linux/plugin_scripts_js/intercept_fetch_request_js.h b/flutter_inappwebview_linux/linux/plugin_scripts_js/intercept_fetch_request_js.h deleted file mode 100644 index e4b53e9017..0000000000 --- a/flutter_inappwebview_linux/linux/plugin_scripts_js/intercept_fetch_request_js.h +++ /dev/null @@ -1,216 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_INTERCEPT_FETCH_REQUEST_JS_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_INTERCEPT_FETCH_REQUEST_JS_H_ - -#include -#include -#include -#include - -#include "../types/plugin_script.h" -#include "javascript_bridge_js.h" -#include "intercept_ajax_request_js.h" // For JAVASCRIPT_UTIL_VAR_NAME - -namespace flutter_inappwebview_plugin { - -/** - * JavaScript for intercepting fetch() requests. - * - * This script wraps the global fetch() function to intercept requests - * before they're sent and allow modification of the request/response. - * - * Matches iOS implementation: InterceptFetchRequestJS.swift - */ -class InterceptFetchRequestJS { - public: - inline static const std::string INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = - "IN_APP_WEBVIEW_INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT"; - - /** - * Flag variable name used to enable/disable fetch request interception at runtime. - */ - static std::string FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE() { - return "window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + - "._useShouldInterceptFetchRequest"; - } - - /** - * JavaScript source code for fetch request interception. - * Wraps the global fetch() function to intercept requests. - * - * Matches iOS InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_SOURCE() - */ - static std::string INTERCEPT_FETCH_REQUEST_JS_SOURCE() { - const std::string flagIntercept = FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE(); - const std::string utilVarName = InterceptAjaxRequestJS::JAVASCRIPT_UTIL_VAR_NAME(); - const std::string bridgeName = JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME(); - - // Ensure utility functions exist (may already be defined by AJAX script) - std::string utilitySetup = R"JS( -if (typeof )JS" + utilVarName + R"JS( === 'undefined') { - )JS" + InterceptAjaxRequestJS::JAVASCRIPT_UTIL_JS_SOURCE() + R"JS( -} -)JS"; - - return utilitySetup + flagIntercept + R"JS( = true; -(function(fetch) { - if (fetch == null) { - return; - } - window.fetch = async function(resource, init) { - if ()JS" + flagIntercept + R"JS( == null || )JS" + flagIntercept + R"JS( == true) { - var fetchRequest = { - url: null, - method: null, - headers: null, - body: null, - mode: null, - credentials: null, - cache: null, - redirect: null, - referrer: null, - referrerPolicy: null, - integrity: null, - keepalive: null - }; - if (resource instanceof Request) { - fetchRequest.url = resource.url; - fetchRequest.method = resource.method; - fetchRequest.headers = resource.headers; - fetchRequest.body = resource.body; - fetchRequest.mode = resource.mode; - fetchRequest.credentials = resource.credentials; - fetchRequest.cache = resource.cache; - fetchRequest.redirect = resource.redirect; - fetchRequest.referrer = resource.referrer; - fetchRequest.referrerPolicy = resource.referrerPolicy; - fetchRequest.integrity = resource.integrity; - fetchRequest.keepalive = resource.keepalive; - } else { - fetchRequest.url = resource != null ? resource.toString() : null; - if (init != null) { - fetchRequest.method = init.method; - fetchRequest.headers = init.headers; - fetchRequest.body = init.body; - fetchRequest.mode = init.mode; - fetchRequest.credentials = init.credentials; - fetchRequest.cache = init.cache; - fetchRequest.redirect = init.redirect; - fetchRequest.referrer = init.referrer; - fetchRequest.referrerPolicy = init.referrerPolicy; - fetchRequest.integrity = init.integrity; - fetchRequest.keepalive = init.keepalive; - } - } - if (fetchRequest.headers instanceof Headers) { - fetchRequest.headers = )JS" + utilVarName + R"JS(.convertHeadersToJson(fetchRequest.headers); - } - fetchRequest.credentials = )JS" + utilVarName + R"JS(.convertCredentialsToJson(fetchRequest.credentials); - return )JS" + utilVarName + R"JS(.convertBodyRequest(fetchRequest.body).then(function(body) { - fetchRequest.body = body; - return window.)JS" + bridgeName + R"JS(.callHandler('shouldInterceptFetchRequest', fetchRequest).then(function(result) { - if (result != null) { - try { - result = JSON.parse(result); - } catch(e) {} - if (result != null && result.action === 0) { - var controller = new AbortController(); - if (init != null) { - init.signal = controller.signal; - } else { - init = { - signal: controller.signal - }; - } - controller.abort(); - return fetch(resource, init); - } - if (result != null) { - if (result.body != null && !)JS" + utilVarName + R"JS(.isString(result.body) && result.body.length > 0) { - var bodyString = )JS" + utilVarName + R"JS(.arrayBufferToString(result.body); - if ()JS" + utilVarName + R"JS(.isBodyFormData(bodyString)) { - var formDataContentType = )JS" + utilVarName + R"JS(.getFormDataContentType(bodyString); - if (result.headers != null) { - result.headers['Content-Type'] = result.headers['Content-Type'] == null ? formDataContentType : result.headers['Content-Type']; - } else { - result.headers = { 'Content-Type': formDataContentType }; - } - } - } - resource = result.url; - if (init == null) { - init = {}; - } - if (result.method != null && result.method.length > 0) { - init.method = result.method; - } - if (result.headers != null && Object.keys(result.headers).length > 0) { - init.headers = )JS" + utilVarName + R"JS(.convertJsonToHeaders(result.headers); - } - if ()JS" + utilVarName + R"JS(.isString(result.body) || result.body == null) { - init.body = result.body; - } else if (result.body.length > 0) { - init.body = new Uint8Array(result.body); - } - if (result.mode != null && result.mode.length > 0) { - init.mode = result.mode; - } - if (result.credentials != null) { - init.credentials = )JS" + utilVarName + R"JS(.convertJsonToCredential(result.credentials); - } - if (result.cache != null && result.cache.length > 0) { - init.cache = result.cache; - } - if (result.redirect != null && result.redirect.length > 0) { - init.redirect = result.redirect; - } - if (result.referrer != null && result.referrer.length > 0) { - init.referrer = result.referrer; - } - if (result.referrerPolicy != null && result.referrerPolicy.length > 0) { - init.referrerPolicy = result.referrerPolicy; - } - if (result.integrity != null && result.integrity.length > 0) { - init.integrity = result.integrity; - } - if (result.keepalive != null) { - init.keepalive = result.keepalive; - } - return fetch(resource, init); - } - } - return fetch(resource, init); - }); - }); - } else { - return fetch(resource, init); - } - }; -})(window.fetch); -)JS"; - } - - /** - * Creates a PluginScript for fetch request interception. - * - * @param allowedOriginRules Optional list of origin rules to restrict script injection. - * @param forMainFrameOnly Whether to inject only in main frame. - */ - static std::unique_ptr INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT( - const std::optional>& allowedOriginRules, - bool forMainFrameOnly) { - return std::make_unique( - INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, - INTERCEPT_FETCH_REQUEST_JS_SOURCE(), - UserScriptInjectionTime::atDocumentStart, - forMainFrameOnly, - allowedOriginRules, - nullptr, // contentWorld - true, // requiredInAllContentWorlds - std::vector{} // no additional message handlers needed - ); - } -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_INTERCEPT_FETCH_REQUEST_JS_H_ diff --git a/flutter_inappwebview_linux/linux/plugin_scripts_js/javascript_bridge_js.h b/flutter_inappwebview_linux/linux/plugin_scripts_js/javascript_bridge_js.h deleted file mode 100644 index 37f752cf8a..0000000000 --- a/flutter_inappwebview_linux/linux/plugin_scripts_js/javascript_bridge_js.h +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_BRIDGE_JS_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_BRIDGE_JS_H_ - -#include -#include -#include -#include - -#include "../types/plugin_script.h" -#include "../utils/string.h" - -namespace flutter_inappwebview_plugin { - -// Forward declaration to avoid circular dependency -class WindowIdJS; - -/** - * JavaScript bridge for communication between web content and native code. - * - * This implementation matches iOS JavaScriptBridgeJS.swift for consistency. - * It uses webkit.messageHandlers to communicate with native code and includes - * support for multi-window scenarios via _windowId. - */ -class JavaScriptBridgeJS { - public: - static void set_JAVASCRIPT_BRIDGE_NAME(const std::string& bridgeName) { - _JAVASCRIPT_BRIDGE_NAME = bridgeName; - } - - static std::string get_JAVASCRIPT_BRIDGE_NAME() { return _JAVASCRIPT_BRIDGE_NAME; } - - inline static const std::string JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME = - "IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT"; - - inline static const std::string VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET = - "$IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_BRIDGE_SECRET"; - - /** - * Returns the JavaScript variable name for the window ID. - * Match iOS WindowIdJS: "window._flutter_inappwebview_windowId" - */ - static std::string WINDOW_ID_VARIABLE_JS_SOURCE() { - return "window._" + get_JAVASCRIPT_BRIDGE_NAME() + "_windowId"; - } - - /** - * JavaScript source code for the bridge. - * This code sets up window.flutter_inappwebview.callHandler() function - * which communicates with native code via webkit.messageHandlers. - * - * Matches iOS JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_SOURCE() - */ - static std::string JAVASCRIPT_BRIDGE_JS_SOURCE() { - return R"JS( -window.)JS" + - get_JAVASCRIPT_BRIDGE_NAME() + R"JS( = {}; -window.)JS" + - get_JAVASCRIPT_BRIDGE_NAME() + R"JS(._webMessageChannels = {}; -(function(window) { - var bridgeSecret = ')JS" + - VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET + R"JS('; - var _JSON_stringify; - var _Array_slice; - var _UserMessageHandler; - var _postMessage; - - try { - _JSON_stringify = window.JSON.stringify; - _Array_slice = window.Array.prototype.slice; - _Array_slice.call = window.Function.prototype.call; - _UserMessageHandler = window.webkit.messageHandlers['callHandler']; - _postMessage = _UserMessageHandler.postMessage; - _postMessage.call = window.Function.prototype.call; - } catch (_) { return; } - - window.)JS" + - get_JAVASCRIPT_BRIDGE_NAME() + R"JS(.callHandler = function() { - var _windowId = )JS" + - WINDOW_ID_VARIABLE_JS_SOURCE() + R"JS(; - // Use with_reply API - postMessage returns a Promise directly - return _postMessage.call(_UserMessageHandler, { - 'handlerName': arguments[0], - '_bridgeSecret': bridgeSecret, - 'args': _JSON_stringify(_Array_slice.call(arguments, 1)), - '_windowId': _windowId, - '_isMainFrame': (window.top === window) - }); - }; -})(window); -)JS"; - } - - /** - * JavaScript to dispatch the platform ready event. - */ - static std::string PLATFORM_READY_JS_SOURCE() { - return R"JS( -(function() { - if ((window.top == null || window.top === window) && - window.)JS" + - get_JAVASCRIPT_BRIDGE_NAME() + R"JS( != null && - window.)JS" + - get_JAVASCRIPT_BRIDGE_NAME() + R"JS(._platformReady == null) { - window.dispatchEvent(new Event('flutterInAppWebViewPlatformReady')); - window.)JS" + - get_JAVASCRIPT_BRIDGE_NAME() + R"JS(._platformReady = true; - } -})(); -)JS"; - } - - /** - * Creates a PluginScript for the JavaScript bridge. - */ - static std::unique_ptr JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT( - const std::string& expectedBridgeSecret, - const std::optional>& allowedOriginRules, bool forMainFrameOnly) { - std::string source = JAVASCRIPT_BRIDGE_JS_SOURCE(); - // Replace the placeholder with the actual secret - size_t pos = source.find(VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET); - if (pos != std::string::npos) { - source.replace(pos, VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET.length(), expectedBridgeSecret); - } - - return std::make_unique( - JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME, source, - UserScriptInjectionTime::atDocumentStart, forMainFrameOnly, allowedOriginRules, - nullptr, // contentWorld - true, // requiredInAllContentWorlds - std::vector{"callHandler"} // messageHandlerNames - ); - } - - private: - inline static std::string _JAVASCRIPT_BRIDGE_NAME = "flutter_inappwebview"; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_BRIDGE_JS_H_ diff --git a/flutter_inappwebview_linux/linux/plugin_scripts_js/on_load_resource_js.h b/flutter_inappwebview_linux/linux/plugin_scripts_js/on_load_resource_js.h deleted file mode 100644 index 489f6c00ab..0000000000 --- a/flutter_inappwebview_linux/linux/plugin_scripts_js/on_load_resource_js.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_ON_LOAD_RESOURCE_JS_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_ON_LOAD_RESOURCE_JS_H_ - -#include -#include -#include -#include - -#include "../types/plugin_script.h" -#include "javascript_bridge_js.h" - -namespace flutter_inappwebview_plugin { - -/** - * JavaScript for capturing resource load events. - * - * This script uses the PerformanceObserver API to monitor resource loading - * and sends the data to the native side via the JavaScript bridge. - * - * Matches iOS implementation: OnLoadResourceJS.swift - */ -class OnLoadResourceJS { - public: - inline static const std::string ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT_GROUP_NAME = - "IN_APP_WEBVIEW_ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT"; - - /** - * Flag variable name used to enable/disable the observer at runtime. - */ - static std::string FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE() { - return "window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + - "._useOnLoadResource"; - } - - /** - * JavaScript source code for resource loading observation. - * Uses PerformanceObserver API to track all resource loads. - * - * Matches iOS OnLoadResourceJS.swift implementation. - */ - static std::string ON_LOAD_RESOURCE_JS_SOURCE() { - const std::string flagVariable = FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE(); - const std::string bridgeName = JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME(); - - return flagVariable + R"JS( = true; -(function() { - var observer = new PerformanceObserver(function(list) { - list.getEntries().forEach(function(entry) { - if ()JS" + flagVariable + R"JS( == null || )JS" + flagVariable + R"JS( == true) { - var resource = { - "url": entry.name, - "initiatorType": entry.initiatorType, - "startTime": entry.startTime, - "duration": entry.duration - }; - window.)JS" + bridgeName + R"JS(.callHandler("onLoadResource", resource); - } - }); - }); - observer.observe({entryTypes: ['resource']}); -})(); -)JS"; - } - - /** - * Creates a PluginScript for resource load observation. - * - * @param allowedOriginRules Optional list of origin rules to restrict script injection. - * @param forMainFrameOnly Whether to inject only in main frame. - */ - static std::unique_ptr ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT( - const std::optional>& allowedOriginRules, - bool forMainFrameOnly) { - return std::make_unique( - ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT_GROUP_NAME, - ON_LOAD_RESOURCE_JS_SOURCE(), - UserScriptInjectionTime::atDocumentStart, - forMainFrameOnly, - allowedOriginRules, - nullptr, // contentWorld - false, // requiredInAllContentWorlds - std::vector{} // no additional message handlers needed - ); - } -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_ON_LOAD_RESOURCE_JS_H_ diff --git a/flutter_inappwebview_linux/linux/plugin_scripts_js/print_interception_js.h b/flutter_inappwebview_linux/linux/plugin_scripts_js/print_interception_js.h deleted file mode 100644 index e5fba6b9d4..0000000000 --- a/flutter_inappwebview_linux/linux/plugin_scripts_js/print_interception_js.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_PRINT_INTERCEPTION_JS_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_PRINT_INTERCEPTION_JS_H_ - -#include -#include -#include -#include - -#include "../types/plugin_script.h" -#include "javascript_bridge_js.h" - -namespace flutter_inappwebview_plugin { - -/** - * JavaScript for intercepting window.print() calls. - * - * WPE WebKit doesn't have a native print signal like WebKitGTK, - * so we intercept window.print() calls via JavaScript and notify - * the Dart side via the JavaScript bridge. - * - * This allows the app to: - * - Know when a page tries to print - * - Optionally implement print-to-PDF functionality - * - Handle print requests in a platform-appropriate way - */ -class PrintInterceptionJS { - public: - inline static const std::string PRINT_INTERCEPTION_JS_PLUGIN_SCRIPT_GROUP_NAME = - "IN_APP_WEBVIEW_PRINT_INTERCEPTION_JS_PLUGIN_SCRIPT"; - - /** - * JavaScript source code for print interception. - * This code intercepts window.print() calls and notifies the native side. - */ - static std::string PRINT_INTERCEPTION_JS_SOURCE() { - return R"JS( -(function() { - // Avoid re-registering - if (window._flutterInAppWebViewPrintInterceptionInit) return; - window._flutterInAppWebViewPrintInterceptionInit = true; - - // Store the original window.print function - var originalPrint = window.print; - - // Override window.print - window.print = function() { - // Check if the JavaScript bridge is available - var bridge = window.)JS" + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + R"JS(; - if (bridge && typeof bridge.callHandler === 'function') { - // Notify the native side about the print request - bridge.callHandler('_onPrintRequest', { - url: window.location.href, - title: document.title - }).then(function(result) { - // If the native side returns true, proceed with original print - // Otherwise, the native side handled the print request - if (result === true) { - originalPrint.call(window); - } - }).catch(function(error) { - // On error, fall back to original print behavior - console.warn('Print interception error:', error); - originalPrint.call(window); - }); - } else { - // No bridge available, use original print - originalPrint.call(window); - } - }; -})(); -)JS"; - } - - /** - * Creates a PluginScript for print interception. - */ - static std::unique_ptr PRINT_INTERCEPTION_JS_PLUGIN_SCRIPT( - const std::optional>& allowedOriginRules, - bool forMainFrameOnly) { - return std::make_unique( - PRINT_INTERCEPTION_JS_PLUGIN_SCRIPT_GROUP_NAME, PRINT_INTERCEPTION_JS_SOURCE(), - UserScriptInjectionTime::atDocumentStart, forMainFrameOnly, - allowedOriginRules, - nullptr, // contentWorld - true, // requiredInAllContentWorlds - std::vector{} // no additional message handlers needed - ); - } -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_PRINT_INTERCEPTION_JS_H_ diff --git a/flutter_inappwebview_linux/linux/plugin_scripts_js/web_message_channel_js.h b/flutter_inappwebview_linux/linux/plugin_scripts_js/web_message_channel_js.h deleted file mode 100644 index bb316a1916..0000000000 --- a/flutter_inappwebview_linux/linux/plugin_scripts_js/web_message_channel_js.h +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_MESSAGE_CHANNEL_JS_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_MESSAGE_CHANNEL_JS_H_ - -#include - -#include "javascript_bridge_js.h" - -namespace flutter_inappwebview_plugin { - -/** - * JavaScript support for WebMessageChannel. - * - * Provides the variable name for storing MessageChannels in JavaScript - * and JavaScript snippets for creating and managing WebMessageChannels. - * Matches iOS WebMessageChannelJS.swift for consistency. - */ -class WebMessageChannelJS { - public: - /** - * Returns the JavaScript variable name for storing WebMessageChannels. - * Example: "window.flutter_inappwebview._webMessageChannels" - */ - static std::string WEB_MESSAGE_CHANNELS_VARIABLE_NAME() { - return "window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + - "._webMessageChannels"; - } - - /** - * JavaScript to create a new MessageChannel and store it. - * - * @param channelId The unique identifier for the channel - * @return JavaScript code that creates the channel and returns its info - */ - static std::string createWebMessageChannelJs(const std::string& channelId) { - return - "(function() {\n" - " var channel = new MessageChannel();\n" - " " + WEB_MESSAGE_CHANNELS_VARIABLE_NAME() + "['" + channelId + "'] = channel;\n" - " return {'id': '" + channelId + "'};\n" - "})();"; - } - - /** - * JavaScript to set the onmessage callback for a port. - * - * @param channelId The channel identifier - * @param portIndex The port index (0 or 1) - * @return JavaScript code that sets up the callback - */ - static std::string setWebMessageCallbackJs(const std::string& channelId, int portIndex) { - std::string portName = portIndex == 0 ? "port1" : "port2"; - return - "(function() {\n" - " var webMessageChannel = " + WEB_MESSAGE_CHANNELS_VARIABLE_NAME() + "['" + channelId + "'];\n" - " if (webMessageChannel != null) {\n" - " webMessageChannel." + portName + ".onmessage = function(event) {\n" - " " + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onWebMessagePortMessageReceived', {\n" - " 'webMessageChannelId': '" + channelId + "',\n" - " 'index': " + std::to_string(portIndex) + ",\n" - " 'message': {\n" - " 'data': window.ArrayBuffer != null && event.data instanceof ArrayBuffer\n" - " ? Array.from(new Uint8Array(event.data))\n" - " : (event.data != null ? event.data.toString() : null),\n" - " 'type': window.ArrayBuffer != null && event.data instanceof ArrayBuffer ? 1 : 0\n" - " }\n" - " });\n" - " };\n" - " webMessageChannel." + portName + ".start();\n" - " }\n" - "})();"; - } - - /** - * JavaScript to post a message on a port. - * - * @param channelId The channel identifier - * @param portIndex The port index (0 or 1) - * @param messageDataJs The message data as JavaScript expression - * @return JavaScript code that posts the message - */ - static std::string postMessageJs(const std::string& channelId, int portIndex, - const std::string& messageDataJs) { - std::string portName = portIndex == 0 ? "port1" : "port2"; - return - "(function() {\n" - " var webMessageChannel = " + WEB_MESSAGE_CHANNELS_VARIABLE_NAME() + "['" + channelId + "'];\n" - " if (webMessageChannel != null) {\n" - " webMessageChannel." + portName + ".postMessage(" + messageDataJs + ");\n" - " }\n" - "})();"; - } - - /** - * JavaScript to close a port. - * - * @param channelId The channel identifier - * @param portIndex The port index (0 or 1) - * @return JavaScript code that closes the port - */ - static std::string closePortJs(const std::string& channelId, int portIndex) { - std::string portName = portIndex == 0 ? "port1" : "port2"; - return - "(function() {\n" - " var webMessageChannel = " + WEB_MESSAGE_CHANNELS_VARIABLE_NAME() + "['" + channelId + "'];\n" - " if (webMessageChannel != null) {\n" - " webMessageChannel." + portName + ".close();\n" - " }\n" - "})();"; - } - - /** - * JavaScript to dispose of a channel (clean up both ports and remove from storage). - * - * @param channelId The channel identifier - * @return JavaScript code that disposes the channel - */ - static std::string disposeChannelJs(const std::string& channelId) { - return - "(function() {\n" - " var webMessageChannel = " + WEB_MESSAGE_CHANNELS_VARIABLE_NAME() + "['" + channelId + "'];\n" - " if (webMessageChannel != null) {\n" - " try { webMessageChannel.port1.close(); } catch(e) {}\n" - " try { webMessageChannel.port2.close(); } catch(e) {}\n" - " delete " + WEB_MESSAGE_CHANNELS_VARIABLE_NAME() + "['" + channelId + "'];\n" - " }\n" - "})();"; - } - - /** - * JavaScript to post a WebMessage to the window, optionally with ports. - * - * @param messageDataJs The message data as JavaScript expression - * @param targetOrigin The target origin string - * @param portsJs Optional JavaScript expression for ports array (empty string if no ports) - * @return JavaScript code that posts the message - */ - static std::string postWebMessageJs(const std::string& messageDataJs, - const std::string& targetOrigin, - const std::string& portsJs) { - std::string portsArg = portsJs.empty() ? "undefined" : portsJs; - return - "(function() {\n" - " window.postMessage(" + messageDataJs + ", '" + targetOrigin + "', " + portsArg + ");\n" - "})();"; - } -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_MESSAGE_CHANNEL_JS_H_ diff --git a/flutter_inappwebview_linux/linux/plugin_scripts_js/web_message_listener_js.h b/flutter_inappwebview_linux/linux/plugin_scripts_js/web_message_listener_js.h deleted file mode 100644 index 2f54fc4942..0000000000 --- a/flutter_inappwebview_linux/linux/plugin_scripts_js/web_message_listener_js.h +++ /dev/null @@ -1,186 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_MESSAGE_LISTENER_JS_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_MESSAGE_LISTENER_JS_H_ - -#include - -#include "javascript_bridge_js.h" - -namespace flutter_inappwebview_plugin { - -/** - * JavaScript source for WebMessageListener support. - * - * This creates the FlutterInAppWebViewWebMessageListener class that web pages - * can use to communicate with the native side via postMessage. - * - * Usage in JavaScript: - * myListener.postMessage("Hello from web!"); - * myListener.addEventListener("message", (event) => { ... }); - * - * Matches iOS WebMessageListenerJS.swift for consistency. - */ -class WebMessageListenerJS { - public: - /** - * JavaScript source code for the FlutterInAppWebViewWebMessageListener class. - */ - static std::string WEB_MESSAGE_LISTENER_JS_SOURCE() { - return R"JS( -function FlutterInAppWebViewWebMessageListener(jsObjectName) { - this.jsObjectName = jsObjectName; - this.listeners = []; - this.onmessage = null; -} -FlutterInAppWebViewWebMessageListener.prototype.postMessage = function(data) { - var message = { - "data": window.ArrayBuffer != null && data instanceof ArrayBuffer ? Array.from(new Uint8Array(data)) : (data != null ? data.toString() : null), - "type": window.ArrayBuffer != null && data instanceof ArrayBuffer ? 1 : 0 - }; - window.)JS" + - JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + R"JS(.callHandler('onWebMessageListenerPostMessageReceived', { - jsObjectName: this.jsObjectName, - message: message, - sourceOrigin: window.location.origin, - isMainFrame: window.top === window - }); -}; -FlutterInAppWebViewWebMessageListener.prototype.addEventListener = function(type, listener) { - if (listener == null) { - return; - } - this.listeners.push(listener); -}; -FlutterInAppWebViewWebMessageListener.prototype.removeEventListener = function(type, listener) { - if (listener == null) { - return; - } - var index = this.listeners.indexOf(listener); - if (index >= 0) { - this.listeners.splice(index, 1); - } -}; -)JS"; - } - - /** - * JavaScript to check if origin is allowed based on origin rules. - * - * Origin rules format: - * - "*" matches all origins - * - "https://example.com" matches exact origin - * - "https: // *.example.com" matches subdomains (note: no space in actual use) - */ - static std::string IS_ORIGIN_ALLOWED_JS_SOURCE() { - // Note: Using string concatenation to avoid compiler warning about - // regex patterns like /[0-9]+/g being interpreted as C comments. - return - "var _normalizeIPv6 = function(ip_string) {\n" - " var ipv4 = ip_string.match(/(.*)([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$)/);\n" - " if (ipv4) {\n" - " ip_string = ipv4[1];\n" - " ipv4 = ipv4[2].match(/[0-9]+/" "g);\n" // Split to avoid /* comment warning - " for (var i = 0;i < 4;i ++) {\n" - " var byte = parseInt(ipv4[i],10);\n" - " ipv4[i] = ('0' + byte.toString(16)).substr(-2);\n" - " }\n" - " ip_string += ipv4[0] + ipv4[1] + ':' + ipv4[2] + ipv4[3];\n" - " }\n" - " ip_string = ip_string.replace(/^:|:$/" "g, '');\n" // Split to avoid /* comment warning - " var ipv6 = ip_string.split(':');\n" - " for (var i = 0; i < ipv6.length; i ++) {\n" - " var hex = ipv6[i];\n" - " if (hex != '') {\n" - " ipv6[i] = ('0000' + hex).substr(-4);\n" - " }\n" - " else {\n" - " hex = [];\n" - " for (var j = ipv6.length; j <= 8; j ++) {\n" - " hex.push('0000');\n" - " }\n" - " ipv6[i] = hex.join(':');\n" - " }\n" - " }\n" - " return ipv6.join(':');\n" - "};\n" - "\n" - "var _isOriginAllowed = function(allowedOriginRules, scheme, host, port) {\n" - " for (var rule of allowedOriginRules) {\n" - " if (rule === '*') {\n" - " return true;\n" - " }\n" - " if (scheme == null || scheme === '') {\n" - " continue;\n" - " }\n" - " if ((scheme == null || scheme === '') && (host == null || host === '') && (port === 0 || port === '' || port == null)) {\n" - " continue;\n" - " }\n" - " var rulePort = rule.port == null || rule.port === 0 ? (rule.scheme == 'https' ? 443 : 80) : rule.port;\n" - " var currentPort = port === 0 || port === '' || port == null ? (scheme == 'https' ? 443 : 80) : port;\n" - " var IPv6 = null;\n" - " if (rule.host != null && rule.host[0] === '[') {\n" - " try {\n" - " IPv6 = _normalizeIPv6(rule.host.substring(1, rule.host.length - 1));\n" - " } catch(e) {}\n" - " }\n" - " var hostIPv6 = null;\n" - " try {\n" - " hostIPv6 = _normalizeIPv6(host);\n" - " } catch(e) {}\n" - "\n" - " var schemeAllowed = scheme == rule.scheme;\n" - " \n" - " var hostAllowed = rule.host == null ||\n" - " rule.host === '' ||\n" - " host === rule.host ||\n" - " (rule.host[0] === '*' && host != null && host.indexOf(rule.host.split('*')[1]) >= 0) ||\n" - " (hostIPv6 != null && IPv6 != null && hostIPv6 === IPv6);\n" - "\n" - " var portAllowed = rulePort === currentPort;\n" - "\n" - " if (schemeAllowed && hostAllowed && portAllowed) {\n" - " return true;\n" - " }\n" - " }\n" - " return false;\n" - "};\n"; - } - - /** - * Creates the JavaScript to inject a web message listener with the given name and origin rules. - * - * @param jsObjectName The name of the JavaScript object to inject (e.g., "myListener") - * @param allowedOriginRulesJs JSON array string of allowed origin rules - */ - static std::string createWebMessageListenerInjectionJs( - const std::string& jsObjectName, - const std::string& allowedOriginRulesJs) { - std::string jsObjectNameEscaped = jsObjectName; - // Escape single quotes in jsObjectName - size_t pos = 0; - while ((pos = jsObjectNameEscaped.find("'", pos)) != std::string::npos) { - jsObjectNameEscaped.replace(pos, 1, "\\'"); - pos += 2; - } - - return "(function() {\n" + IS_ORIGIN_ALLOWED_JS_SOURCE() + "\n" + - WEB_MESSAGE_LISTENER_JS_SOURCE() + - "\nvar allowedOriginRules = " + allowedOriginRulesJs + - ";\n" - "var isPageBlank = window.location.href === 'about:blank';\n" - "var scheme = !isPageBlank ? window.location.protocol.replace(':', '') : null;\n" - "var host = !isPageBlank ? window.location.hostname : null;\n" - "var port = !isPageBlank ? window.location.port : null;\n" - "if (_isOriginAllowed(allowedOriginRules, scheme, host, port)) {\n" - " window['" + - jsObjectNameEscaped + - "'] = new FlutterInAppWebViewWebMessageListener('" + - jsObjectNameEscaped + - "');\n" - "}\n" - "})();"; - } -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_MESSAGE_LISTENER_JS_H_ diff --git a/flutter_inappwebview_linux/linux/plugin_scripts_js/window_id_js.h b/flutter_inappwebview_linux/linux/plugin_scripts_js/window_id_js.h deleted file mode 100644 index 9669973221..0000000000 --- a/flutter_inappwebview_linux/linux/plugin_scripts_js/window_id_js.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_WINDOW_ID_JS_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_WINDOW_ID_JS_H_ - -#include - -#include "javascript_bridge_js.h" - -namespace flutter_inappwebview_plugin { - -/** - * JavaScript for managing window IDs in multi-window scenarios. - * - * This matches the iOS WindowIdJS.swift implementation. - * Window IDs are used to route JavaScript bridge calls to the correct - * webview when using window.open() or similar multi-window features. - * - * Note: The WINDOW_ID_VARIABLE_JS_SOURCE() function is now in JavaScriptBridgeJS - * to avoid circular dependencies. This class provides the initialization script. - */ -class WindowIdJS { - public: - inline static const std::string WINDOW_ID_JS_PLUGIN_SCRIPT_GROUP_NAME = - "IN_APP_WEBVIEW_WINDOW_ID_JS_PLUGIN_SCRIPT"; - - /** - * Placeholder value that will be replaced with the actual window ID. - */ - inline static const std::string VAR_PLACEHOLDER_VALUE = "$PLACEHOLDER_VALUE"; - - /** - * Returns JavaScript code to initialize the window ID. - * The placeholder will be replaced with the actual window ID. - * Match iOS: WINDOW_ID_INITIALIZE_JS_SOURCE() - */ - static std::string WINDOW_ID_INITIALIZE_JS_SOURCE() { - return R"JS( -(function() { - )JS" + JavaScriptBridgeJS::WINDOW_ID_VARIABLE_JS_SOURCE() + - R"JS( = )JS" + VAR_PLACEHOLDER_VALUE + R"JS(; - return )JS" + - JavaScriptBridgeJS::WINDOW_ID_VARIABLE_JS_SOURCE() + R"JS(; -})() -)JS"; - } -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_WINDOW_ID_JS_H_ diff --git a/flutter_inappwebview_linux/linux/proxy_manager.cc b/flutter_inappwebview_linux/linux/proxy_manager.cc deleted file mode 100644 index 884799a5c7..0000000000 --- a/flutter_inappwebview_linux/linux/proxy_manager.cc +++ /dev/null @@ -1,200 +0,0 @@ -#include "proxy_manager.h" - -#include -#include - -#include "plugin_instance.h" -#include "utils/flutter.h" -#include "utils/log.h" - -namespace flutter_inappwebview_plugin { - -namespace { -// Helper to compare method names -bool string_equals(const gchar* a, const char* b) { - return strcmp(a, b) == 0; -} -} // namespace - -// === ProxyRule === - -ProxyRule::ProxyRule(FlValue* map) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - url = get_fl_map_value(map, "url", ""); - - // Check for schemeFilter - it may be a map with "rawValue" or a direct value - FlValue* schemeFilterValue = get_fl_map_value_raw(map, "schemeFilter"); - if (schemeFilterValue != nullptr) { - if (fl_value_get_type(schemeFilterValue) == FL_VALUE_TYPE_MAP) { - // It's a map, look for "rawValue" field - schemeFilter = get_optional_fl_map_value(schemeFilterValue, "rawValue"); - } else if (fl_value_get_type(schemeFilterValue) == FL_VALUE_TYPE_STRING) { - // It's a direct string - schemeFilter = std::string(fl_value_get_string(schemeFilterValue)); - } - } -} - -// === ProxySettings === - -ProxySettings::ProxySettings(FlValue* map) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - bypassRules = get_fl_map_value>(map, "bypassRules", {}); - - // Parse proxyRules - FlValue* proxyRulesValue = get_fl_map_value_raw(map, "proxyRules"); - if (proxyRulesValue != nullptr && fl_value_get_type(proxyRulesValue) == FL_VALUE_TYPE_LIST) { - size_t length = fl_value_get_length(proxyRulesValue); - for (size_t i = 0; i < length; i++) { - FlValue* item = fl_value_get_list_value(proxyRulesValue, i); - if (item != nullptr && fl_value_get_type(item) == FL_VALUE_TYPE_MAP) { - proxyRules.emplace_back(item); - } - } - } -} - -// === ProxyManager === - -ProxyManager::ProxyManager(PluginInstance* plugin) - : ChannelDelegate(plugin->messenger(), METHOD_CHANNEL_NAME), - plugin_(plugin) {} - -ProxyManager::~ProxyManager() { - debugLog("dealloc ProxyManager"); - plugin_ = nullptr; -} - -void ProxyManager::HandleMethodCall(FlMethodCall* method_call) { - const gchar* method = fl_method_call_get_name(method_call); - FlValue* args = fl_method_call_get_args(method_call); - - if (string_equals(method, "setProxyOverride")) { - FlValue* settingsMap = get_fl_map_value_raw(args, "settings"); - if (settingsMap == nullptr || fl_value_get_type(settingsMap) != FL_VALUE_TYPE_MAP) { - fl_method_call_respond_success(method_call, fl_value_new_null(), nullptr); - return; - } - - ProxySettings settings(settingsMap); - setProxyOverride(settings); - fl_method_call_respond_success(method_call, fl_value_new_null(), nullptr); - - } else if (string_equals(method, "clearProxyOverride")) { - clearProxyOverride(); - fl_method_call_respond_success(method_call, fl_value_new_null(), nullptr); - - } else { - fl_method_call_respond_not_implemented(method_call, nullptr); - } -} - -void ProxyManager::setProxyOverride(const ProxySettings& settings) { - WebKitNetworkSession* session = webkit_network_session_get_default(); - if (session == nullptr) { - errorLog("ProxyManager: Failed to get default network session"); - return; - } - - // If no proxy rules, clear the proxy - if (settings.proxyRules.empty()) { - clearProxyOverride(); - return; - } - - // Build the ignore_hosts array from bypassRules - std::vector ignoreHostsCStrings; - for (const auto& rule : settings.bypassRules) { - ignoreHostsCStrings.push_back(rule.c_str()); - } - ignoreHostsCStrings.push_back(nullptr); // NULL-terminate the array - - // Get the default proxy URI (first proxy rule with no schemeFilter, or schemeFilter == "*") - std::string defaultProxyUri; - for (const auto& rule : settings.proxyRules) { - if (!rule.schemeFilter.has_value() || rule.schemeFilter.value().empty()) { - defaultProxyUri = rule.url; - break; - } - - std::string scheme = rule.schemeFilter.value(); - for (char& c : scheme) { - c = static_cast(std::tolower(static_cast(c))); - } - if (scheme == "*") { - defaultProxyUri = rule.url; - break; - } - } - - // Collect supported scheme-specific proxy rules so we can decide whether we - // need to force a direct default proxy to activate custom mode. - std::vector> schemeSpecificProxyRules; - schemeSpecificProxyRules.reserve(settings.proxyRules.size()); - for (const auto& rule : settings.proxyRules) { - if (!rule.schemeFilter.has_value() || rule.schemeFilter.value().empty()) { - continue; - } - - std::string scheme = rule.schemeFilter.value(); - for (char& c : scheme) { - c = static_cast(std::tolower(static_cast(c))); - } - - // Treat "*" as default proxy (already handled above). - if (scheme == "*") { - continue; - } - - // Accept common scheme filters. - if (scheme != "http" && scheme != "https" && scheme != "socks" && scheme != "socks4" && - scheme != "socks5") { - continue; - } - - schemeSpecificProxyRules.emplace_back(std::move(scheme), rule.url); - } - - // Create the proxy settings - WebKitNetworkProxySettings* proxySettings = webkit_network_proxy_settings_new( - defaultProxyUri.empty() ? nullptr : defaultProxyUri.c_str(), - settings.bypassRules.empty() ? nullptr : ignoreHostsCStrings.data()); - - if (proxySettings == nullptr) { - errorLog("ProxyManager: Failed to create WebKitNetworkProxySettings"); - return; - } - - // Add scheme-specific proxies - for (const auto& entry : schemeSpecificProxyRules) { - webkit_network_proxy_settings_add_proxy_for_scheme( - proxySettings, entry.first.c_str(), entry.second.c_str()); - } - - // Apply the proxy settings to the session - webkit_network_session_set_proxy_settings( - session, WEBKIT_NETWORK_PROXY_MODE_CUSTOM, proxySettings); - - // Free the proxy settings - webkit_network_proxy_settings_free(proxySettings); -} - -void ProxyManager::clearProxyOverride() { - WebKitNetworkSession* session = webkit_network_session_get_default(); - if (session == nullptr) { - errorLog("ProxyManager: Failed to get default network session"); - return; - } - - // Revert to system default proxy settings - webkit_network_session_set_proxy_settings( - session, WEBKIT_NETWORK_PROXY_MODE_DEFAULT, nullptr); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/proxy_manager.h b/flutter_inappwebview_linux/linux/proxy_manager.h deleted file mode 100644 index 7f0f9cd40f..0000000000 --- a/flutter_inappwebview_linux/linux/proxy_manager.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_PROXY_MANAGER_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_PROXY_MANAGER_H_ - -#include -#include - -#include -#include -#include -#include - -#include "types/channel_delegate.h" - -namespace flutter_inappwebview_plugin { - -class PluginInstance; - -/** - * Represents a proxy rule with URL and optional scheme filter. - */ -struct ProxyRule { - std::string url; - std::optional schemeFilter; // "HTTP", "HTTPS", or nullopt for all - - ProxyRule() = default; - ProxyRule(const std::string& url, std::optional schemeFilter = std::nullopt) - : url(url), schemeFilter(schemeFilter) {} - ProxyRule(FlValue* map); -}; - -/** - * Represents proxy settings configuration. - */ -struct ProxySettings { - std::vector bypassRules; - std::vector proxyRules; - - ProxySettings() = default; - ProxySettings(FlValue* map); -}; - -/** - * Manages proxy settings for WPE WebKit. - * Uses WebKitNetworkProxySettings and WebKitNetworkSession for proxy configuration. - */ -class ProxyManager : public ChannelDelegate { - public: - static constexpr const char* METHOD_CHANNEL_NAME = - "com.pichillilorenzo/flutter_inappwebview_proxycontroller"; - - ProxyManager(PluginInstance* plugin); - ~ProxyManager() override; - - /// Get the plugin instance - PluginInstance* plugin() const { return plugin_; } - - void HandleMethodCall(FlMethodCall* method_call) override; - - /** - * Set proxy override with the given settings. - * This applies proxy settings to the default network session. - */ - void setProxyOverride(const ProxySettings& settings); - - /** - * Clear proxy override and revert to system defaults. - */ - void clearProxyOverride(); - - private: - PluginInstance* plugin_ = nullptr; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_PROXY_MANAGER_H_ diff --git a/flutter_inappwebview_linux/linux/test/flutter_inappwebview_linux_plugin_test.cc b/flutter_inappwebview_linux/linux/test/flutter_inappwebview_linux_plugin_test.cc deleted file mode 100644 index 2971f7e7b2..0000000000 --- a/flutter_inappwebview_linux/linux/test/flutter_inappwebview_linux_plugin_test.cc +++ /dev/null @@ -1,16 +0,0 @@ -#include - -// Placeholder test for the flutter_inappwebview_linux plugin. -// More comprehensive tests can be added as features are implemented. - -namespace flutter_inappwebview_plugin { -namespace test { - -TEST(FlutterInappwebviewLinuxPlugin, Placeholder) { - // This is a placeholder test to satisfy the CMake build. - // Real tests should be added for the WebView functionality. - EXPECT_TRUE(true); -} - -} // namespace test -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/base_callback_result.h b/flutter_inappwebview_linux/linux/types/base_callback_result.h deleted file mode 100644 index d7718771ba..0000000000 --- a/flutter_inappwebview_linux/linux/types/base_callback_result.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_BASE_CALLBACK_RESULT_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_BASE_CALLBACK_RESULT_H_ - -#include - -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * Base class for async callback results from Flutter method invocations. - * This mirrors the Windows BaseCallbackResult pattern, adapted for FlValue. - * - * Template parameter T is the decoded result type. - * - * Usage: - * 1. Create a subclass and set decodeResult in the constructor - * 2. Optionally set nonNullSuccess/nullSuccess to return whether default - * behaviour should run - * 3. Optionally set defaultBehaviour to run when no specific handling is done - * 4. Call handleResult() when the async response arrives - */ -template -class BaseCallbackResult { - public: - /** - * Error handler - called when an error response is received. - */ - std::function error; - - /** - * Not implemented handler - called when method is not implemented. - */ - std::function notImplemented; - - /** - * Called when result is non-null. - * Returns true if defaultBehaviour should run. - */ - std::function nonNullSuccess = [](const T) { return true; }; - - /** - * Called when result is null. - * Returns true if defaultBehaviour should run. - */ - std::function nullSuccess = []() { return true; }; - - /** - * Default behaviour to run after success handling. - */ - std::function result)> defaultBehaviour = [](const std::optional) { - }; - - /** - * Decode the FlValue result into type T. - * Must be set by subclasses. - */ - std::function(FlValue* result)> decodeResult = [](FlValue*) { - return std::nullopt; - }; - - BaseCallbackResult() = default; - virtual ~BaseCallbackResult() = default; - - /** - * Handle the async result from Flutter. - * This should be called from the GAsyncReadyCallback. - */ - void handleResult(FlValue* value) { - std::optional result = decodeResult ? decodeResult(value) : std::nullopt; - bool shouldRunDefaultBehaviour = false; - - if (result.has_value()) { - shouldRunDefaultBehaviour = - nonNullSuccess ? nonNullSuccess(result.value()) : shouldRunDefaultBehaviour; - } else { - shouldRunDefaultBehaviour = nullSuccess ? nullSuccess() : shouldRunDefaultBehaviour; - } - - if (shouldRunDefaultBehaviour && defaultBehaviour) { - defaultBehaviour(result); - } - } - - /** - * Handle an error result. - */ - void handleError(const std::string& code, const std::string& message) { - if (error) { - error(code, message); - } - } - - /** - * Handle not implemented response. - */ - void handleNotImplemented() { - if (defaultBehaviour) { - defaultBehaviour(std::nullopt); - } - if (notImplemented) { - notImplemented(); - } - } -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_BASE_CALLBACK_RESULT_H_ diff --git a/flutter_inappwebview_linux/linux/types/channel_delegate.cc b/flutter_inappwebview_linux/linux/types/channel_delegate.cc deleted file mode 100644 index 7cb8d8b1e1..0000000000 --- a/flutter_inappwebview_linux/linux/types/channel_delegate.cc +++ /dev/null @@ -1,60 +0,0 @@ -#include "channel_delegate.h" - -#include - -namespace flutter_inappwebview_plugin { - -ChannelDelegate::ChannelDelegate(FlBinaryMessenger* messenger, const std::string& name) - : messenger_(messenger) { - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - channel_ = fl_method_channel_new(messenger_, name.c_str(), FL_METHOD_CODEC(codec)); - - fl_method_channel_set_method_call_handler(channel_, HandleMethodCallStatic, this, nullptr); -} - -ChannelDelegate::~ChannelDelegate() { - unregisterMethodCallHandler(); - if (channel_ != nullptr) { - g_object_unref(channel_); - channel_ = nullptr; - } - messenger_ = nullptr; -} - -void ChannelDelegate::HandleMethodCallStatic(FlMethodChannel* channel, FlMethodCall* method_call, - gpointer user_data) { - auto* self = static_cast(user_data); - if (self) { - self->HandleMethodCall(method_call); - } -} - -void ChannelDelegate::HandleMethodCall(FlMethodCall* method_call) { - // Default implementation - subclasses should override - fl_method_call_respond_not_implemented(method_call, nullptr); -} - -void ChannelDelegate::invokeMethod(const std::string& method, FlValue* arguments) const { - if (channel_ == nullptr) { - return; - } - fl_method_channel_invoke_method(channel_, method.c_str(), arguments, nullptr, nullptr, nullptr); -} - -void ChannelDelegate::invokeMethodWithResult(const std::string& method, FlValue* arguments, - GAsyncReadyCallback callback, - gpointer user_data) const { - if (channel_ == nullptr) { - return; - } - fl_method_channel_invoke_method(channel_, method.c_str(), arguments, nullptr, callback, - user_data); -} - -void ChannelDelegate::unregisterMethodCallHandler() { - if (channel_ != nullptr) { - fl_method_channel_set_method_call_handler(channel_, nullptr, nullptr, nullptr); - } -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/channel_delegate.h b/flutter_inappwebview_linux/linux/types/channel_delegate.h deleted file mode 100644 index 94b41e24f8..0000000000 --- a/flutter_inappwebview_linux/linux/types/channel_delegate.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CHANNEL_DELEGATE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_CHANNEL_DELEGATE_H_ - -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * Base class for channel delegates that handle Flutter method channels. - * This mirrors the Windows ChannelDelegate pattern. - */ -class ChannelDelegate { - public: - ChannelDelegate(FlBinaryMessenger* messenger, const std::string& name); - virtual ~ChannelDelegate(); - - /** - * Handle a method call from Flutter. - * Subclasses should override this to handle their specific methods. - */ - virtual void HandleMethodCall(FlMethodCall* method_call); - - /** - * Invoke a method on the Dart side without expecting a result. - */ - void invokeMethod(const std::string& method, FlValue* arguments) const; - - /** - * Invoke a method on the Dart side with a result callback. - */ - void invokeMethodWithResult(const std::string& method, FlValue* arguments, - GAsyncReadyCallback callback, gpointer user_data) const; - - /** - * Unregister the method call handler. - */ - void unregisterMethodCallHandler(); - - FlMethodChannel* channel() const { return channel_; } - FlBinaryMessenger* messenger() const { return messenger_; } - - protected: - FlBinaryMessenger* messenger_ = nullptr; - FlMethodChannel* channel_ = nullptr; - - private: - static void HandleMethodCallStatic(FlMethodChannel* channel, FlMethodCall* method_call, - gpointer user_data); -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_CHANNEL_DELEGATE_H_ diff --git a/flutter_inappwebview_linux/linux/types/client_cert_challenge.cc b/flutter_inappwebview_linux/linux/types/client_cert_challenge.cc deleted file mode 100644 index c38cec1e12..0000000000 --- a/flutter_inappwebview_linux/linux/types/client_cert_challenge.cc +++ /dev/null @@ -1,45 +0,0 @@ -#include "client_cert_challenge.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -ClientCertChallenge::ClientCertChallenge(const URLProtectionSpace& protectionSpace, bool isProxy) - : protectionSpace(protectionSpace), isProxy(isProxy) {} - -FlValue* ClientCertChallenge::toFlValue() const { - // Convert keyTypes to FlValue list - g_autoptr(FlValue) keyTypesValue = fl_value_new_list(); - for (const auto& keyType : keyTypes) { - fl_value_append_take(keyTypesValue, fl_value_new_string(keyType.c_str())); - } - - // Convert principals to FlValue list - g_autoptr(FlValue) principalsValue = fl_value_new_list(); - for (const auto& principal : principals) { - fl_value_append_take(principalsValue, fl_value_new_string(principal.c_str())); - } - - // Convert allowedCertificateAuthorities to FlValue list - g_autoptr(FlValue) allowedCAsValue = fl_value_new_list(); - for (const auto& ca : allowedCertificateAuthorities) { - fl_value_append_take(allowedCAsValue, fl_value_new_string(ca.c_str())); - } - - // Convert mutuallyTrustedCertificates to FlValue list - g_autoptr(FlValue) trustedCertsValue = fl_value_new_list(); - for (const auto& cert : mutuallyTrustedCertificates) { - fl_value_append(trustedCertsValue, cert.toFlValue()); - } - - return to_fl_map({ - {"protectionSpace", protectionSpace.toFlValue()}, - {"isProxy", make_fl_value(isProxy)}, - {"keyTypes", fl_value_ref(keyTypesValue)}, - {"principals", fl_value_ref(principalsValue)}, - {"allowedCertificateAuthorities", fl_value_ref(allowedCAsValue)}, - {"mutuallyTrustedCertificates", fl_value_ref(trustedCertsValue)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/client_cert_challenge.h b/flutter_inappwebview_linux/linux/types/client_cert_challenge.h deleted file mode 100644 index 2043be3cf3..0000000000 --- a/flutter_inappwebview_linux/linux/types/client_cert_challenge.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CLIENT_CERT_CHALLENGE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_CLIENT_CERT_CHALLENGE_H_ - -#include - -#include -#include -#include - -#include "url_protection_space.h" -#include "ssl_certificate.h" - -namespace flutter_inappwebview_plugin { - -/** - * Client certificate challenge - sent when server requests a client certificate. - * - * This is used for mTLS (mutual TLS) authentication scenarios. - * - * NOTE: WPE WebKit's support for providing client certificates programmatically - * is limited. The `webkit_credential_new_for_certificate()` API (since 2.34) - * allows providing a certificate, but this may not be available on all systems. - * When not available, the app can at least be notified of the request. - */ -class ClientCertChallenge { - public: - URLProtectionSpace protectionSpace; - - // Whether this is a proxy authentication request - bool isProxy; - - // Key types accepted by the server (if available) - std::vector keyTypes; - - // Certificate authorities accepted by the server (Base64 DER encoded, if available) - std::vector principals; - - // Allowed certificate authorities (Base64 encoded, for Windows compatibility) - std::vector allowedCertificateAuthorities; - - // Mutually trusted certificates (if available) - std::vector mutuallyTrustedCertificates; - - ClientCertChallenge(const URLProtectionSpace& protectionSpace, bool isProxy); - ~ClientCertChallenge() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_CLIENT_CERT_CHALLENGE_H_ diff --git a/flutter_inappwebview_linux/linux/types/client_cert_response.cc b/flutter_inappwebview_linux/linux/types/client_cert_response.cc deleted file mode 100644 index 0f35225bb1..0000000000 --- a/flutter_inappwebview_linux/linux/types/client_cert_response.cc +++ /dev/null @@ -1,62 +0,0 @@ -#include "client_cert_response.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -ClientCertResponse::ClientCertResponse() - : action(ClientCertResponseAction::CANCEL), selectedCertificate(-1) {} - -ClientCertResponse::ClientCertResponse(FlValue* map) - : action(ClientCertResponseAction::CANCEL), selectedCertificate(-1) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - // Parse action - FlValue* actionValue = fl_value_lookup_string(map, "action"); - if (actionValue != nullptr && fl_value_get_type(actionValue) == FL_VALUE_TYPE_INT) { - int actionInt = static_cast(fl_value_get_int(actionValue)); - switch (actionInt) { - case 0: - action = ClientCertResponseAction::CANCEL; - break; - case 1: - action = ClientCertResponseAction::PROCEED; - break; - case 2: - action = ClientCertResponseAction::IGNORE; - break; - default: - action = ClientCertResponseAction::CANCEL; - break; - } - } - - // Parse certificatePath - certificatePath = get_optional_fl_map_value(map, "certificatePath"); - - // Parse certificatePassword - certificatePassword = get_optional_fl_map_value(map, "certificatePassword"); - - // Parse keyStoreType - keyStoreType = get_optional_fl_map_value(map, "keyStoreType"); - - // Parse selectedCertificate - FlValue* selectedValue = fl_value_lookup_string(map, "selectedCertificate"); - if (selectedValue != nullptr && fl_value_get_type(selectedValue) == FL_VALUE_TYPE_INT) { - selectedCertificate = static_cast(fl_value_get_int(selectedValue)); - } -} - -std::optional ClientCertResponse::fromFlValue(FlValue* value) { - if (value == nullptr || fl_value_get_type(value) == FL_VALUE_TYPE_NULL) { - return std::nullopt; - } - if (fl_value_get_type(value) == FL_VALUE_TYPE_MAP) { - return ClientCertResponse(value); - } - return std::nullopt; -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/client_cert_response.h b/flutter_inappwebview_linux/linux/types/client_cert_response.h deleted file mode 100644 index 34ca8ebd4c..0000000000 --- a/flutter_inappwebview_linux/linux/types/client_cert_response.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CLIENT_CERT_RESPONSE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_CLIENT_CERT_RESPONSE_H_ - -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * Action to take in response to a client certificate request. - */ -enum class ClientCertResponseAction { - CANCEL = 0, // Cancel the request - PROCEED = 1, // Proceed with a certificate - IGNORE = 2, // Ignore the request (for now) -}; - -/** - * Response to a client certificate challenge. - * - * NOTE: WPE WebKit's ability to programmatically provide a client certificate - * is limited. The webkit_credential_new_for_certificate() API requires a - * GTlsCertificate which must be loaded from a file. If the certificate cannot - * be loaded or the API is not available, PROCEED will behave like CANCEL. - */ -class ClientCertResponse { - public: - ClientCertResponseAction action; - - // Path to the certificate file (PEM or PKCS12 format) - std::optional certificatePath; - - // Password for the certificate (if PKCS12) - std::optional certificatePassword; - - // Key store type (e.g., "PKCS12", "PEM") - std::optional keyStoreType; - - // Index of selected certificate (for Windows compatibility, not used on Linux) - int selectedCertificate; - - ClientCertResponse(); - explicit ClientCertResponse(FlValue* map); - ~ClientCertResponse() = default; - - static std::optional fromFlValue(FlValue* value); -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_CLIENT_CERT_RESPONSE_H_ diff --git a/flutter_inappwebview_linux/linux/types/content_world.cc b/flutter_inappwebview_linux/linux/types/content_world.cc deleted file mode 100644 index 524d5a09d9..0000000000 --- a/flutter_inappwebview_linux/linux/types/content_world.cc +++ /dev/null @@ -1,50 +0,0 @@ -#include "content_world.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -// Static member initialization -std::shared_ptr ContentWorld::pageWorld_; -std::shared_ptr ContentWorld::defaultClientWorld_; - -ContentWorld::ContentWorld(const std::string& name) : name(name) {} - -ContentWorld::ContentWorld(FlValue* map) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - name = "page"; - return; - } - - name = get_fl_map_value(map, "name", "page"); -} - -FlValue* ContentWorld::toFlValue() const { - return to_fl_map({ - {"name", make_fl_value(name)}, - }); -} - -bool ContentWorld::operator==(const ContentWorld& other) const { - return name == other.name; -} - -std::shared_ptr ContentWorld::page() { - if (!pageWorld_) { - pageWorld_ = std::make_shared("page"); - } - return pageWorld_; -} - -std::shared_ptr ContentWorld::defaultClient() { - if (!defaultClientWorld_) { - defaultClientWorld_ = std::make_shared("defaultClient"); - } - return defaultClientWorld_; -} - -std::shared_ptr ContentWorld::world(const std::string& name) { - return std::make_shared(name); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/content_world.h b/flutter_inappwebview_linux/linux/types/content_world.h deleted file mode 100644 index 0029101bce..0000000000 --- a/flutter_inappwebview_linux/linux/types/content_world.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CONTENT_WORLD_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_CONTENT_WORLD_H_ - -#include - -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * Represents a content world for JavaScript execution isolation. - * WebKitGTK doesn't have full content world isolation like WKWebView, - * but we can track the concept for API compatibility. - */ -class ContentWorld { - public: - std::string name; - - ContentWorld(const std::string& name); - ContentWorld(FlValue* map); - - FlValue* toFlValue() const; - - bool operator==(const ContentWorld& other) const; - - // Factory methods for well-known content worlds - static std::shared_ptr page(); - static std::shared_ptr defaultClient(); - static std::shared_ptr world(const std::string& name); - - private: - static std::shared_ptr pageWorld_; - static std::shared_ptr defaultClientWorld_; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_CONTENT_WORLD_H_ diff --git a/flutter_inappwebview_linux/linux/types/context_menu.h b/flutter_inappwebview_linux/linux/types/context_menu.h deleted file mode 100644 index c757bfd9bc..0000000000 --- a/flutter_inappwebview_linux/linux/types/context_menu.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CONTEXT_MENU_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_CONTEXT_MENU_H_ - -#include - -#include -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * Context menu settings - matches Dart ContextMenuSettings class. - */ -class ContextMenuSettings { - public: - /// Whether all the default system context menu items should be hidden or not. - bool hideDefaultSystemContextMenuItems = false; - - ContextMenuSettings() = default; - - explicit ContextMenuSettings(FlValue* map) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - FlValue* hideDefault = fl_value_lookup_string(map, "hideDefaultSystemContextMenuItems"); - if (hideDefault != nullptr && fl_value_get_type(hideDefault) == FL_VALUE_TYPE_BOOL) { - hideDefaultSystemContextMenuItems = fl_value_get_bool(hideDefault); - } - } -}; - -/** - * Context menu item - matches Dart ContextMenuItem class. - */ -class ContextMenuItem { - public: - /// Menu item ID - can be a string or int - std::variant id; - - /// Menu item title - std::string title; - - ContextMenuItem() = default; - - explicit ContextMenuItem(FlValue* map) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - // Parse id - can be string or int - FlValue* idValue = fl_value_lookup_string(map, "id"); - if (idValue != nullptr) { - if (fl_value_get_type(idValue) == FL_VALUE_TYPE_STRING) { - id = std::string(fl_value_get_string(idValue)); - } else if (fl_value_get_type(idValue) == FL_VALUE_TYPE_INT) { - id = fl_value_get_int(idValue); - } - } - - // Parse title - FlValue* titleValue = fl_value_lookup_string(map, "title"); - if (titleValue != nullptr && fl_value_get_type(titleValue) == FL_VALUE_TYPE_STRING) { - title = std::string(fl_value_get_string(titleValue)); - } - } - - /// Get the ID as a string for comparison/storage - std::string getIdAsString() const { - if (std::holds_alternative(id)) { - return std::get(id); - } else { - return std::to_string(std::get(id)); - } - } -}; - -/** - * Context menu configuration - matches Dart ContextMenu class. - */ -class ContextMenu { - public: - /// Context menu settings - ContextMenuSettings settings; - - /// List of custom menu items - std::vector menuItems; - - ContextMenu() = default; - - explicit ContextMenu(FlValue* map) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - // Parse settings - FlValue* settingsValue = fl_value_lookup_string(map, "settings"); - if (settingsValue != nullptr && fl_value_get_type(settingsValue) == FL_VALUE_TYPE_MAP) { - settings = ContextMenuSettings(settingsValue); - } - - // Parse menu items - FlValue* menuItemsValue = fl_value_lookup_string(map, "menuItems"); - if (menuItemsValue != nullptr && fl_value_get_type(menuItemsValue) == FL_VALUE_TYPE_LIST) { - size_t length = fl_value_get_length(menuItemsValue); - for (size_t i = 0; i < length; ++i) { - FlValue* item = fl_value_get_list_value(menuItemsValue, i); - if (item != nullptr && fl_value_get_type(item) == FL_VALUE_TYPE_MAP) { - menuItems.emplace_back(item); - } - } - } - } -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_CONTEXT_MENU_H_ diff --git a/flutter_inappwebview_linux/linux/types/context_menu_popup.cc b/flutter_inappwebview_linux/linux/types/context_menu_popup.cc deleted file mode 100644 index 094903743e..0000000000 --- a/flutter_inappwebview_linux/linux/types/context_menu_popup.cc +++ /dev/null @@ -1,490 +0,0 @@ -#include "context_menu_popup.h" - -#include -#include -#include - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -namespace flutter_inappwebview_plugin { - -ContextMenuPopup::ContextMenuPopup(GtkWindow* parent_window) : parent_window_(parent_window) { - // Create a popup window - popup_window_ = gtk_window_new(GTK_WINDOW_POPUP); - gtk_window_set_type_hint(GTK_WINDOW(popup_window_), GDK_WINDOW_TYPE_HINT_POPUP_MENU); - gtk_window_set_skip_taskbar_hint(GTK_WINDOW(popup_window_), TRUE); - gtk_window_set_skip_pager_hint(GTK_WINDOW(popup_window_), TRUE); - gtk_window_set_decorated(GTK_WINDOW(popup_window_), FALSE); - gtk_window_set_resizable(GTK_WINDOW(popup_window_), FALSE); - - if (parent_window_ != nullptr) { - gtk_window_set_transient_for(GTK_WINDOW(popup_window_), parent_window_); - } - - // Enable RGBA for transparency - GdkScreen* screen = gtk_widget_get_screen(popup_window_); - GdkVisual* visual = gdk_screen_get_rgba_visual(screen); - if (visual != nullptr) { - gtk_widget_set_visual(popup_window_, visual); - } - gtk_widget_set_app_paintable(popup_window_, TRUE); - - // Create drawing area - drawing_area_ = gtk_drawing_area_new(); - gtk_container_add(GTK_CONTAINER(popup_window_), drawing_area_); - - // Enable events on drawing area - gtk_widget_add_events(drawing_area_, - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | - GDK_LEAVE_NOTIFY_MASK); - - // Connect signals for drawing area - g_signal_connect(drawing_area_, "draw", G_CALLBACK(OnDraw), this); - g_signal_connect(drawing_area_, "button-press-event", G_CALLBACK(OnButtonPress), this); - g_signal_connect(drawing_area_, "button-release-event", G_CALLBACK(OnButtonRelease), this); - g_signal_connect(drawing_area_, "motion-notify-event", G_CALLBACK(OnMotionNotify), this); - g_signal_connect(drawing_area_, "leave-notify-event", G_CALLBACK(OnLeaveNotify), this); - - // Also connect button-press to popup window for when clicks land on window edge - g_signal_connect(popup_window_, "button-press-event", G_CALLBACK(OnButtonPress), this); - - // Connect signals for popup window - g_signal_connect(popup_window_, "focus-out-event", G_CALLBACK(OnFocusOut), this); - g_signal_connect(popup_window_, "unrealize", G_CALLBACK(OnUnrealize), this); - - gtk_widget_show(drawing_area_); -} - -ContextMenuPopup::~ContextMenuPopup() { - Hide(); // Ensure cleanup - if (popup_window_ != nullptr) { - gtk_widget_destroy(popup_window_); - popup_window_ = nullptr; - } -} - -void ContextMenuPopup::AddItem(const std::string& id, const std::string& title, bool enabled) { - PopupMenuItem item; - item.id = id; - item.title = title; - item.enabled = enabled; - item.is_separator = false; - items_.push_back(std::move(item)); -} - -void ContextMenuPopup::AddSeparator() { - PopupMenuItem item; - item.is_separator = true; - items_.push_back(std::move(item)); -} - -void ContextMenuPopup::Clear() { - items_.clear(); - hovered_index_ = -1; - pressed_index_ = -1; -} - -void ContextMenuPopup::UpdateSize() { - if (items_.empty()) { - width_ = MENU_MIN_WIDTH; - height_ = MENU_VERTICAL_PADDING * 2; - return; - } - - // Calculate width based on text - cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); - cairo_t* cr = cairo_create(surface); - - cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cr, MENU_ITEM_TEXT_SIZE); - - int max_text_width = 0; - int non_separator_count = 0; - for (const auto& item : items_) { - if (!item.is_separator) { - non_separator_count++; - cairo_text_extents_t extents; - cairo_text_extents(cr, item.title.c_str(), &extents); - max_text_width = std::max(max_text_width, static_cast(extents.width)); - } - } - - cairo_destroy(cr); - cairo_surface_destroy(surface); - - width_ = std::max(MENU_MIN_WIDTH, std::min(MENU_MAX_WIDTH, max_text_width + MENU_HORIZONTAL_PADDING * 4)); - - // Calculate height with separator filtering logic - height_ = MENU_VERTICAL_PADDING * 2; - bool last_was_separator = true; // Start true to skip leading separators - - for (size_t i = 0; i < items_.size(); ++i) { - const auto& item = items_[i]; - - if (item.is_separator) { - // Skip separator if: - // 1. Only 1 or fewer non-separator items - // 2. Last item was a separator (consecutive) - // 3. This is at the start - // 4. This is at the end (all remaining items are separators) - if (non_separator_count <= 1 || last_was_separator) { - continue; - } - - // Check if trailing separator - bool is_trailing = true; - for (size_t j = i + 1; j < items_.size(); ++j) { - if (!items_[j].is_separator) { - is_trailing = false; - break; - } - } - if (is_trailing) { - continue; - } - - height_ += MENU_SEPARATOR_HEIGHT; - last_was_separator = true; - } else { - height_ += MENU_ITEM_HEIGHT; - last_was_separator = false; - } - } -} - -void ContextMenuPopup::Show(int x, int y) { - if (items_.empty()) { - return; - } - - UpdateSize(); - - // Get display for monitor geometry - GdkDisplay* display = gdk_display_get_default(); - - // Get screen/monitor geometry for boundary checks - GdkMonitor* monitor = nullptr; - int screen_x = 0, screen_y = 0; - int screen_width = 1920, screen_height = 1080; - - if (display != nullptr) { - monitor = gdk_display_get_monitor_at_point(display, x, y); - if (monitor == nullptr) { - monitor = gdk_display_get_primary_monitor(display); - } - if (monitor == nullptr) { - monitor = gdk_display_get_monitor(display, 0); - } - } - - if (monitor != nullptr) { - GdkRectangle geometry; - gdk_monitor_get_geometry(monitor, &geometry); - screen_x = geometry.x; - screen_y = geometry.y; - screen_width = geometry.x + geometry.width; - screen_height = geometry.y + geometry.height; - } - - // Position menu so its top-left corner is at (x, y), adjusted for screen bounds - // If it would go off the right edge, flip to show on the left of cursor - if (x + width_ > screen_width) { - x = x - width_; - } - // If it would go off the bottom, flip to show above cursor - if (y + height_ > screen_height) { - y = y - height_; - } - // Ensure it stays within screen bounds - if (x < screen_x) { - x = screen_x; - } - if (y < screen_y) { - y = screen_y; - } - - // Store menu position for outside click detection - menu_x_ = x; - menu_y_ = y; - - gtk_widget_set_size_request(drawing_area_, width_, height_); - gtk_window_resize(GTK_WINDOW(popup_window_), width_, height_); - gtk_window_move(GTK_WINDOW(popup_window_), x, y); - gtk_window_set_position(GTK_WINDOW(popup_window_), GTK_WIN_POS_NONE); - gtk_widget_show(popup_window_); - gtk_window_move(GTK_WINDOW(popup_window_), x, y); - - visible_ = true; - - // Connect to parent window as fallback for clicks outside Flutter area - if (parent_window_ != nullptr && parent_button_handler_id_ == 0) { - parent_button_handler_id_ = g_signal_connect( - parent_window_, "button-press-event", G_CALLBACK(OnParentButtonPress), this); - } -} - -void ContextMenuPopup::Hide() { - if (!visible_) { - return; - } - - visible_ = false; - hovered_index_ = -1; - pressed_index_ = -1; - - // Disconnect from parent window - if (parent_window_ != nullptr && parent_button_handler_id_ != 0) { - g_signal_handler_disconnect(parent_window_, parent_button_handler_id_); - parent_button_handler_id_ = 0; - } - - // Hide the popup - gtk_widget_hide(popup_window_); - - if (dismissed_callback_) { - dismissed_callback_(); - } -} - -int ContextMenuPopup::GetItemAtPosition(int x, int y) const { - if (x < 0 || x >= width_) { - return -1; - } - - int current_y = MENU_VERTICAL_PADDING; - for (size_t i = 0; i < items_.size(); ++i) { - int item_height = items_[i].is_separator ? MENU_SEPARATOR_HEIGHT : MENU_ITEM_HEIGHT; - - if (y >= current_y && y < current_y + item_height) { - if (items_[i].is_separator || !items_[i].enabled) { - return -1; // Can't select separators or disabled items - } - return static_cast(i); - } - - current_y += item_height; - } - - return -1; -} - -void ContextMenuPopup::Paint() { - gtk_widget_queue_draw(drawing_area_); -} - -gboolean ContextMenuPopup::OnDraw(GtkWidget* widget, cairo_t* cr, gpointer user_data) { - auto* self = static_cast(user_data); - - // Clear with transparency - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - - // Draw background with rounded corners - double radius = 6.0; - double x = 0, y = 0; - double w = self->width_, h = self->height_; - - cairo_new_path(cr); - cairo_arc(cr, x + w - radius, y + radius, radius, -M_PI / 2, 0); - cairo_arc(cr, x + w - radius, y + h - radius, radius, 0, M_PI / 2); - cairo_arc(cr, x + radius, y + h - radius, radius, M_PI / 2, M_PI); - cairo_arc(cr, x + radius, y + radius, radius, M_PI, 3 * M_PI / 2); - cairo_close_path(cr); - - // Background - cairo_set_source_rgba(cr, 0.98, 0.98, 0.98, 0.98); - cairo_fill_preserve(cr); - - // Border - cairo_set_source_rgba(cr, 0.7, 0.7, 0.7, 1.0); - cairo_set_line_width(cr, 1.0); - cairo_stroke(cr); - - // Draw items - cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cr, MENU_ITEM_TEXT_SIZE); - - // Count non-separator items - int non_separator_count = 0; - for (const auto& item : self->items_) { - if (!item.is_separator) { - non_separator_count++; - } - } - - int current_y = MENU_VERTICAL_PADDING; - bool last_was_separator = true; // Start true to skip leading separators - - for (size_t i = 0; i < self->items_.size(); ++i) { - const auto& item = self->items_[i]; - - if (item.is_separator) { - // Skip separator if: - // 1. Only 1 or fewer non-separator items - // 2. Last drawn item was a separator (consecutive) - // 3. This is at the start (last_was_separator is true initially) - // 4. This is at the end (check if remaining items are all separators) - if (non_separator_count <= 1 || last_was_separator) { - continue; - } - - // Check if this is a trailing separator (all remaining items are separators) - bool is_trailing = true; - for (size_t j = i + 1; j < self->items_.size(); ++j) { - if (!self->items_[j].is_separator) { - is_trailing = false; - break; - } - } - if (is_trailing) { - continue; - } - - // Draw separator line - int sep_y = current_y + MENU_SEPARATOR_HEIGHT / 2; - cairo_set_source_rgba(cr, 0.8, 0.8, 0.8, 1.0); - cairo_set_line_width(cr, 1.0); - cairo_move_to(cr, MENU_HORIZONTAL_PADDING, sep_y); - cairo_line_to(cr, self->width_ - MENU_HORIZONTAL_PADDING, sep_y); - cairo_stroke(cr); - - current_y += MENU_SEPARATOR_HEIGHT; - last_was_separator = true; - } else { - // Draw item background if hovered - if (static_cast(i) == self->hovered_index_ && item.enabled) { - cairo_set_source_rgba(cr, 0.2, 0.5, 0.9, 1.0); - cairo_rectangle(cr, 4, current_y, self->width_ - 8, MENU_ITEM_HEIGHT); - cairo_fill(cr); - } - - // Draw text - if (!item.enabled) { - cairo_set_source_rgba(cr, 0.6, 0.6, 0.6, 1.0); - } else if (static_cast(i) == self->hovered_index_) { - cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); - } else { - cairo_set_source_rgba(cr, 0.1, 0.1, 0.1, 1.0); - } - - cairo_move_to(cr, MENU_HORIZONTAL_PADDING, current_y + MENU_ITEM_HEIGHT - 10); - cairo_show_text(cr, item.title.c_str()); - - current_y += MENU_ITEM_HEIGHT; - last_was_separator = false; - } - } - - return TRUE; -} - -gboolean ContextMenuPopup::OnButtonPress(GtkWidget* widget, GdkEventButton* event, - gpointer user_data) { - auto* self = static_cast(user_data); - - // Get screen coordinates of the click - gint screen_x = static_cast(event->x_root); - gint screen_y = static_cast(event->y_root); - - // Check if click is outside the menu bounds - bool outside = (screen_x < self->menu_x_ || screen_x >= self->menu_x_ + self->width_ || - screen_y < self->menu_y_ || screen_y >= self->menu_y_ + self->height_); - - if (outside) { - // Click was outside the menu - dismiss it - self->Hide(); - return FALSE; // Let the event propagate - } - - if (event->button == 1) { - int index = self->GetItemAtPosition(static_cast(event->x), static_cast(event->y)); - self->pressed_index_ = index; - } else if (event->button == 3) { - // Right click outside menu item dismisses - self->Hide(); - return TRUE; - } - - return TRUE; -} - -gboolean ContextMenuPopup::OnButtonRelease(GtkWidget* widget, GdkEventButton* event, - gpointer user_data) { - auto* self = static_cast(user_data); - - if (event->button == 1) { - int index = self->GetItemAtPosition(static_cast(event->x), static_cast(event->y)); - - if (index >= 0 && index == self->pressed_index_ && index < static_cast(self->items_.size())) { - const auto& item = self->items_[index]; - if (item.enabled && !item.is_separator) { - std::string id = item.id; - std::string title = item.title; - - self->Hide(); - - if (self->item_callback_) { - self->item_callback_(id, title); - } - } - } - } else if (event->button == 3) { - // Right click dismisses menu - self->Hide(); - } - - self->pressed_index_ = -1; - return TRUE; -} - -gboolean ContextMenuPopup::OnMotionNotify(GtkWidget* widget, GdkEventMotion* event, - gpointer user_data) { - auto* self = static_cast(user_data); - - int index = self->GetItemAtPosition(static_cast(event->x), static_cast(event->y)); - - if (index != self->hovered_index_) { - self->hovered_index_ = index; - self->Paint(); - } - - return TRUE; -} - -gboolean ContextMenuPopup::OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event, - gpointer user_data) { - auto* self = static_cast(user_data); - - if (self->hovered_index_ >= 0) { - self->hovered_index_ = -1; - self->Paint(); - } - - return TRUE; -} - -gboolean ContextMenuPopup::OnParentButtonPress(GtkWidget* widget, GdkEventButton* event, - gpointer user_data) { - auto* self = static_cast(user_data); - // Any click on parent window while popup is visible should hide the popup - if (self->visible_) { - self->Hide(); - } - return FALSE; // Let the event continue to Flutter -} - -gboolean ContextMenuPopup::OnFocusOut(GtkWidget* widget, GdkEventFocus* event, gpointer user_data) { - auto* self = static_cast(user_data); - if (self->visible_) { - self->Hide(); - } - return FALSE; -} - -void ContextMenuPopup::OnUnrealize(GtkWidget* widget, gpointer user_data) { - auto* self = static_cast(user_data); - self->visible_ = false; -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/context_menu_popup.h b/flutter_inappwebview_linux/linux/types/context_menu_popup.h deleted file mode 100644 index 99d8f454cf..0000000000 --- a/flutter_inappwebview_linux/linux/types/context_menu_popup.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CONTEXT_MENU_POPUP_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_CONTEXT_MENU_POPUP_H_ - -#include -#include - -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -// Constants for menu rendering -constexpr int MENU_VERTICAL_PADDING = 8; -constexpr int MENU_HORIZONTAL_PADDING = 12; -constexpr int MENU_ITEM_HEIGHT = 32; -constexpr int MENU_ITEM_TEXT_SIZE = 14; -constexpr int MENU_SEPARATOR_HEIGHT = 9; -constexpr int MENU_MIN_WIDTH = 150; -constexpr int MENU_MAX_WIDTH = 400; - -struct PopupMenuItem { - std::string id; - std::string title; - bool enabled = true; - bool is_separator = false; -}; - -// Callback when a menu item is clicked -using MenuItemCallback = std::function; -// Callback when the menu is dismissed -using MenuDismissedCallback = std::function; - -class ContextMenuPopup { - public: - ContextMenuPopup(GtkWindow* parent_window); - ~ContextMenuPopup(); - - // Add a menu item - void AddItem(const std::string& id, const std::string& title, bool enabled = true); - - // Add a separator - void AddSeparator(); - - // Clear all items - void Clear(); - - // Show the popup at the given screen coordinates - void Show(int x, int y); - - // Hide the popup - void Hide(); - - // Check if the popup is visible - bool IsVisible() const { return visible_; } - - // Set callbacks - void SetItemCallback(MenuItemCallback callback) { item_callback_ = std::move(callback); } - void SetDismissedCallback(MenuDismissedCallback callback) { - dismissed_callback_ = std::move(callback); - } - - private: - // Cairo drawing - void Paint(); - void UpdateSize(); - int GetItemAtPosition(int x, int y) const; - - // GTK signal handlers - static gboolean OnDraw(GtkWidget* widget, cairo_t* cr, gpointer user_data); - static gboolean OnButtonPress(GtkWidget* widget, GdkEventButton* event, gpointer user_data); - static gboolean OnButtonRelease(GtkWidget* widget, GdkEventButton* event, gpointer user_data); - static gboolean OnMotionNotify(GtkWidget* widget, GdkEventMotion* event, gpointer user_data); - static gboolean OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event, gpointer user_data); - static gboolean OnParentButtonPress(GtkWidget* widget, GdkEventButton* event, gpointer user_data); - static gboolean OnFocusOut(GtkWidget* widget, GdkEventFocus* event, gpointer user_data); - static void OnUnrealize(GtkWidget* widget, gpointer user_data); - - GtkWindow* parent_window_ = nullptr; - GtkWidget* popup_window_ = nullptr; - GtkWidget* drawing_area_ = nullptr; - - std::vector items_; - int width_ = 0; - int height_ = 0; - int menu_x_ = 0; // Screen X position of menu - int menu_y_ = 0; // Screen Y position of menu - int hovered_index_ = -1; - int pressed_index_ = -1; - bool visible_ = false; - gulong parent_button_handler_id_ = 0; - - MenuItemCallback item_callback_; - MenuDismissedCallback dismissed_callback_; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_CONTEXT_MENU_POPUP_H_ diff --git a/flutter_inappwebview_linux/linux/types/create_window_action.cc b/flutter_inappwebview_linux/linux/types/create_window_action.cc deleted file mode 100644 index 17844f0562..0000000000 --- a/flutter_inappwebview_linux/linux/types/create_window_action.cc +++ /dev/null @@ -1,87 +0,0 @@ -#include "create_window_action.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -WindowFeatures::WindowFeatures(WebKitWindowProperties* properties) { - if (properties == nullptr) { - return; - } - - // WPE WebKit doesn't have window geometry API - use defaults - // WPE is headless so window properties aren't meaningful - menuBarVisible = false; - statusBarVisible = false; - toolbarsVisible = false; - scrollbarsVisible = true; - locationbarVisible = false; - fullscreen = false; - resizable = true; -} - -FlValue* WindowFeatures::toFlValue() const { - return to_fl_map({ - {"menuBarVisible", make_fl_value(menuBarVisible)}, - {"statusBarVisible", make_fl_value(statusBarVisible)}, - {"toolbarsVisible", make_fl_value(toolbarsVisible)}, - {"scrollbarsVisible", make_fl_value(scrollbarsVisible)}, - {"locationbarVisible", make_fl_value(locationbarVisible)}, - {"fullscreen", make_fl_value(fullscreen)}, - {"resizable", make_fl_value(resizable)}, - {"x", make_fl_value(x)}, - {"y", make_fl_value(y)}, - {"width", make_fl_value(width)}, - {"height", make_fl_value(height)}, - }); -} - -CreateWindowAction::CreateWindowAction(WebKitNavigationAction* navigationAction, int64_t windowId, - WebKitWindowProperties* windowProperties) - : windowId(windowId), isUserGesture(false), isForMainFrame(true) { - if (navigationAction != nullptr) { - WebKitURIRequest* uriRequest = webkit_navigation_action_get_request(navigationAction); - if (uriRequest != nullptr) { - const gchar* uri = webkit_uri_request_get_uri(uriRequest); - const gchar* method = webkit_uri_request_get_http_method(uriRequest); - - request = std::make_shared( - uri != nullptr ? std::make_optional(std::string(uri)) : std::nullopt, - method != nullptr ? std::make_optional(std::string(method)) - : std::make_optional(std::string("GET")), - std::nullopt, // headers - std::nullopt // body - ); - } - - navigationType = - static_cast(webkit_navigation_action_get_navigation_type(navigationAction)); - isUserGesture = webkit_navigation_action_is_user_gesture(navigationAction); - - // Get target frame name - const gchar* frameName = webkit_navigation_action_get_frame_name(navigationAction); - if (frameName != nullptr) { - targetFrame = std::string(frameName); - } - } - - if (windowProperties != nullptr) { - windowFeatures = WindowFeatures(windowProperties); - } -} - -FlValue* CreateWindowAction::toFlValue() const { - return to_fl_map({ - {"windowId", make_fl_value(windowId)}, - {"isDialog", make_fl_value(isDialog)}, - {"request", request ? request->toFlValue() : make_fl_value()}, - {"navigationType", make_fl_value(navigationType)}, - {"isForMainFrame", make_fl_value(isForMainFrame)}, - {"hasGesture", make_fl_value(isUserGesture)}, - {"targetFrame", make_fl_value(targetFrame)}, - {"sourceUrl", make_fl_value(sourceUrl)}, - {"windowFeatures", windowFeatures.has_value() ? windowFeatures->toFlValue() : make_fl_value()}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/create_window_action.h b/flutter_inappwebview_linux/linux/types/create_window_action.h deleted file mode 100644 index 2d756b4502..0000000000 --- a/flutter_inappwebview_linux/linux/types/create_window_action.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CREATE_WINDOW_ACTION_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_CREATE_WINDOW_ACTION_H_ - -#include -#include - -#include -#include -#include -#include - -#include "url_request.h" - -namespace flutter_inappwebview_plugin { - -/** - * Represents window features from WebKitWindowProperties. - */ -class WindowFeatures { - public: - std::optional menuBarVisible; - std::optional statusBarVisible; - std::optional toolbarsVisible; - std::optional scrollbarsVisible; - std::optional locationbarVisible; - std::optional fullscreen; - std::optional resizable; - std::optional x; - std::optional y; - std::optional width; - std::optional height; - - WindowFeatures() = default; - WindowFeatures(WebKitWindowProperties* properties); - ~WindowFeatures() = default; - - FlValue* toFlValue() const; -}; - -/** - * Represents an action to create a new window (e.g., from window.open() or target="_blank"). - */ -class CreateWindowAction { - public: - // The window id assigned to the new window - int64_t windowId; - - // Whether this is a dialog window - std::optional isDialog; - - // The navigation action that triggered this - std::shared_ptr request; - - // Navigation type (same as NavigationAction) - int64_t navigationType; - - // Whether the navigation was triggered by a user gesture - bool isUserGesture; - - // Whether it's for the main frame - bool isForMainFrame; - - // Target frame name (e.g., "_blank") - std::optional targetFrame; - - // Source URL (the URL of the page that initiated the request) - std::optional sourceUrl; - - // Window features - std::optional windowFeatures; - - CreateWindowAction(WebKitNavigationAction* navigationAction, int64_t windowId, - WebKitWindowProperties* windowProperties = nullptr); - ~CreateWindowAction() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_CREATE_WINDOW_ACTION_H_ diff --git a/flutter_inappwebview_linux/linux/types/custom_scheme_response.cc b/flutter_inappwebview_linux/linux/types/custom_scheme_response.cc deleted file mode 100644 index fdfcbed297..0000000000 --- a/flutter_inappwebview_linux/linux/types/custom_scheme_response.cc +++ /dev/null @@ -1,28 +0,0 @@ -#include "custom_scheme_response.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -CustomSchemeResponse::CustomSchemeResponse() - : contentType("application/octet-stream"), contentEncoding("utf-8") {} - -CustomSchemeResponse::CustomSchemeResponse(FlValue* map) - : contentType(get_fl_map_value(map, "contentType", "application/octet-stream")), - contentEncoding(get_fl_map_value(map, "contentEncoding", "utf-8")) { - // Parse data (Uint8List) - needs special handling for byte arrays - auto data_opt = get_optional_fl_map_value>(map, "data"); - if (data_opt.has_value()) { - data = data_opt.value(); - } -} - -FlValue* CustomSchemeResponse::toFlValue() const { - return to_fl_map({ - {"data", make_fl_value(data)}, - {"contentType", make_fl_value(contentType)}, - {"contentEncoding", make_fl_value(contentEncoding)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/custom_scheme_response.h b/flutter_inappwebview_linux/linux/types/custom_scheme_response.h deleted file mode 100644 index ea8bfb0be7..0000000000 --- a/flutter_inappwebview_linux/linux/types/custom_scheme_response.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CUSTOM_SCHEME_RESPONSE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_CUSTOM_SCHEME_RESPONSE_H_ - -#include - -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * CustomSchemeResponse - Response for custom URI scheme requests. - * - * This class represents the response returned by the onLoadResourceWithCustomScheme - * event. It allows loading a specific resource with custom scheme. - */ -class CustomSchemeResponse { - public: - // Data to be returned for the custom scheme request - std::vector data; - - // Content-Type of the data, such as "image/png" - std::string contentType; - - // Content-Encoding of the data, such as "utf-8" - std::string contentEncoding; - - CustomSchemeResponse(); - explicit CustomSchemeResponse(FlValue* map); - ~CustomSchemeResponse() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_CUSTOM_SCHEME_RESPONSE_H_ diff --git a/flutter_inappwebview_linux/linux/types/download_start_request.cc b/flutter_inappwebview_linux/linux/types/download_start_request.cc deleted file mode 100644 index e9af4b72e9..0000000000 --- a/flutter_inappwebview_linux/linux/types/download_start_request.cc +++ /dev/null @@ -1,68 +0,0 @@ -#include "download_start_request.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -// === DownloadStartRequest === - -DownloadStartRequest::DownloadStartRequest() : contentLength(-1) {} - -DownloadStartRequest::DownloadStartRequest(WebKitDownload* download) : contentLength(-1) { - if (download == nullptr) { - return; - } - - WebKitURIRequest* request = webkit_download_get_request(download); - if (request != nullptr) { - const gchar* uri = webkit_uri_request_get_uri(request); - if (uri != nullptr) { - url = std::string(uri); - } - } - - WebKitURIResponse* response = webkit_download_get_response(download); - if (response != nullptr) { - const gchar* mimeTypeStr = webkit_uri_response_get_mime_type(response); - if (mimeTypeStr != nullptr) { - mimeType = std::string(mimeTypeStr); - } - - contentLength = webkit_uri_response_get_content_length(response); - - // Try to get suggested filename from response headers - const gchar* suggestedName = webkit_uri_response_get_suggested_filename(response); - if (suggestedName != nullptr) { - suggestedFilename = std::string(suggestedName); - } - } - - // If no suggested filename from response, get it from download - if (!suggestedFilename.has_value()) { - // WebKitGTK automatically determines a filename - const gchar* dest = webkit_download_get_destination(download); - if (dest != nullptr) { - // Extract filename from path - std::string destStr(dest); - size_t lastSlash = destStr.rfind('/'); - if (lastSlash != std::string::npos) { - suggestedFilename = destStr.substr(lastSlash + 1); - } else { - suggestedFilename = destStr; - } - } - } -} - -FlValue* DownloadStartRequest::toFlValue() const { - return to_fl_map({ - {"url", make_fl_value(url)}, - {"suggestedFilename", make_fl_value(suggestedFilename)}, - {"mimeType", make_fl_value(mimeType)}, - {"contentLength", make_fl_value(contentLength)}, - {"contentDisposition", make_fl_value(contentDisposition)}, - {"userAgent", make_fl_value(userAgent)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/download_start_request.h b/flutter_inappwebview_linux/linux/types/download_start_request.h deleted file mode 100644 index e307e15137..0000000000 --- a/flutter_inappwebview_linux/linux/types/download_start_request.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_DOWNLOAD_START_REQUEST_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_DOWNLOAD_START_REQUEST_H_ - -#include -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -class DownloadStartRequest { - public: - std::optional url; - std::optional suggestedFilename; - std::optional mimeType; - int64_t contentLength; - std::optional contentDisposition; - std::optional userAgent; - - DownloadStartRequest(); - DownloadStartRequest(WebKitDownload* download); - ~DownloadStartRequest() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_DOWNLOAD_START_REQUEST_H_ diff --git a/flutter_inappwebview_linux/linux/types/download_start_response.cc b/flutter_inappwebview_linux/linux/types/download_start_response.cc deleted file mode 100644 index 3df130c5bd..0000000000 --- a/flutter_inappwebview_linux/linux/types/download_start_response.cc +++ /dev/null @@ -1,23 +0,0 @@ -#include "download_start_response.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -// === DownloadStartResponse === - -DownloadStartResponse::DownloadStartResponse() : action(DownloadStartResponseAction::CANCEL) {} - -DownloadStartResponse::DownloadStartResponse(FlValue* map) - : action(DownloadStartResponseAction::CANCEL) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - int64_t actionInt = get_fl_map_value(map, "action", 0); - action = static_cast(actionInt); - - destinationPath = get_optional_fl_map_value(map, "destinationPath"); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/download_start_response.h b/flutter_inappwebview_linux/linux/types/download_start_response.h deleted file mode 100644 index 61c37f1910..0000000000 --- a/flutter_inappwebview_linux/linux/types/download_start_response.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_DOWNLOAD_START_RESPONSE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_DOWNLOAD_START_RESPONSE_H_ - -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -enum class DownloadStartResponseAction { CANCEL = 0, ALLOW = 1 }; - -class DownloadStartResponse { - public: - DownloadStartResponseAction action; - std::optional destinationPath; - - DownloadStartResponse(); - DownloadStartResponse(FlValue* map); - ~DownloadStartResponse() = default; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_DOWNLOAD_START_RESPONSE_H_ diff --git a/flutter_inappwebview_linux/linux/types/find_session.cc b/flutter_inappwebview_linux/linux/types/find_session.cc deleted file mode 100644 index 0ca30445e6..0000000000 --- a/flutter_inappwebview_linux/linux/types/find_session.cc +++ /dev/null @@ -1,21 +0,0 @@ -#include "find_session.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -FindSession::FindSession(int resultCount, int highlightedResultIndex) - : resultCount(resultCount), highlightedResultIndex(highlightedResultIndex) {} - -FindSession::FindSession(FlValue* value) - : resultCount(get_fl_map_value(value, "resultCount", 0)), - highlightedResultIndex(get_fl_map_value(value, "highlightedResultIndex", 0)) {} - -FlValue* FindSession::toFlValue() const { - return to_fl_map({ - {"resultCount", make_fl_value(resultCount)}, - {"highlightedResultIndex", make_fl_value(highlightedResultIndex)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/find_session.h b/flutter_inappwebview_linux/linux/types/find_session.h deleted file mode 100644 index 41f97078db..0000000000 --- a/flutter_inappwebview_linux/linux/types/find_session.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_FIND_SESSION_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_FIND_SESSION_H_ - -#include -#include - -namespace flutter_inappwebview_plugin { - -class FindSession { - public: - int resultCount; - int highlightedResultIndex; - - FindSession(int resultCount, int highlightedResultIndex); - explicit FindSession(FlValue* value); - ~FindSession() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_FIND_SESSION_H_ diff --git a/flutter_inappwebview_linux/linux/types/hit_test_result.cc b/flutter_inappwebview_linux/linux/types/hit_test_result.cc deleted file mode 100644 index e18936118c..0000000000 --- a/flutter_inappwebview_linux/linux/types/hit_test_result.cc +++ /dev/null @@ -1,55 +0,0 @@ -#include "hit_test_result.h" - -#include - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -HitTestResult HitTestResult::fromWebKitHitTestResult(void* hit_test_result_ptr) { - if (hit_test_result_ptr == nullptr) { - return HitTestResult(HitTestResultType::UNKNOWN_TYPE); - } - - auto* hit_test_result = static_cast(hit_test_result_ptr); - - // Determine the type based on WebKit hit test result context - // Priority matters: link+image = SRC_IMAGE_ANCHOR_TYPE, otherwise check each type - if (webkit_hit_test_result_context_is_link(hit_test_result) && - webkit_hit_test_result_context_is_image(hit_test_result)) { - // Image that is also a link - const char* uri = webkit_hit_test_result_get_link_uri(hit_test_result); - return HitTestResult(HitTestResultType::SRC_IMAGE_ANCHOR_TYPE, - uri ? std::optional(uri) : std::nullopt); - } else if (webkit_hit_test_result_context_is_link(hit_test_result)) { - const char* uri = webkit_hit_test_result_get_link_uri(hit_test_result); - return HitTestResult(HitTestResultType::SRC_ANCHOR_TYPE, - uri ? std::optional(uri) : std::nullopt); - } else if (webkit_hit_test_result_context_is_image(hit_test_result)) { - const char* uri = webkit_hit_test_result_get_image_uri(hit_test_result); - return HitTestResult(HitTestResultType::IMAGE_TYPE, - uri ? std::optional(uri) : std::nullopt); - } else if (webkit_hit_test_result_context_is_media(hit_test_result)) { - // Media elements (video/audio) - use IMAGE_TYPE as there's no specific media type - const char* uri = webkit_hit_test_result_get_media_uri(hit_test_result); - return HitTestResult(HitTestResultType::IMAGE_TYPE, - uri ? std::optional(uri) : std::nullopt); - } else if (webkit_hit_test_result_context_is_editable(hit_test_result)) { - return HitTestResult(HitTestResultType::EDIT_TEXT_TYPE); - } - - // Default: unknown type - return HitTestResult(HitTestResultType::UNKNOWN_TYPE); -} - -FlValue* HitTestResult::toFlValue() const { - // Convert type enum to the integer value expected by Dart - int64_t type_value = static_cast(type_); - - return to_fl_map({ - {"type", make_fl_value(type_value)}, - {"extra", make_fl_value(extra_)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/hit_test_result.h b/flutter_inappwebview_linux/linux/types/hit_test_result.h deleted file mode 100644 index 2b7d6ecf40..0000000000 --- a/flutter_inappwebview_linux/linux/types/hit_test_result.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_HIT_TEST_RESULT_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_HIT_TEST_RESULT_H_ - -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -/// Hit test result types matching InAppWebViewHitTestResultType in Dart -enum class HitTestResultType { - UNKNOWN_TYPE = 0, - PHONE_TYPE = 2, - GEO_TYPE = 3, - EMAIL_TYPE = 4, - IMAGE_TYPE = 5, - SRC_ANCHOR_TYPE = 7, - SRC_IMAGE_ANCHOR_TYPE = 8, - EDIT_TEXT_TYPE = 9 -}; - -/// HitTestResult - represents the result of a hit test on the WebView -/// -/// This maps to InAppWebViewHitTestResult in Dart. -/// It contains the type of element hit and optional extra information (like a URL). -class HitTestResult { - public: - /// Default constructor - creates an unknown type hit test result - HitTestResult() : type_(HitTestResultType::UNKNOWN_TYPE) {} - - /// Constructor with type and optional extra data - HitTestResult(HitTestResultType type, const std::optional& extra = std::nullopt) - : type_(type), extra_(extra) {} - - /// Construct from a WebKitHitTestResult pointer - /// This extracts the relevant information from the WPE WebKit hit test result - static HitTestResult fromWebKitHitTestResult(void* hit_test_result); - - /// Convert to FlValue map for Dart serialization - FlValue* toFlValue() const; - - // Getters - HitTestResultType type() const { return type_; } - const std::optional& extra() const { return extra_; } - - private: - HitTestResultType type_; - std::optional extra_; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_HIT_TEST_RESULT_H_ diff --git a/flutter_inappwebview_linux/linux/types/http_auth_response.cc b/flutter_inappwebview_linux/linux/types/http_auth_response.cc deleted file mode 100644 index a821fae9dc..0000000000 --- a/flutter_inappwebview_linux/linux/types/http_auth_response.cc +++ /dev/null @@ -1,25 +0,0 @@ -#include "http_auth_response.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -HttpAuthResponse::HttpAuthResponse() - : action(HttpAuthResponseAction::CANCEL), permanentPersistence(false) {} - -HttpAuthResponse::HttpAuthResponse(FlValue* map) - : action(HttpAuthResponseAction::CANCEL), permanentPersistence(false) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - username = get_optional_fl_map_value(map, "username"); - password = get_optional_fl_map_value(map, "password"); - - int64_t actionInt = get_fl_map_value(map, "action", 0); - action = static_cast(actionInt); - - permanentPersistence = get_fl_map_value(map, "permanentPersistence", false); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/http_auth_response.h b/flutter_inappwebview_linux/linux/types/http_auth_response.h deleted file mode 100644 index b1eb6d5466..0000000000 --- a/flutter_inappwebview_linux/linux/types/http_auth_response.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_HTTP_AUTH_RESPONSE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_HTTP_AUTH_RESPONSE_H_ - -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * HTTP authentication response action. - */ -enum class HttpAuthResponseAction { CANCEL = 0, PROCEED = 1, USE_SAVED_CREDENTIAL = 2 }; - -/** - * Response to an HTTP authentication challenge. - */ -class HttpAuthResponse { - public: - std::optional username; - std::optional password; - HttpAuthResponseAction action; - bool permanentPersistence; - - HttpAuthResponse(); - HttpAuthResponse(FlValue* map); - ~HttpAuthResponse() = default; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_HTTP_AUTH_RESPONSE_H_ diff --git a/flutter_inappwebview_linux/linux/types/http_authentication_challenge.cc b/flutter_inappwebview_linux/linux/types/http_authentication_challenge.cc deleted file mode 100644 index 85793c0c24..0000000000 --- a/flutter_inappwebview_linux/linux/types/http_authentication_challenge.cc +++ /dev/null @@ -1,21 +0,0 @@ -#include "http_authentication_challenge.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -HttpAuthenticationChallenge::HttpAuthenticationChallenge(const URLProtectionSpace& protectionSpace, - bool isRetry) - : protectionSpace(protectionSpace), isRetry(isRetry) {} - -FlValue* HttpAuthenticationChallenge::toFlValue() const { - return to_fl_map({ - {"protectionSpace", protectionSpace.toFlValue()}, - {"previousFailureCount", make_fl_value(previousFailureCount)}, - {"proposedCredential", make_fl_value()}, - {"failureResponse", make_fl_value()}, - {"error", make_fl_value()}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/http_authentication_challenge.h b/flutter_inappwebview_linux/linux/types/http_authentication_challenge.h deleted file mode 100644 index b0e57eb53a..0000000000 --- a/flutter_inappwebview_linux/linux/types/http_authentication_challenge.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_HTTP_AUTHENTICATION_CHALLENGE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_HTTP_AUTHENTICATION_CHALLENGE_H_ - -#include - -#include -#include - -#include "url_protection_space.h" - -namespace flutter_inappwebview_plugin { - -/** - * HTTP authentication challenge - sent when server requires authentication. - */ -class HttpAuthenticationChallenge { - public: - URLProtectionSpace protectionSpace; - std::optional previousFailureCount; // Number of retry attempts - bool isRetry; - - HttpAuthenticationChallenge(const URLProtectionSpace& protectionSpace, bool isRetry); - ~HttpAuthenticationChallenge() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_HTTP_AUTHENTICATION_CHALLENGE_H_ diff --git a/flutter_inappwebview_linux/linux/types/javascript_handler_function_data.cc b/flutter_inappwebview_linux/linux/types/javascript_handler_function_data.cc deleted file mode 100644 index 20b0bf0fa8..0000000000 --- a/flutter_inappwebview_linux/linux/types/javascript_handler_function_data.cc +++ /dev/null @@ -1,28 +0,0 @@ -#include "javascript_handler_function_data.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -JavaScriptHandlerFunctionData::JavaScriptHandlerFunctionData(const std::string& origin, - const std::string& requestUrl, - bool isMainFrame, - const std::string& args) - : origin(origin), requestUrl(requestUrl), isMainFrame(isMainFrame), args(args) {} - -JavaScriptHandlerFunctionData::JavaScriptHandlerFunctionData(FlValue* map) - : origin(get_fl_map_value(map, "origin", "")), - requestUrl(get_fl_map_value(map, "requestUrl", "")), - isMainFrame(get_fl_map_value(map, "isMainFrame", false)), - args(get_fl_map_value(map, "args", "")) {} - -FlValue* JavaScriptHandlerFunctionData::toFlValue() const { - return to_fl_map({ - {"origin", make_fl_value(origin)}, - {"requestUrl", make_fl_value(requestUrl)}, - {"isMainFrame", make_fl_value(isMainFrame)}, - {"args", make_fl_value(args)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/javascript_handler_function_data.h b/flutter_inappwebview_linux/linux/types/javascript_handler_function_data.h deleted file mode 100644 index 92cfa320e7..0000000000 --- a/flutter_inappwebview_linux/linux/types/javascript_handler_function_data.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_HANDLER_FUNCTION_DATA_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_HANDLER_FUNCTION_DATA_H_ - -#include - -#include - -namespace flutter_inappwebview_plugin { - -class JavaScriptHandlerFunctionData { - public: - const std::string origin; - const std::string requestUrl; - const bool isMainFrame; - const std::string args; - - JavaScriptHandlerFunctionData(const std::string& origin, const std::string& requestUrl, - bool isMainFrame, const std::string& args); - JavaScriptHandlerFunctionData(FlValue* map); - ~JavaScriptHandlerFunctionData() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_HANDLER_FUNCTION_DATA_H_ diff --git a/flutter_inappwebview_linux/linux/types/js_alert_request.cc b/flutter_inappwebview_linux/linux/types/js_alert_request.cc deleted file mode 100644 index 2bb0d44de4..0000000000 --- a/flutter_inappwebview_linux/linux/types/js_alert_request.cc +++ /dev/null @@ -1,19 +0,0 @@ -#include "js_alert_request.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -JsAlertRequest::JsAlertRequest(const std::optional& url, const std::string& message, - bool isMainFrame) - : url(url), message(message), isMainFrame(isMainFrame) {} - -FlValue* JsAlertRequest::toFlValue() const { - return to_fl_map({ - {"url", make_fl_value(url)}, - {"message", make_fl_value(message)}, - {"isMainFrame", make_fl_value(isMainFrame)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/js_alert_request.h b/flutter_inappwebview_linux/linux/types/js_alert_request.h deleted file mode 100644 index 638df65083..0000000000 --- a/flutter_inappwebview_linux/linux/types/js_alert_request.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_JS_ALERT_REQUEST_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_JS_ALERT_REQUEST_H_ - -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * Represents a JavaScript alert() dialog request. - */ -class JsAlertRequest { - public: - std::optional url; - std::string message; - bool isMainFrame; - - JsAlertRequest(const std::optional& url, const std::string& message, - bool isMainFrame); - ~JsAlertRequest() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_JS_ALERT_REQUEST_H_ diff --git a/flutter_inappwebview_linux/linux/types/js_alert_response.cc b/flutter_inappwebview_linux/linux/types/js_alert_response.cc deleted file mode 100644 index ce04a57987..0000000000 --- a/flutter_inappwebview_linux/linux/types/js_alert_response.cc +++ /dev/null @@ -1,22 +0,0 @@ -#include "js_alert_response.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -JsAlertResponse::JsAlertResponse() - : handledByClient(false), action(JsAlertResponseAction::CONFIRM) {} - -JsAlertResponse::JsAlertResponse(FlValue* map) - : handledByClient(false), action(JsAlertResponseAction::CONFIRM) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - handledByClient = get_fl_map_value(map, "handledByClient", handledByClient); - int64_t actionInt = get_fl_map_value(map, "action", 0); - action = static_cast(actionInt); - message = get_optional_fl_map_value(map, "message"); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/js_alert_response.h b/flutter_inappwebview_linux/linux/types/js_alert_response.h deleted file mode 100644 index 0a7547cd29..0000000000 --- a/flutter_inappwebview_linux/linux/types/js_alert_response.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_JS_ALERT_RESPONSE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_JS_ALERT_RESPONSE_H_ - -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * Response action for JS alert dialogs. - */ -enum class JsAlertResponseAction { CONFIRM = 0 }; - -/** - * Response to a JavaScript alert() dialog. - */ -class JsAlertResponse { - public: - bool handledByClient; - JsAlertResponseAction action; - std::optional message; - - JsAlertResponse(); - JsAlertResponse(FlValue* map); - ~JsAlertResponse() = default; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_JS_ALERT_RESPONSE_H_ diff --git a/flutter_inappwebview_linux/linux/types/js_before_unload_response.cc b/flutter_inappwebview_linux/linux/types/js_before_unload_response.cc deleted file mode 100644 index 1f026628a7..0000000000 --- a/flutter_inappwebview_linux/linux/types/js_before_unload_response.cc +++ /dev/null @@ -1,23 +0,0 @@ -#include "js_before_unload_response.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -JsBeforeUnloadResponse::JsBeforeUnloadResponse() - : handledByClient(false), shouldAllowNavigation(true) {} - -JsBeforeUnloadResponse::JsBeforeUnloadResponse(FlValue* map) - : handledByClient(false), shouldAllowNavigation(true) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - handledByClient = get_fl_map_value(map, "handledByClient", handledByClient); - // Action 1 = allow navigation - int64_t actionInt = get_fl_map_value(map, "action", 1); - shouldAllowNavigation = (actionInt == 1); - message = get_optional_fl_map_value(map, "message"); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/js_before_unload_response.h b/flutter_inappwebview_linux/linux/types/js_before_unload_response.h deleted file mode 100644 index 90e375ca0e..0000000000 --- a/flutter_inappwebview_linux/linux/types/js_before_unload_response.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_JS_BEFORE_UNLOAD_RESPONSE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_JS_BEFORE_UNLOAD_RESPONSE_H_ - -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * Response for beforeunload dialogs. - */ -class JsBeforeUnloadResponse { - public: - bool handledByClient; - bool shouldAllowNavigation; - std::optional message; - - JsBeforeUnloadResponse(); - JsBeforeUnloadResponse(FlValue* map); - ~JsBeforeUnloadResponse() = default; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_JS_BEFORE_UNLOAD_RESPONSE_H_ diff --git a/flutter_inappwebview_linux/linux/types/js_confirm_request.cc b/flutter_inappwebview_linux/linux/types/js_confirm_request.cc deleted file mode 100644 index d1565b0b5e..0000000000 --- a/flutter_inappwebview_linux/linux/types/js_confirm_request.cc +++ /dev/null @@ -1,19 +0,0 @@ -#include "js_confirm_request.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -JsConfirmRequest::JsConfirmRequest(const std::optional& url, - const std::string& message, bool isMainFrame) - : url(url), message(message), isMainFrame(isMainFrame) {} - -FlValue* JsConfirmRequest::toFlValue() const { - return to_fl_map({ - {"url", make_fl_value(url)}, - {"message", make_fl_value(message)}, - {"isMainFrame", make_fl_value(isMainFrame)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/js_confirm_request.h b/flutter_inappwebview_linux/linux/types/js_confirm_request.h deleted file mode 100644 index 7ba77ed1c4..0000000000 --- a/flutter_inappwebview_linux/linux/types/js_confirm_request.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_JS_CONFIRM_REQUEST_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_JS_CONFIRM_REQUEST_H_ - -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * Represents a JavaScript confirm() dialog request. - */ -class JsConfirmRequest { - public: - std::optional url; - std::string message; - bool isMainFrame; - - JsConfirmRequest(const std::optional& url, const std::string& message, - bool isMainFrame); - ~JsConfirmRequest() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_JS_CONFIRM_REQUEST_H_ diff --git a/flutter_inappwebview_linux/linux/types/js_confirm_response.cc b/flutter_inappwebview_linux/linux/types/js_confirm_response.cc deleted file mode 100644 index 2b435154e8..0000000000 --- a/flutter_inappwebview_linux/linux/types/js_confirm_response.cc +++ /dev/null @@ -1,21 +0,0 @@ -#include "js_confirm_response.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -JsConfirmResponse::JsConfirmResponse() - : handledByClient(false), action(JsConfirmResponseAction::CANCEL) {} - -JsConfirmResponse::JsConfirmResponse(FlValue* map) - : handledByClient(false), action(JsConfirmResponseAction::CANCEL) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - handledByClient = get_fl_map_value(map, "handledByClient", handledByClient); - int64_t actionInt = get_fl_map_value(map, "action", 0); - action = static_cast(actionInt); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/js_confirm_response.h b/flutter_inappwebview_linux/linux/types/js_confirm_response.h deleted file mode 100644 index a2cadcf8ef..0000000000 --- a/flutter_inappwebview_linux/linux/types/js_confirm_response.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_JS_CONFIRM_RESPONSE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_JS_CONFIRM_RESPONSE_H_ - -#include - -namespace flutter_inappwebview_plugin { - -/** - * Response action for JS confirm dialogs. - */ -enum class JsConfirmResponseAction { CANCEL = 0, CONFIRM = 1 }; - -/** - * Response to a JavaScript confirm() dialog. - */ -class JsConfirmResponse { - public: - bool handledByClient; - JsConfirmResponseAction action; - - JsConfirmResponse(); - JsConfirmResponse(FlValue* map); - ~JsConfirmResponse() = default; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_JS_CONFIRM_RESPONSE_H_ diff --git a/flutter_inappwebview_linux/linux/types/js_prompt_request.cc b/flutter_inappwebview_linux/linux/types/js_prompt_request.cc deleted file mode 100644 index 5d4e1c3975..0000000000 --- a/flutter_inappwebview_linux/linux/types/js_prompt_request.cc +++ /dev/null @@ -1,20 +0,0 @@ -#include "js_prompt_request.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -JsPromptRequest::JsPromptRequest(const std::optional& url, const std::string& message, - const std::optional& defaultValue, bool isMainFrame) - : url(url), message(message), defaultValue(defaultValue), isMainFrame(isMainFrame) {} - -FlValue* JsPromptRequest::toFlValue() const { - return to_fl_map({ - {"url", make_fl_value(url)}, - {"message", make_fl_value(message)}, - {"defaultValue", make_fl_value(defaultValue)}, - {"isMainFrame", make_fl_value(isMainFrame)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/js_prompt_request.h b/flutter_inappwebview_linux/linux/types/js_prompt_request.h deleted file mode 100644 index bbd533c7d8..0000000000 --- a/flutter_inappwebview_linux/linux/types/js_prompt_request.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_JS_PROMPT_REQUEST_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_JS_PROMPT_REQUEST_H_ - -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * Represents a JavaScript prompt() dialog request. - */ -class JsPromptRequest { - public: - std::optional url; - std::string message; - std::optional defaultValue; - bool isMainFrame; - - JsPromptRequest(const std::optional& url, const std::string& message, - const std::optional& defaultValue, bool isMainFrame); - ~JsPromptRequest() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_JS_PROMPT_REQUEST_H_ diff --git a/flutter_inappwebview_linux/linux/types/js_prompt_response.cc b/flutter_inappwebview_linux/linux/types/js_prompt_response.cc deleted file mode 100644 index 7f73ed9c19..0000000000 --- a/flutter_inappwebview_linux/linux/types/js_prompt_response.cc +++ /dev/null @@ -1,22 +0,0 @@ -#include "js_prompt_response.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -JsPromptResponse::JsPromptResponse() - : handledByClient(false), action(JsPromptResponseAction::CANCEL) {} - -JsPromptResponse::JsPromptResponse(FlValue* map) - : handledByClient(false), action(JsPromptResponseAction::CANCEL) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - handledByClient = get_fl_map_value(map, "handledByClient", handledByClient); - int64_t actionInt = get_fl_map_value(map, "action", 0); - action = static_cast(actionInt); - value = get_optional_fl_map_value(map, "value"); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/js_prompt_response.h b/flutter_inappwebview_linux/linux/types/js_prompt_response.h deleted file mode 100644 index ea90d1743c..0000000000 --- a/flutter_inappwebview_linux/linux/types/js_prompt_response.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_JS_PROMPT_RESPONSE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_JS_PROMPT_RESPONSE_H_ - -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * Response action for JS prompt dialogs. - */ -enum class JsPromptResponseAction { CANCEL = 0, CONFIRM = 1 }; - -/** - * Response to a JavaScript prompt() dialog. - */ -class JsPromptResponse { - public: - bool handledByClient; - JsPromptResponseAction action; - std::optional value; - - JsPromptResponse(); - JsPromptResponse(FlValue* map); - ~JsPromptResponse() = default; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_JS_PROMPT_RESPONSE_H_ diff --git a/flutter_inappwebview_linux/linux/types/navigation_action.cc b/flutter_inappwebview_linux/linux/types/navigation_action.cc deleted file mode 100644 index dc15a44802..0000000000 --- a/flutter_inappwebview_linux/linux/types/navigation_action.cc +++ /dev/null @@ -1,24 +0,0 @@ -#include "navigation_action.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -NavigationAction::NavigationAction(std::shared_ptr request, bool isForMainFrame, - const std::optional& isRedirect, - const std::optional& navigationType) - : request(std::move(request)), - isForMainFrame(isForMainFrame), - isRedirect(isRedirect), - navigationType(navigationType) {} - -FlValue* NavigationAction::toFlValue() const { - return to_fl_map({ - {"request", request ? request->toFlValue() : make_fl_value()}, - {"isForMainFrame", make_fl_value(isForMainFrame)}, - {"isRedirect", make_fl_value(isRedirect)}, - {"navigationType", make_fl_value(NavigationActionTypeToInteger(navigationType))}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/navigation_action.h b/flutter_inappwebview_linux/linux/types/navigation_action.h deleted file mode 100644 index 0354c19f68..0000000000 --- a/flutter_inappwebview_linux/linux/types/navigation_action.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_NAVIGATION_ACTION_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_NAVIGATION_ACTION_H_ - -#include - -#include -#include - -#include "url_request.h" - -namespace flutter_inappwebview_plugin { - -enum class NavigationActionType { linkActivated = 0, backForward, reload, other }; - -inline std::optional NavigationActionTypeToInteger( - const std::optional& action) { - return action.has_value() ? static_cast(action.value()) : std::optional{}; -} - -class NavigationAction { - public: - const std::shared_ptr request; - const bool isForMainFrame; - const std::optional isRedirect; - const std::optional navigationType; - - NavigationAction(std::shared_ptr request, bool isForMainFrame, - const std::optional& isRedirect, - const std::optional& navigationType); - ~NavigationAction() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_NAVIGATION_ACTION_H_ diff --git a/flutter_inappwebview_linux/linux/types/option_menu_popup.cc b/flutter_inappwebview_linux/linux/types/option_menu_popup.cc deleted file mode 100644 index 2e4a0317ce..0000000000 --- a/flutter_inappwebview_linux/linux/types/option_menu_popup.cc +++ /dev/null @@ -1,665 +0,0 @@ -#include "option_menu_popup.h" - -#include - -#include -#include -#include - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -namespace flutter_inappwebview_plugin { - -OptionMenuPopup::OptionMenuPopup(GtkWindow* parent_window) : parent_window_(parent_window) { - // Create a popup window - popup_window_ = gtk_window_new(GTK_WINDOW_POPUP); - gtk_window_set_type_hint(GTK_WINDOW(popup_window_), GDK_WINDOW_TYPE_HINT_POPUP_MENU); - gtk_window_set_skip_taskbar_hint(GTK_WINDOW(popup_window_), TRUE); - gtk_window_set_skip_pager_hint(GTK_WINDOW(popup_window_), TRUE); - gtk_window_set_decorated(GTK_WINDOW(popup_window_), FALSE); - gtk_window_set_resizable(GTK_WINDOW(popup_window_), FALSE); - - if (parent_window_ != nullptr) { - gtk_window_set_transient_for(GTK_WINDOW(popup_window_), parent_window_); - } - - // Enable RGBA for transparency - GdkScreen* screen = gtk_widget_get_screen(popup_window_); - GdkVisual* visual = gdk_screen_get_rgba_visual(screen); - if (visual != nullptr) { - gtk_widget_set_visual(popup_window_, visual); - } - gtk_widget_set_app_paintable(popup_window_, TRUE); - - // Create drawing area - drawing_area_ = gtk_drawing_area_new(); - gtk_widget_set_can_focus(drawing_area_, TRUE); - gtk_container_add(GTK_CONTAINER(popup_window_), drawing_area_); - - // Enable events on drawing area - gtk_widget_add_events(drawing_area_, - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | - GDK_LEAVE_NOTIFY_MASK | GDK_SCROLL_MASK | GDK_KEY_PRESS_MASK); - - // Connect signals for drawing area - g_signal_connect(drawing_area_, "draw", G_CALLBACK(OnDraw), this); - g_signal_connect(drawing_area_, "button-press-event", G_CALLBACK(OnButtonPress), this); - g_signal_connect(drawing_area_, "button-release-event", G_CALLBACK(OnButtonRelease), this); - g_signal_connect(drawing_area_, "motion-notify-event", G_CALLBACK(OnMotionNotify), this); - g_signal_connect(drawing_area_, "leave-notify-event", G_CALLBACK(OnLeaveNotify), this); - g_signal_connect(drawing_area_, "scroll-event", G_CALLBACK(OnScroll), this); - g_signal_connect(drawing_area_, "key-press-event", G_CALLBACK(OnKeyPress), this); - - // Also connect button-press to popup window for when clicks land on window edge - g_signal_connect(popup_window_, "button-press-event", G_CALLBACK(OnButtonPress), this); - - // Connect signals for popup window - g_signal_connect(popup_window_, "focus-out-event", G_CALLBACK(OnFocusOut), this); - g_signal_connect(popup_window_, "unrealize", G_CALLBACK(OnUnrealize), this); - - gtk_widget_show(drawing_area_); -} - -OptionMenuPopup::~OptionMenuPopup() { - Hide(); // Ensure cleanup - if (popup_window_ != nullptr) { - gtk_widget_destroy(popup_window_); - popup_window_ = nullptr; - } -} - -void OptionMenuPopup::SetOptionMenu(WebKitOptionMenu* menu) { - webkit_menu_ = menu; - UpdateItems(); -} - -void OptionMenuPopup::UpdateItems() { - items_.clear(); - initially_selected_index_ = -1; - - if (webkit_menu_ == nullptr) { - return; - } - - guint n_items = webkit_option_menu_get_n_items(webkit_menu_); - - for (guint i = 0; i < n_items; i++) { - WebKitOptionMenuItem* item = webkit_option_menu_get_item(webkit_menu_, i); - - MenuItem menu_item; - const gchar* label = webkit_option_menu_item_get_label(item); - menu_item.label = label ? label : ""; - menu_item.enabled = webkit_option_menu_item_is_enabled(item); - menu_item.selected = webkit_option_menu_item_is_selected(item); - menu_item.is_group_label = webkit_option_menu_item_is_group_label(item); - menu_item.is_group_child = webkit_option_menu_item_is_group_child(item); - - if (menu_item.selected && menu_item.enabled && !menu_item.is_group_label) { - initially_selected_index_ = static_cast(i); - } - - items_.push_back(std::move(menu_item)); - } -} - -void OptionMenuPopup::UpdateSize() { - if (items_.empty()) { - width_ = MENU_MIN_WIDTH; - height_ = MENU_VERTICAL_PADDING * 2; - content_height_ = 0; - return; - } - - // Calculate width based on text - cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); - cairo_t* cr = cairo_create(surface); - - cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cr, MENU_ITEM_TEXT_SIZE); - - int max_text_width = 0; - for (const auto& item : items_) { - cairo_text_extents_t extents; - cairo_text_extents(cr, item.label.c_str(), &extents); - max_text_width = std::max(max_text_width, static_cast(extents.width)); - } - - cairo_destroy(cr); - cairo_surface_destroy(surface); - - // Add padding for margins - width_ = std::max(MENU_MIN_WIDTH, std::min(MENU_MAX_WIDTH, - max_text_width + MENU_HORIZONTAL_PADDING * 4)); - - // Calculate content height - content_height_ = 0; - for (const auto& item : items_) { - if (item.is_group_label) { - content_height_ += MENU_GROUP_LABEL_HEIGHT; - } else { - content_height_ += MENU_ITEM_HEIGHT; - } - } - - // Limit visible height - int max_visible_height = MENU_MAX_VISIBLE_ITEMS * MENU_ITEM_HEIGHT + MENU_VERTICAL_PADDING * 2; - height_ = std::min(content_height_ + MENU_VERTICAL_PADDING * 2, max_visible_height); -} - -void OptionMenuPopup::Show(int x, int y, int min_width) { - if (items_.empty()) { - return; - } - - UpdateSize(); - - // Use the HTML option menus using Cairo drawing. -/// This avoids focus issues with GtkMenu by using a GTK_WINDOW_POPUP -/// with custom rendering, similar to Cog browser's approach. -class OptionMenuPopup { - public: - explicit OptionMenuPopup(GtkWindow* parent_window); - ~OptionMenuPopup(); - - /// Set the WebKit option menu to display - void SetOptionMenu(WebKitOptionMenu* menu); - - /// Show the popup at the specified position (screen coordinates) - /// min_width is the minimum width based on the HTML element's width - void Show(int x, int y, int min_width = 0); - - /// Hide the popup and clean up - void Hide(); - - /// Check if the popup is currently visible - bool IsVisible() const { return visible_; } - - /// Set callback when an item is selected - void SetItemSelectedCallback(std::function callback) { - item_selected_callback_ = std::move(callback); - } - - /// Set callback when the menu is dismissed without selection - void SetDismissedCallback(std::function callback) { - dismissed_callback_ = std::move(callback); - } - - private: - struct MenuItem { - std::string label; - bool enabled = true; - bool selected = false; - bool is_group_label = false; - bool is_group_child = false; - }; - - // Layout constants (matching Cog browser style) - static constexpr int MENU_VERTICAL_PADDING = 8; - static constexpr int MENU_HORIZONTAL_PADDING = 12; - static constexpr int MENU_ITEM_HEIGHT = 32; - static constexpr int MENU_GROUP_LABEL_HEIGHT = 28; - static constexpr int MENU_ITEM_TEXT_SIZE = 14; - static constexpr int MENU_MIN_WIDTH = 150; - static constexpr int MENU_MAX_WIDTH = 400; - static constexpr int MENU_MAX_VISIBLE_ITEMS = 10; - - void UpdateItems(); - void UpdateSize(); - void Paint(); - int GetItemAtPosition(int x, int y) const; - void ScrollToItem(int index); - - // GTK signal handlers - static gboolean OnDraw(GtkWidget* widget, cairo_t* cr, gpointer user_data); - static gboolean OnButtonPress(GtkWidget* widget, GdkEventButton* event, gpointer user_data); - static gboolean OnButtonRelease(GtkWidget* widget, GdkEventButton* event, gpointer user_data); - static gboolean OnMotionNotify(GtkWidget* widget, GdkEventMotion* event, gpointer user_data); - static gboolean OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event, gpointer user_data); - static gboolean OnScroll(GtkWidget* widget, GdkEventScroll* event, gpointer user_data); - static gboolean OnKeyPress(GtkWidget* widget, GdkEventKey* event, gpointer user_data); - static gboolean OnFocusOut(GtkWidget* widget, GdkEventFocus* event, gpointer user_data); - static gboolean OnParentButtonPress(GtkWidget* widget, GdkEventButton* event, gpointer user_data); - static void OnUnrealize(GtkWidget* widget, gpointer user_data); - - GtkWindow* parent_window_ = nullptr; - GtkWidget* popup_window_ = nullptr; - GtkWidget* drawing_area_ = nullptr; - - WebKitOptionMenu* webkit_menu_ = nullptr; - std::vector items_; - - int width_ = 0; - int height_ = 0; - int content_height_ = 0; // Total height of all items - int scroll_offset_ = 0; // Current scroll position - int hovered_index_ = -1; - int pressed_index_ = -1; - int initially_selected_index_ = -1; - - int menu_x_ = 0; - int menu_y_ = 0; - - bool visible_ = false; - - gulong parent_button_handler_id_ = 0; - - std::function item_selected_callback_; - std::function dismissed_callback_; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_OPTION_MENU_POPUP_H_ diff --git a/flutter_inappwebview_linux/linux/types/permission_request.cc b/flutter_inappwebview_linux/linux/types/permission_request.cc deleted file mode 100644 index ad9a534fb0..0000000000 --- a/flutter_inappwebview_linux/linux/types/permission_request.cc +++ /dev/null @@ -1,56 +0,0 @@ -#include "permission_request.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -PermissionRequest::PermissionRequest(const std::optional& origin, - const std::vector& resourceTypes) - : origin(origin), webkitRequest(nullptr) { - for (const auto& type : resourceTypes) { - resources.push_back(static_cast(type)); - } -} - -FlValue* PermissionRequest::toFlValue() const { - return to_fl_map({ - {"origin", make_fl_value(origin)}, - {"resources", make_fl_value(resources)}, - {"frame", make_fl_value()}, // always null for WPE WebKit - }); -} - -std::vector PermissionRequest::getResourceTypes( - WebKitPermissionRequest* request) { - std::vector types; - - if (WEBKIT_IS_GEOLOCATION_PERMISSION_REQUEST(request)) { - types.push_back(PermissionResourceType::GEOLOCATION); - } else if (WEBKIT_IS_NOTIFICATION_PERMISSION_REQUEST(request)) { - types.push_back(PermissionResourceType::NOTIFICATIONS); - } else if (WEBKIT_IS_USER_MEDIA_PERMISSION_REQUEST(request)) { - gboolean isAudio = FALSE; - gboolean isVideo = FALSE; - - g_object_get(request, "is-for-audio-device", &isAudio, "is-for-video-device", &isVideo, - nullptr); - - if (isAudio && isVideo) { - types.push_back(PermissionResourceType::CAMERA_AND_MICROPHONE); - } else if (isAudio) { - types.push_back(PermissionResourceType::MICROPHONE); - } else if (isVideo) { - types.push_back(PermissionResourceType::CAMERA); - } - } - // Note: WEBKIT_IS_POINTER_LOCK_PERMISSION_REQUEST is not available in WPE WebKit - else if (WEBKIT_IS_DEVICE_INFO_PERMISSION_REQUEST(request)) { - types.push_back(PermissionResourceType::DEVICE_INFO); - } else if (WEBKIT_IS_MEDIA_KEY_SYSTEM_PERMISSION_REQUEST(request)) { - types.push_back(PermissionResourceType::PROTECTED_MEDIA_ID); - } - - return types; -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/permission_request.h b/flutter_inappwebview_linux/linux/types/permission_request.h deleted file mode 100644 index 7ac101c650..0000000000 --- a/flutter_inappwebview_linux/linux/types/permission_request.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_PERMISSION_REQUEST_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_PERMISSION_REQUEST_H_ - -#include -#include - -#include -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * Permission resource types that can be requested. - */ -enum class PermissionResourceType { - CAMERA = 0, - MICROPHONE = 1, - CAMERA_AND_MICROPHONE = 2, - GEOLOCATION = 3, - NOTIFICATIONS = 4, - PROTECTED_MEDIA_ID = 5, // EME/DRM permission (WebKitMediaKeySystemPermissionRequest) - MIDI_SYSEX = 6, // Not directly supported - DEVICE_INFO = 7, - POINTER_LOCK = 8 -}; - -/** - * Represents a permission request from web content. - */ -class PermissionRequest { - public: - std::optional origin; - std::vector resources; - - // Reference to the WebKit request to allow/deny later - WebKitPermissionRequest* webkitRequest; - - PermissionRequest(const std::optional& origin, - const std::vector& resourceTypes); - ~PermissionRequest() = default; - - FlValue* toFlValue() const; - - /** - * Determine the permission resource type from a WebKitPermissionRequest. - */ - static std::vector getResourceTypes(WebKitPermissionRequest* request); -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_PERMISSION_REQUEST_H_ diff --git a/flutter_inappwebview_linux/linux/types/permission_response.cc b/flutter_inappwebview_linux/linux/types/permission_response.cc deleted file mode 100644 index 2397293306..0000000000 --- a/flutter_inappwebview_linux/linux/types/permission_response.cc +++ /dev/null @@ -1,29 +0,0 @@ -#include "permission_response.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -PermissionResponse::PermissionResponse() : action(PermissionResponseAction::DENY) {} - -PermissionResponse::PermissionResponse(FlValue* map) : action(PermissionResponseAction::DENY) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - int64_t actionInt = get_fl_map_value(map, "action", 0); - action = static_cast(actionInt); - - FlValue* resourcesValue = fl_value_lookup_string(map, "resources"); - if (resourcesValue != nullptr && fl_value_get_type(resourcesValue) == FL_VALUE_TYPE_LIST) { - size_t len = fl_value_get_length(resourcesValue); - for (size_t i = 0; i < len; i++) { - FlValue* item = fl_value_get_list_value(resourcesValue, i); - if (fl_value_get_type(item) == FL_VALUE_TYPE_INT) { - resources.push_back(fl_value_get_int(item)); - } - } - } -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/permission_response.h b/flutter_inappwebview_linux/linux/types/permission_response.h deleted file mode 100644 index 4eeba7e868..0000000000 --- a/flutter_inappwebview_linux/linux/types/permission_response.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_PERMISSION_RESPONSE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_PERMISSION_RESPONSE_H_ - -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * Permission response actions. - */ -enum class PermissionResponseAction { - DENY = 0, - GRANT = 1, - PROMPT = 2 // Not used on Linux - will default to deny -}; - -/** - * Response to a permission request. - */ -class PermissionResponse { - public: - std::vector resources; - PermissionResponseAction action; - - PermissionResponse(); - PermissionResponse(FlValue* map); - ~PermissionResponse() = default; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_PERMISSION_RESPONSE_H_ diff --git a/flutter_inappwebview_linux/linux/types/plugin_script.cc b/flutter_inappwebview_linux/linux/types/plugin_script.cc deleted file mode 100644 index ae93ca0936..0000000000 --- a/flutter_inappwebview_linux/linux/types/plugin_script.cc +++ /dev/null @@ -1,22 +0,0 @@ -#include "plugin_script.h" - -namespace flutter_inappwebview_plugin { - -PluginScript::PluginScript(const std::string& groupName, const std::string& source, - UserScriptInjectionTime injectionTime, bool forMainFrameOnly, - const std::optional>& allowedOriginRules, - std::shared_ptr contentWorld, - bool requiredInAllContentWorlds, - const std::vector& messageHandlerNames) - : UserScript(groupName, source, injectionTime, forMainFrameOnly, allowedOriginRules, - contentWorld), - requiredInAllContentWorlds(requiredInAllContentWorlds), - messageHandlerNames(messageHandlerNames) {} - -bool PluginScript::operator==(const PluginScript& other) const { - return UserScript::operator==(other) && - requiredInAllContentWorlds == other.requiredInAllContentWorlds && - messageHandlerNames == other.messageHandlerNames; -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/plugin_script.h b/flutter_inappwebview_linux/linux/types/plugin_script.h deleted file mode 100644 index 2de163c62e..0000000000 --- a/flutter_inappwebview_linux/linux/types/plugin_script.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_PLUGIN_SCRIPT_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_PLUGIN_SCRIPT_H_ - -#include -#include -#include - -#include "user_script.h" - -namespace flutter_inappwebview_plugin { - -/** - * Represents an internal plugin script that is required for WebView functionality. - * Plugin scripts extend user scripts with additional properties like: - * - requiredInAllContentWorlds: whether the script needs to run in all content worlds - * - messageHandlerNames: names of message handlers this script uses - */ -class PluginScript : public UserScript { - public: - bool requiredInAllContentWorlds; - std::vector messageHandlerNames; - - PluginScript(const std::string& groupName, const std::string& source, - UserScriptInjectionTime injectionTime, bool forMainFrameOnly, - const std::optional>& allowedOriginRules = std::nullopt, - std::shared_ptr contentWorld = nullptr, - bool requiredInAllContentWorlds = false, - const std::vector& messageHandlerNames = {}); - - bool operator==(const PluginScript& other) const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_PLUGIN_SCRIPT_H_ diff --git a/flutter_inappwebview_linux/linux/types/render_process_gone_detail.cc b/flutter_inappwebview_linux/linux/types/render_process_gone_detail.cc deleted file mode 100644 index 19a1de2ce8..0000000000 --- a/flutter_inappwebview_linux/linux/types/render_process_gone_detail.cc +++ /dev/null @@ -1,32 +0,0 @@ -#include "render_process_gone_detail.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -RenderProcessGoneDetail::RenderProcessGoneDetail(WebKitWebProcessTerminationReason reason) { - // Map WPE WebKit termination reasons to didCrash: - // - WEBKIT_WEB_PROCESS_CRASHED: The web process crashed -> didCrash = true - // - WEBKIT_WEB_PROCESS_EXCEEDED_MEMORY_LIMIT: Killed by system due to memory -> didCrash = false - // - WEBKIT_WEB_PROCESS_TERMINATED_BY_API: Terminated via API call -> didCrash = false - switch (reason) { - case WEBKIT_WEB_PROCESS_CRASHED: - did_crash_ = true; - break; - case WEBKIT_WEB_PROCESS_EXCEEDED_MEMORY_LIMIT: - case WEBKIT_WEB_PROCESS_TERMINATED_BY_API: - default: - did_crash_ = false; - break; - } -} - -FlValue* RenderProcessGoneDetail::toFlValue() const { - return to_fl_map({ - {"didCrash", make_fl_value(did_crash_)}, - // rendererPriorityAtExit - WPE WebKit doesn't provide this, so it's always null - {"rendererPriorityAtExit", make_fl_value(nullptr)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/render_process_gone_detail.h b/flutter_inappwebview_linux/linux/types/render_process_gone_detail.h deleted file mode 100644 index b4fa63896d..0000000000 --- a/flutter_inappwebview_linux/linux/types/render_process_gone_detail.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_RENDER_PROCESS_GONE_DETAIL_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_RENDER_PROCESS_GONE_DETAIL_H_ - -#include -#include - -#include - -namespace flutter_inappwebview_plugin { - -/** - * RenderProcessGoneDetail - Provides details about why the web process terminated. - * - * Maps to Dart's RenderProcessGoneDetail class in platform_interface. - * Used by the onRenderProcessGone event. - */ -class RenderProcessGoneDetail { - public: - /** - * Construct from WPE WebKit termination reason. - */ - explicit RenderProcessGoneDetail(WebKitWebProcessTerminationReason reason); - - /** - * Whether the render process crashed (as opposed to being killed by the system). - */ - bool didCrash() const { return did_crash_; } - - /** - * Convert to FlValue for sending to Dart. - */ - FlValue* toFlValue() const; - - private: - bool did_crash_ = false; - // Note: WPE WebKit doesn't provide renderer priority information like Android does, - // so rendererPriorityAtExit is always null for Linux. -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_RENDER_PROCESS_GONE_DETAIL_H_ diff --git a/flutter_inappwebview_linux/linux/types/server_trust_auth_response.cc b/flutter_inappwebview_linux/linux/types/server_trust_auth_response.cc deleted file mode 100644 index 82c1957b41..0000000000 --- a/flutter_inappwebview_linux/linux/types/server_trust_auth_response.cc +++ /dev/null @@ -1,40 +0,0 @@ -#include "server_trust_auth_response.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -ServerTrustAuthResponse::ServerTrustAuthResponse(ServerTrustAuthResponseAction action) - : action(action) {} - -std::optional ServerTrustAuthResponse::fromFlValue(FlValue* value) { - if (value == nullptr || fl_value_get_type(value) == FL_VALUE_TYPE_NULL) { - return std::nullopt; - } - - if (fl_value_get_type(value) != FL_VALUE_TYPE_MAP) { - return std::nullopt; - } - - // Get the action field - FlValue* actionValue = fl_value_lookup_string(value, "action"); - if (actionValue == nullptr || fl_value_get_type(actionValue) == FL_VALUE_TYPE_NULL) { - return ServerTrustAuthResponse(ServerTrustAuthResponseAction::CANCEL); - } - - int64_t actionInt = fl_value_get_int(actionValue); - ServerTrustAuthResponseAction action; - switch (actionInt) { - case 1: - action = ServerTrustAuthResponseAction::PROCEED; - break; - case 0: - default: - action = ServerTrustAuthResponseAction::CANCEL; - break; - } - - return ServerTrustAuthResponse(action); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/server_trust_auth_response.h b/flutter_inappwebview_linux/linux/types/server_trust_auth_response.h deleted file mode 100644 index b4e2a06b1a..0000000000 --- a/flutter_inappwebview_linux/linux/types/server_trust_auth_response.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_SERVER_TRUST_AUTH_RESPONSE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_SERVER_TRUST_AUTH_RESPONSE_H_ - -#include - -#include - -namespace flutter_inappwebview_plugin { - -/** - * Action to take in response to a server trust authentication challenge. - * Maps to Dart's ServerTrustAuthResponseAction. - */ -enum class ServerTrustAuthResponseAction { - CANCEL = 0, // Reject the certificate and cancel the request - PROCEED = 1, // Accept the certificate and continue the request -}; - -/** - * Response to a server trust authentication challenge. - * Maps to Dart's ServerTrustAuthResponse. - */ -class ServerTrustAuthResponse { - public: - ServerTrustAuthResponseAction action; - - explicit ServerTrustAuthResponse(ServerTrustAuthResponseAction action = ServerTrustAuthResponseAction::CANCEL); - ~ServerTrustAuthResponse() = default; - - /** - * Create from FlValue map (from Dart response). - */ - static std::optional fromFlValue(FlValue* value); -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_SERVER_TRUST_AUTH_RESPONSE_H_ diff --git a/flutter_inappwebview_linux/linux/types/server_trust_challenge.cc b/flutter_inappwebview_linux/linux/types/server_trust_challenge.cc deleted file mode 100644 index 6e60d1918e..0000000000 --- a/flutter_inappwebview_linux/linux/types/server_trust_challenge.cc +++ /dev/null @@ -1,174 +0,0 @@ -#include "server_trust_challenge.h" - -#include -#include - -#include "../utils/flutter.h" -#include "../utils/uri.h" - -namespace flutter_inappwebview_plugin { - -// === SslError === - -SslError::SslError(SslErrorType code, const std::optional& message) - : code(code), message(message) {} - -FlValue* SslError::toFlValue() const { - std::string codeStr; - switch (code) { - case SslErrorType::NOT_YET_VALID: - codeStr = "NOT_YET_VALID"; - break; - case SslErrorType::EXPIRED: - codeStr = "EXPIRED"; - break; - case SslErrorType::IDMISMATCH: - codeStr = "IDMISMATCH"; - break; - case SslErrorType::UNTRUSTED: - codeStr = "UNTRUSTED"; - break; - case SslErrorType::REVOKED: - codeStr = "REVOKED"; - break; - case SslErrorType::INSECURE: - codeStr = "INSECURE"; - break; - case SslErrorType::INVALID: - default: - codeStr = "INVALID"; - break; - } - - return to_fl_map({ - {"code", make_fl_value(codeStr)}, - {"message", make_fl_value(message)}, - }); -} - -SslError SslError::fromGTlsCertificateFlags(GTlsCertificateFlags flags) { - // Map the most significant error - // WPE WebKit may set multiple flags, we pick the most relevant one - SslErrorType code; - std::string message; - - if (flags & G_TLS_CERTIFICATE_UNKNOWN_CA) { - code = SslErrorType::UNTRUSTED; - message = "The signing certificate authority is not known."; - } else if (flags & G_TLS_CERTIFICATE_BAD_IDENTITY) { - code = SslErrorType::IDMISMATCH; - message = "The certificate does not match the expected identity of the site."; - } else if (flags & G_TLS_CERTIFICATE_EXPIRED) { - code = SslErrorType::EXPIRED; - message = "The certificate has expired."; - } else if (flags & G_TLS_CERTIFICATE_NOT_ACTIVATED) { - code = SslErrorType::NOT_YET_VALID; - message = "The certificate's activation time is still in the future."; - } else if (flags & G_TLS_CERTIFICATE_REVOKED) { - code = SslErrorType::REVOKED; - message = "The certificate has been revoked."; - } else if (flags & G_TLS_CERTIFICATE_INSECURE) { - code = SslErrorType::INSECURE; - message = "The certificate's algorithm is considered insecure."; - } else if (flags & G_TLS_CERTIFICATE_GENERIC_ERROR) { - code = SslErrorType::INVALID; - message = "A generic error occurred validating the certificate."; - } else { - code = SslErrorType::INVALID; - message = "Unknown TLS certificate error."; - } - - return SslError(code, message); -} - -// === ServerTrustURLProtectionSpace === - -ServerTrustURLProtectionSpace::ServerTrustURLProtectionSpace( - const std::string& host, int64_t port, - const std::optional& protocol, - std::shared_ptr sslCertificate, - std::shared_ptr sslError) - : host(host), port(port), protocol(protocol), sslCertificate(sslCertificate), - sslError(sslError) {} - -FlValue* ServerTrustURLProtectionSpace::toFlValue() const { - return to_fl_map({ - {"host", make_fl_value(host)}, - {"port", make_fl_value(port)}, - {"protocol", make_fl_value(protocol)}, - {"sslCertificate", sslCertificate ? sslCertificate->toFlValue() : fl_value_new_null()}, - {"sslError", sslError ? sslError->toFlValue() : fl_value_new_null()}, - // Include authenticationMethod as SERVER_TRUST - {"authenticationMethod", make_fl_value(std::string("NSURLAuthenticationMethodServerTrust"))}, - }); -} - -// === ServerTrustChallenge === - -ServerTrustChallenge::ServerTrustChallenge( - std::shared_ptr protectionSpace) - : protectionSpace(protectionSpace) {} - -FlValue* ServerTrustChallenge::toFlValue() const { - return to_fl_map({ - {"protectionSpace", protectionSpace ? protectionSpace->toFlValue() : fl_value_new_null()}, - }); -} - -std::unique_ptr ServerTrustChallenge::fromTlsError( - const std::string& failingUri, GTlsCertificate* certificate, GTlsCertificateFlags errors) { - - // Parse host and port from the failing URI - std::string host = get_host_from_url(failingUri); - int64_t port = 443; // Default to HTTPS port - - // Try to extract port from URL - // Simple parsing - look for :port after host - size_t schemeEnd = failingUri.find("://"); - if (schemeEnd != std::string::npos) { - size_t hostStart = schemeEnd + 3; - size_t pathStart = failingUri.find('/', hostStart); - std::string hostPort = (pathStart != std::string::npos) ? - failingUri.substr(hostStart, pathStart - hostStart) : - failingUri.substr(hostStart); - - size_t colonPos = hostPort.rfind(':'); - if (colonPos != std::string::npos) { - try { - port = std::stoll(hostPort.substr(colonPos + 1)); - } catch (...) { - // Keep default port - } - } - } - - // Extract protocol - std::optional protocol; - std::string scheme = get_scheme_from_url(failingUri); - if (!scheme.empty()) { - protocol = scheme; - } - - // Extract certificate data - std::shared_ptr sslCertificate; - if (certificate != nullptr) { - GByteArray* certData = nullptr; - g_object_get(certificate, "certificate", &certData, nullptr); - if (certData != nullptr) { - std::vector derData(certData->data, certData->data + certData->len); - sslCertificate = std::make_shared(derData); - g_byte_array_unref(certData); - } - } - - // Convert error flags to SslError - auto sslError = std::make_shared(SslError::fromGTlsCertificateFlags(errors)); - - // Create protection space - auto protectionSpace = std::make_shared( - host, port, protocol, sslCertificate, sslError); - - return std::make_unique(protectionSpace); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/server_trust_challenge.h b/flutter_inappwebview_linux/linux/types/server_trust_challenge.h deleted file mode 100644 index 17d361a010..0000000000 --- a/flutter_inappwebview_linux/linux/types/server_trust_challenge.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_SERVER_TRUST_CHALLENGE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_SERVER_TRUST_CHALLENGE_H_ - -#include -#include - -#include -#include -#include -#include -#include - -#include "ssl_certificate.h" - -namespace flutter_inappwebview_plugin { - -/** - * SSL Error type - maps to Dart's SslErrorType. - * Based on GTlsCertificateFlags. - */ -enum class SslErrorType { - INVALID = 0, // G_TLS_CERTIFICATE_GENERIC_ERROR - NOT_YET_VALID = 1, // G_TLS_CERTIFICATE_NOT_ACTIVATED - EXPIRED = 2, // G_TLS_CERTIFICATE_EXPIRED - IDMISMATCH = 3, // G_TLS_CERTIFICATE_BAD_IDENTITY - UNTRUSTED = 4, // G_TLS_CERTIFICATE_UNKNOWN_CA - REVOKED = 5, // G_TLS_CERTIFICATE_REVOKED - INSECURE = 6, // G_TLS_CERTIFICATE_INSECURE -}; - -/** - * SSL Error information - maps to Dart's SslError class. - */ -class SslError { - public: - SslErrorType code; - std::optional message; - - SslError(SslErrorType code, const std::optional& message); - ~SslError() = default; - - FlValue* toFlValue() const; - - static SslError fromGTlsCertificateFlags(GTlsCertificateFlags flags); -}; - -/** - * URL Protection Space for server trust authentication. - * Extended version that includes SSL certificate and error info. - */ -class ServerTrustURLProtectionSpace { - public: - std::string host; - int64_t port; - std::optional protocol; - std::shared_ptr sslCertificate; - std::shared_ptr sslError; - - ServerTrustURLProtectionSpace(const std::string& host, int64_t port, - const std::optional& protocol, - std::shared_ptr sslCertificate, - std::shared_ptr sslError); - ~ServerTrustURLProtectionSpace() = default; - - FlValue* toFlValue() const; -}; - -/** - * Server Trust Challenge - sent when a TLS error occurs. - * Maps to Dart's ServerTrustChallenge class. - */ -class ServerTrustChallenge { - public: - std::shared_ptr protectionSpace; - - explicit ServerTrustChallenge(std::shared_ptr protectionSpace); - ~ServerTrustChallenge() = default; - - FlValue* toFlValue() const; - - /** - * Create a ServerTrustChallenge from WPE WebKit TLS error parameters. - */ - static std::unique_ptr fromTlsError( - const std::string& failingUri, GTlsCertificate* certificate, GTlsCertificateFlags errors); -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_SERVER_TRUST_CHALLENGE_H_ diff --git a/flutter_inappwebview_linux/linux/types/show_file_chooser_response.cc b/flutter_inappwebview_linux/linux/types/show_file_chooser_response.cc deleted file mode 100644 index 98eee6c828..0000000000 --- a/flutter_inappwebview_linux/linux/types/show_file_chooser_response.cc +++ /dev/null @@ -1,36 +0,0 @@ -#include "show_file_chooser_response.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -ShowFileChooserResponse::ShowFileChooserResponse() - : handledByClient(false), filePaths(std::nullopt) {} - -ShowFileChooserResponse::ShowFileChooserResponse( - bool handledByClient, std::optional> filePaths) - : handledByClient(handledByClient), filePaths(std::move(filePaths)) {} - -ShowFileChooserResponse ShowFileChooserResponse::fromFlValue(FlValue* value) { - if (value == nullptr || fl_value_get_type(value) == FL_VALUE_TYPE_NULL) { - return ShowFileChooserResponse(); - } - - if (fl_value_get_type(value) != FL_VALUE_TYPE_MAP) { - return ShowFileChooserResponse(); - } - - auto handledByClient = get_fl_map_value(value, "handledByClient", false); - auto filePaths = get_optional_fl_map_value>(value, "filePaths"); - - return ShowFileChooserResponse(handledByClient, std::move(filePaths)); -} - -FlValue* ShowFileChooserResponse::toFlValue() const { - return to_fl_map({ - {"handledByClient", make_fl_value(handledByClient)}, - {"filePaths", make_fl_value(filePaths)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/show_file_chooser_response.h b/flutter_inappwebview_linux/linux/types/show_file_chooser_response.h deleted file mode 100644 index fef590f75c..0000000000 --- a/flutter_inappwebview_linux/linux/types/show_file_chooser_response.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_SHOW_FILE_CHOOSER_RESPONSE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_SHOW_FILE_CHOOSER_RESPONSE_H_ - -#include - -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -class ShowFileChooserResponse { - public: - bool handledByClient; - std::optional> filePaths; - - ShowFileChooserResponse(); - ShowFileChooserResponse(bool handledByClient, - std::optional> filePaths); - ~ShowFileChooserResponse() = default; - - static ShowFileChooserResponse fromFlValue(FlValue* value); - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_SHOW_FILE_CHOOSER_RESPONSE_H_ diff --git a/flutter_inappwebview_linux/linux/types/ssl_certificate.cc b/flutter_inappwebview_linux/linux/types/ssl_certificate.cc deleted file mode 100644 index c19b020b28..0000000000 --- a/flutter_inappwebview_linux/linux/types/ssl_certificate.cc +++ /dev/null @@ -1,19 +0,0 @@ -#include "ssl_certificate.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -SslCertificate::SslCertificate(const std::optional>& x509Certificate) - : x509Certificate(x509Certificate) {} - -SslCertificate::SslCertificate(FlValue* map) - : x509Certificate(get_optional_fl_map_value>(map, "x509Certificate")) {} - -FlValue* SslCertificate::toFlValue() const { - return to_fl_map({ - {"x509Certificate", make_fl_value(x509Certificate)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/ssl_certificate.h b/flutter_inappwebview_linux/linux/types/ssl_certificate.h deleted file mode 100644 index ab1bdc2c28..0000000000 --- a/flutter_inappwebview_linux/linux/types/ssl_certificate.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_SSL_CERTIFICATE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_SSL_CERTIFICATE_H_ - -#include - -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -/// SSL Certificate information for HTTPS connections. -/// Maps to Dart's SslCertificate class. -class SslCertificate { - public: - /// The raw X.509 certificate data in DER format. - const std::optional> x509Certificate; - - /// Constructor with raw certificate data. - explicit SslCertificate(const std::optional>& x509Certificate); - - /// Constructor from FlValue map (for deserialization from Dart). - explicit SslCertificate(FlValue* map); - - ~SslCertificate() = default; - - /// Convert to FlValue map for sending to Dart. - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_SSL_CERTIFICATE_H_ diff --git a/flutter_inappwebview_linux/linux/types/url_credential.cc b/flutter_inappwebview_linux/linux/types/url_credential.cc deleted file mode 100644 index 24302e5389..0000000000 --- a/flutter_inappwebview_linux/linux/types/url_credential.cc +++ /dev/null @@ -1,29 +0,0 @@ -#include "url_credential.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -URLCredential::URLCredential() {} - -URLCredential::URLCredential(const std::optional& username, - const std::optional& password) - : username(username), password(password) {} - -URLCredential::URLCredential(FlValue* map) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - username = get_optional_fl_map_value(map, "username"); - password = get_optional_fl_map_value(map, "password"); -} - -FlValue* URLCredential::toFlValue() const { - return to_fl_map({ - {"username", make_fl_value(username)}, - {"password", make_fl_value(password)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/url_credential.h b/flutter_inappwebview_linux/linux/types/url_credential.h deleted file mode 100644 index f6a2af6576..0000000000 --- a/flutter_inappwebview_linux/linux/types/url_credential.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_URL_CREDENTIAL_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_URL_CREDENTIAL_H_ - -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * URL credential for storing/providing authentication credentials. - */ -class URLCredential { - public: - std::optional username; - std::optional password; - - URLCredential(); - URLCredential(const std::optional& username, - const std::optional& password); - URLCredential(FlValue* map); - ~URLCredential() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_URL_CREDENTIAL_H_ diff --git a/flutter_inappwebview_linux/linux/types/url_protection_space.cc b/flutter_inappwebview_linux/linux/types/url_protection_space.cc deleted file mode 100644 index f061b56af6..0000000000 --- a/flutter_inappwebview_linux/linux/types/url_protection_space.cc +++ /dev/null @@ -1,80 +0,0 @@ -#include "url_protection_space.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -// Convert HttpAuthScheme to the string values expected by the platform interface -static std::optional authSchemeToString(HttpAuthScheme scheme) { - switch (scheme) { - case HttpAuthScheme::DEFAULT: - return "NSURLAuthenticationMethodDefault"; - case HttpAuthScheme::HTTP_BASIC: - return "NSURLAuthenticationMethodHTTPBasic"; - case HttpAuthScheme::HTTP_DIGEST: - return "NSURLAuthenticationMethodHTTPDigest"; - case HttpAuthScheme::HTML_FORM: - return "NSURLAuthenticationMethodHTMLForm"; - case HttpAuthScheme::NTLM: - return "NSURLAuthenticationMethodNTLM"; - case HttpAuthScheme::NEGOTIATE: - return "NSURLAuthenticationMethodNegotiate"; - case HttpAuthScheme::CLIENT_CERTIFICATE: - return "NSURLAuthenticationMethodClientCertificate"; - case HttpAuthScheme::SERVER_TRUST: - return "NSURLAuthenticationMethodServerTrust"; - case HttpAuthScheme::UNKNOWN: - default: - return std::nullopt; - } -} - -URLProtectionSpace::URLProtectionSpace(const std::string& host, int64_t port, - const std::optional& protocol, - const std::optional& realm, - HttpAuthScheme authenticationMethod, bool isProxy) - : host(host), - port(port), - protocol(protocol), - realm(realm), - authenticationMethod(authenticationMethod), - isProxy(isProxy) {} - -FlValue* URLProtectionSpace::toFlValue() const { - auto authMethodStr = authSchemeToString(authenticationMethod); - return to_fl_map({ - {"host", make_fl_value(host)}, - {"port", make_fl_value(port)}, - {"protocol", make_fl_value(protocol)}, - {"realm", make_fl_value(realm)}, - {"authenticationMethod", make_fl_value(authMethodStr)}, - {"isProxy", make_fl_value(isProxy)}, - {"sslCertificate", make_fl_value()}, - {"sslError", make_fl_value()}, - }); -} - -HttpAuthScheme URLProtectionSpace::fromWebKitScheme(WebKitAuthenticationScheme scheme) { - switch (scheme) { - case WEBKIT_AUTHENTICATION_SCHEME_DEFAULT: - return HttpAuthScheme::DEFAULT; - case WEBKIT_AUTHENTICATION_SCHEME_HTTP_BASIC: - return HttpAuthScheme::HTTP_BASIC; - case WEBKIT_AUTHENTICATION_SCHEME_HTTP_DIGEST: - return HttpAuthScheme::HTTP_DIGEST; - case WEBKIT_AUTHENTICATION_SCHEME_HTML_FORM: - return HttpAuthScheme::HTML_FORM; - case WEBKIT_AUTHENTICATION_SCHEME_NTLM: - return HttpAuthScheme::NTLM; - case WEBKIT_AUTHENTICATION_SCHEME_NEGOTIATE: - return HttpAuthScheme::NEGOTIATE; - case WEBKIT_AUTHENTICATION_SCHEME_CLIENT_CERTIFICATE_REQUESTED: - return HttpAuthScheme::CLIENT_CERTIFICATE; - case WEBKIT_AUTHENTICATION_SCHEME_SERVER_TRUST_EVALUATION_REQUESTED: - return HttpAuthScheme::SERVER_TRUST; - default: - return HttpAuthScheme::UNKNOWN; - } -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/url_protection_space.h b/flutter_inappwebview_linux/linux/types/url_protection_space.h deleted file mode 100644 index 8a73b4436b..0000000000 --- a/flutter_inappwebview_linux/linux/types/url_protection_space.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_URL_PROTECTION_SPACE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_URL_PROTECTION_SPACE_H_ - -#include -#include - -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -/** - * HTTP authentication scheme types. - */ -enum class HttpAuthScheme { - DEFAULT = 0, - HTTP_BASIC = 1, - HTTP_DIGEST = 2, - HTML_FORM = 3, - NTLM = 4, - NEGOTIATE = 5, - CLIENT_CERTIFICATE = 6, - SERVER_TRUST = 7, - UNKNOWN = -1 -}; - -/** - * URL protection space - describes the realm requiring authentication. - */ -class URLProtectionSpace { - public: - std::string host; - int64_t port; - std::optional protocol; - std::optional realm; - HttpAuthScheme authenticationMethod; - bool isProxy; - - URLProtectionSpace(const std::string& host, int64_t port, - const std::optional& protocol, - const std::optional& realm, HttpAuthScheme authenticationMethod, - bool isProxy); - ~URLProtectionSpace() = default; - - FlValue* toFlValue() const; - - static HttpAuthScheme fromWebKitScheme(WebKitAuthenticationScheme scheme); -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_URL_PROTECTION_SPACE_H_ diff --git a/flutter_inappwebview_linux/linux/types/url_request.cc b/flutter_inappwebview_linux/linux/types/url_request.cc deleted file mode 100644 index 710ce75ae3..0000000000 --- a/flutter_inappwebview_linux/linux/types/url_request.cc +++ /dev/null @@ -1,28 +0,0 @@ -#include "url_request.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -URLRequest::URLRequest(const std::optional& url, - const std::optional& method, - const std::optional>& headers, - const std::optional>& body) - : url(url), method(method), headers(headers), body(body) {} - -URLRequest::URLRequest(FlValue* map) - : url(get_optional_fl_map_value(map, "url")), - method(get_optional_fl_map_value(map, "method")), - headers(get_optional_fl_map_value>(map, "headers")), - body(get_optional_fl_map_value>(map, "body")) {} - -FlValue* URLRequest::toFlValue() const { - return to_fl_map({ - {"url", make_fl_value(url)}, - {"method", make_fl_value(method)}, - {"headers", make_fl_value(headers)}, - {"body", make_fl_value(body)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/url_request.h b/flutter_inappwebview_linux/linux/types/url_request.h deleted file mode 100644 index dea9fff496..0000000000 --- a/flutter_inappwebview_linux/linux/types/url_request.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_URL_REQUEST_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_URL_REQUEST_H_ - -#include - -#include -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -class URLRequest { - public: - const std::optional url; - const std::optional method; - const std::optional> headers; - const std::optional> body; - - URLRequest(const std::optional& url, const std::optional& method, - const std::optional>& headers, - const std::optional>& body); - - URLRequest(FlValue* map); - - ~URLRequest() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_URL_REQUEST_H_ diff --git a/flutter_inappwebview_linux/linux/types/user_script.cc b/flutter_inappwebview_linux/linux/types/user_script.cc deleted file mode 100644 index cdfbb4afc5..0000000000 --- a/flutter_inappwebview_linux/linux/types/user_script.cc +++ /dev/null @@ -1,58 +0,0 @@ -#include "user_script.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -UserScript::UserScript(const std::optional& groupName, const std::string& source, - UserScriptInjectionTime injectionTime, bool forMainFrameOnly, - const std::optional>& allowedOriginRules, - std::shared_ptr contentWorld) - : groupName(groupName), - source(source), - injectionTime(injectionTime), - forMainFrameOnly(forMainFrameOnly), - allowedOriginRules(allowedOriginRules), - contentWorld(contentWorld ? contentWorld : ContentWorld::page()) {} - -UserScript::UserScript(FlValue* map) - : injectionTime(UserScriptInjectionTime::atDocumentStart), forMainFrameOnly(true) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return; - } - - groupName = get_optional_fl_map_value(map, "groupName"); - source = get_fl_map_value(map, "source", ""); - - int64_t injectionTimeValue = get_fl_map_value(map, "injectionTime", 0); - injectionTime = static_cast(injectionTimeValue); - - forMainFrameOnly = get_fl_map_value(map, "forMainFrameOnly", true); - - allowedOriginRules = get_optional_fl_map_value>(map, "allowedOriginRules"); - - FlValue* contentWorldValue = fl_value_lookup_string(map, "contentWorld"); - if (contentWorldValue != nullptr && fl_value_get_type(contentWorldValue) == FL_VALUE_TYPE_MAP) { - contentWorld = std::make_shared(contentWorldValue); - } else { - contentWorld = ContentWorld::page(); - } -} - -FlValue* UserScript::toFlValue() const { - return to_fl_map({ - {"groupName", make_fl_value(groupName)}, - {"source", make_fl_value(source)}, - {"injectionTime", make_fl_value(static_cast(injectionTime))}, - {"forMainFrameOnly", make_fl_value(forMainFrameOnly)}, - {"allowedOriginRules", make_fl_value(allowedOriginRules)}, - {"contentWorld", contentWorld ? contentWorld->toFlValue() : make_fl_value()}, - }); -} - -bool UserScript::operator==(const UserScript& other) const { - return groupName == other.groupName && source == other.source && - injectionTime == other.injectionTime && forMainFrameOnly == other.forMainFrameOnly; -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/user_script.h b/flutter_inappwebview_linux/linux/types/user_script.h deleted file mode 100644 index 0fcc622a7f..0000000000 --- a/flutter_inappwebview_linux/linux/types/user_script.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_USER_SCRIPT_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_USER_SCRIPT_H_ - -#include - -#include -#include -#include -#include - -#include "content_world.h" - -namespace flutter_inappwebview_plugin { - -enum class UserScriptInjectionTime { - atDocumentStart = 0, - atDocumentEnd = 1, -}; - -/** - * Represents a user script to be injected into the web view. - */ -class UserScript { - public: - std::optional groupName; - std::string source; - UserScriptInjectionTime injectionTime; - bool forMainFrameOnly; - std::optional> allowedOriginRules; - std::shared_ptr contentWorld; - - UserScript(const std::optional& groupName, const std::string& source, - UserScriptInjectionTime injectionTime, bool forMainFrameOnly, - const std::optional>& allowedOriginRules = std::nullopt, - std::shared_ptr contentWorld = nullptr); - - UserScript(FlValue* map); - - FlValue* toFlValue() const; - - bool operator==(const UserScript& other) const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_USER_SCRIPT_H_ diff --git a/flutter_inappwebview_linux/linux/types/web_resource_error.cc b/flutter_inappwebview_linux/linux/types/web_resource_error.cc deleted file mode 100644 index e577f2ef5d..0000000000 --- a/flutter_inappwebview_linux/linux/types/web_resource_error.cc +++ /dev/null @@ -1,21 +0,0 @@ -#include "web_resource_error.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -WebResourceError::WebResourceError(const std::string& description, int64_t type) - : description(description), type(type) {} - -WebResourceError::WebResourceError(FlValue* map) - : description(get_fl_map_value(map, "description", "")), - type(get_fl_map_value(map, "type", 399)) {} - -FlValue* WebResourceError::toFlValue() const { - return to_fl_map({ - {"description", make_fl_value(description)}, - {"type", make_fl_value(type)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/web_resource_error.h b/flutter_inappwebview_linux/linux/types/web_resource_error.h deleted file mode 100644 index 48a5c91f7e..0000000000 --- a/flutter_inappwebview_linux/linux/types/web_resource_error.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_RESOURCE_ERROR_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_RESOURCE_ERROR_H_ - -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -class WebResourceError { - public: - const std::string description; - const int64_t type; - - WebResourceError(const std::string& description, int64_t type); - WebResourceError(FlValue* map); - ~WebResourceError() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_RESOURCE_ERROR_H_ diff --git a/flutter_inappwebview_linux/linux/types/web_resource_request.cc b/flutter_inappwebview_linux/linux/types/web_resource_request.cc deleted file mode 100644 index cb365332e4..0000000000 --- a/flutter_inappwebview_linux/linux/types/web_resource_request.cc +++ /dev/null @@ -1,28 +0,0 @@ -#include "web_resource_request.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -WebResourceRequest::WebResourceRequest( - const std::optional& url, const std::optional& method, - const std::optional>& headers, - const std::optional& isForMainFrame) - : url(url), method(method), headers(headers), isForMainFrame(isForMainFrame) {} - -WebResourceRequest::WebResourceRequest(FlValue* map) - : url(get_optional_fl_map_value(map, "url")), - method(get_optional_fl_map_value(map, "method")), - headers(get_optional_fl_map_value>(map, "headers")), - isForMainFrame(get_optional_fl_map_value(map, "isForMainFrame")) {} - -FlValue* WebResourceRequest::toFlValue() const { - return to_fl_map({ - {"url", make_fl_value(url)}, - {"method", make_fl_value(method)}, - {"headers", make_fl_value(headers)}, - {"isForMainFrame", make_fl_value(isForMainFrame)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/web_resource_request.h b/flutter_inappwebview_linux/linux/types/web_resource_request.h deleted file mode 100644 index 2616413b0d..0000000000 --- a/flutter_inappwebview_linux/linux/types/web_resource_request.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_RESOURCE_REQUEST_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_RESOURCE_REQUEST_H_ - -#include - -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -class WebResourceRequest { - public: - std::optional url; - std::optional method; - std::optional> headers; - std::optional isForMainFrame; - - WebResourceRequest(const std::optional& url, - const std::optional& method, - const std::optional>& headers, - const std::optional& isForMainFrame); - WebResourceRequest(FlValue* map); - ~WebResourceRequest() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_RESOURCE_REQUEST_H_ diff --git a/flutter_inappwebview_linux/linux/types/web_resource_response.cc b/flutter_inappwebview_linux/linux/types/web_resource_response.cc deleted file mode 100644 index 09f60fb726..0000000000 --- a/flutter_inappwebview_linux/linux/types/web_resource_response.cc +++ /dev/null @@ -1,39 +0,0 @@ -#include "web_resource_response.h" - -#include "../utils/flutter.h" - -namespace flutter_inappwebview_plugin { - -WebResourceResponse::WebResourceResponse( - const std::optional& contentType, - const std::optional& contentEncoding, const std::optional& statusCode, - const std::optional& reasonPhrase, - const std::optional>& headers, - const std::optional>& data) - : contentType(contentType), - contentEncoding(contentEncoding), - statusCode(statusCode), - reasonPhrase(reasonPhrase), - headers(headers), - data(data) {} - -WebResourceResponse::WebResourceResponse(FlValue* map) - : contentType(get_optional_fl_map_value(map, "contentType")), - contentEncoding(get_optional_fl_map_value(map, "contentEncoding")), - statusCode(get_optional_fl_map_value(map, "statusCode")), - reasonPhrase(get_optional_fl_map_value(map, "reasonPhrase")), - headers(get_optional_fl_map_value>(map, "headers")), - data(get_optional_fl_map_value>(map, "data")) {} - -FlValue* WebResourceResponse::toFlValue() const { - return to_fl_map({ - {"contentType", make_fl_value(contentType)}, - {"contentEncoding", make_fl_value(contentEncoding)}, - {"statusCode", make_fl_value(statusCode)}, - {"reasonPhrase", make_fl_value(reasonPhrase)}, - {"headers", make_fl_value(headers)}, - {"data", make_fl_value(data)}, - }); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/web_resource_response.h b/flutter_inappwebview_linux/linux/types/web_resource_response.h deleted file mode 100644 index 6da6bc5985..0000000000 --- a/flutter_inappwebview_linux/linux/types/web_resource_response.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_RESOURCE_RESPONSE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_RESOURCE_RESPONSE_H_ - -#include - -#include -#include -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -class WebResourceResponse { - public: - std::optional contentType; - std::optional contentEncoding; - std::optional statusCode; - std::optional reasonPhrase; - std::optional> headers; - std::optional> data; - - WebResourceResponse( - const std::optional& contentType = std::nullopt, - const std::optional& contentEncoding = std::nullopt, - const std::optional& statusCode = std::nullopt, - const std::optional& reasonPhrase = std::nullopt, - const std::optional>& headers = std::nullopt, - const std::optional>& data = std::nullopt); - WebResourceResponse(FlValue* map); - ~WebResourceResponse() = default; - - FlValue* toFlValue() const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_RESOURCE_RESPONSE_H_ diff --git a/flutter_inappwebview_linux/linux/types/web_view_transport.cc b/flutter_inappwebview_linux/linux/types/web_view_transport.cc deleted file mode 100644 index 2965fc50d5..0000000000 --- a/flutter_inappwebview_linux/linux/types/web_view_transport.cc +++ /dev/null @@ -1,14 +0,0 @@ -#include "web_view_transport.h" - -#include "../in_app_webview/in_app_webview.h" - -namespace flutter_inappwebview_plugin { - -WebKitWebView* WebViewTransport::getWebKitWebView() const { - if (inAppWebView) { - return inAppWebView->webview(); - } - return nullptr; -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/types/web_view_transport.h b/flutter_inappwebview_linux/linux/types/web_view_transport.h deleted file mode 100644 index 8ceb364ad5..0000000000 --- a/flutter_inappwebview_linux/linux/types/web_view_transport.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_VIEW_TRANSPORT_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_VIEW_TRANSPORT_H_ - -#include - -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -class InAppWebView; - -/** - * Holds a WebView created for a new window (via onCreateWindow) - * along with the initial URL request that triggered it. - */ -struct WebViewTransport { - // The InAppWebView wrapper that owns the WebKitWebView - std::unique_ptr inAppWebView; - - // The initial URL request that triggered the window creation - std::optional url; - - WebViewTransport(std::unique_ptr webView, const std::optional& url) - : inAppWebView(std::move(webView)), url(url) {} - - // Get the internal WebKitWebView* (for returning to WebKit create signal) - WebKitWebView* getWebKitWebView() const; - - ~WebViewTransport() = default; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_VIEW_TRANSPORT_H_ diff --git a/flutter_inappwebview_linux/linux/utils/defer.h b/flutter_inappwebview_linux/linux/utils/defer.h deleted file mode 100644 index 5f47e24297..0000000000 --- a/flutter_inappwebview_linux/linux/utils/defer.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_DEFER_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_DEFER_H_ - -#include -#include - -namespace flutter_inappwebview_plugin { - -// Utility to defer cleanup operations using RAII -static inline std::shared_ptr defer(void* handle, - const std::function& callback) { - return std::shared_ptr(handle, callback); -} - -// RAII helper for scoped cleanup -template -class ScopeGuard { - public: - explicit ScopeGuard(Func&& func) : func_(std::move(func)), active_(true) {} - - ScopeGuard(ScopeGuard&& other) noexcept : func_(std::move(other.func_)), active_(other.active_) { - other.dismiss(); - } - - ~ScopeGuard() { - if (active_) { - func_(); - } - } - - void dismiss() noexcept { active_ = false; } - - ScopeGuard(const ScopeGuard&) = delete; - ScopeGuard& operator=(const ScopeGuard&) = delete; - - private: - Func func_; - bool active_; -}; - -template -ScopeGuard make_scope_guard(Func&& func) { - return ScopeGuard(std::forward(func)); -} - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_DEFER_H_ diff --git a/flutter_inappwebview_linux/linux/utils/flutter.h b/flutter_inappwebview_linux/linux/utils/flutter.h deleted file mode 100644 index b9663624c1..0000000000 --- a/flutter_inappwebview_linux/linux/utils/flutter.h +++ /dev/null @@ -1,390 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_FLUTTER_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_FLUTTER_H_ - -#include - -#include -#include -#include -#include -#include - -#include "map.h" -#include "util.h" -#include "vector.h" - -namespace flutter_inappwebview_plugin { - -// ============================================================================ -// Type aliases for FlValue map building (similar to Windows EncodableMap) -// ============================================================================ - -/** - * Type alias for building FlValue maps using standard C++ initializer lists. - * This allows a consistent pattern similar to Windows' flutter::EncodableMap. - * - * Usage: - * FlValueMap map = { - * {"key1", make_fl_value("value1")}, - * {"key2", make_fl_value(42)}, - * {"key3", make_fl_value(optionalValue)}, // auto handles std::optional - * }; - * return to_fl_map(map); - */ -using FlValueMap = std::initializer_list>; - -/** - * Converts an FlValueMap initializer list to an FlValue* map. - * All values are taken (ownership transferred), so they should be created - * with make_fl_value() or fl_value_new_*() functions. - */ -static inline FlValue* to_fl_map(FlValueMap entries) { - FlValue* map = fl_value_new_map(); - for (const auto& [key, value] : entries) { - fl_value_set_string_take(map, key, value); - } - return map; -} - -// ============================================================================ -// FlValue creation helpers (make_fl_value) -// ============================================================================ - -static inline FlValue* make_fl_value() { - return fl_value_new_null(); -} - -static inline FlValue* make_fl_value(std::nullptr_t) { - return fl_value_new_null(); -} - -static inline FlValue* make_fl_value(bool val) { - return fl_value_new_bool(val); -} - -static inline FlValue* make_fl_value(int32_t val) { - return fl_value_new_int(static_cast(val)); -} - -static inline FlValue* make_fl_value(int64_t val) { - return fl_value_new_int(val); -} - -static inline FlValue* make_fl_value(double val) { - return fl_value_new_float(val); -} - -static inline FlValue* make_fl_value(const char* val) { - return val == nullptr ? fl_value_new_null() : fl_value_new_string(val); -} - -static inline FlValue* make_fl_value(const std::string& val) { - return fl_value_new_string(val.c_str()); -} - -static inline FlValue* make_fl_value(const std::vector& val) { - return fl_value_new_uint8_list(val.data(), val.size()); -} - -template -static inline FlValue* make_fl_value(const std::vector& vec) { - FlValue* list = fl_value_new_list(); - for (const auto& item : vec) { - fl_value_append_take(list, make_fl_value(item)); - } - return list; -} - -template -static inline FlValue* make_fl_value(const std::map& map) { - FlValue* fl_map = fl_value_new_map(); - for (const auto& [key, val] : map) { - fl_value_set_take(fl_map, make_fl_value(key), make_fl_value(val)); - } - return fl_map; -} - -template -static inline FlValue* make_fl_value(const std::optional& optional) { - return optional.has_value() ? make_fl_value(optional.value()) : fl_value_new_null(); -} - -// ============================================================================ -// FlValue map access helpers -// ============================================================================ - -static inline bool fl_map_contains(FlValue* map, const char* key) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return false; - } - FlValue* value = fl_value_lookup_string(map, key); - return value != nullptr; -} - -static inline bool fl_map_contains_not_null(FlValue* map, const char* key) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return false; - } - FlValue* value = fl_value_lookup_string(map, key); - return value != nullptr && fl_value_get_type(value) != FL_VALUE_TYPE_NULL; -} - -// ============================================================================ -// FlValue extraction helpers (get_fl_map_value with default) -// ============================================================================ - -// Generic template declaration -template -static inline T get_fl_map_value(FlValue* map, const char* key, const T& defaultValue); - -// Specialization for bool -template <> -inline bool get_fl_map_value(FlValue* map, const char* key, const bool& defaultValue) { - if (!fl_map_contains_not_null(map, key)) { - return defaultValue; - } - FlValue* value = fl_value_lookup_string(map, key); - if (fl_value_get_type(value) == FL_VALUE_TYPE_BOOL) { - return fl_value_get_bool(value); - } - return defaultValue; -} - -// Specialization for int64_t -template <> -inline int64_t get_fl_map_value(FlValue* map, const char* key, - const int64_t& defaultValue) { - if (!fl_map_contains_not_null(map, key)) { - return defaultValue; - } - FlValue* value = fl_value_lookup_string(map, key); - if (fl_value_get_type(value) == FL_VALUE_TYPE_INT) { - return fl_value_get_int(value); - } - return defaultValue; -} - -// Specialization for int32_t (uses int64_t internally) -template <> -inline int32_t get_fl_map_value(FlValue* map, const char* key, - const int32_t& defaultValue) { - if (!fl_map_contains_not_null(map, key)) { - return defaultValue; - } - FlValue* value = fl_value_lookup_string(map, key); - if (fl_value_get_type(value) == FL_VALUE_TYPE_INT) { - return static_cast(fl_value_get_int(value)); - } - return defaultValue; -} - -// Specialization for double -template <> -inline double get_fl_map_value(FlValue* map, const char* key, const double& defaultValue) { - if (!fl_map_contains_not_null(map, key)) { - return defaultValue; - } - FlValue* value = fl_value_lookup_string(map, key); - if (fl_value_get_type(value) == FL_VALUE_TYPE_FLOAT) { - return fl_value_get_float(value); - } - if (fl_value_get_type(value) == FL_VALUE_TYPE_INT) { - return static_cast(fl_value_get_int(value)); - } - return defaultValue; -} - -// Specialization for std::string -template <> -inline std::string get_fl_map_value(FlValue* map, const char* key, - const std::string& defaultValue) { - if (!fl_map_contains_not_null(map, key)) { - return defaultValue; - } - FlValue* value = fl_value_lookup_string(map, key); - if (fl_value_get_type(value) == FL_VALUE_TYPE_STRING) { - return std::string(fl_value_get_string(value)); - } - return defaultValue; -} - -// Specialization for std::vector -template <> -inline std::vector get_fl_map_value>( - FlValue* map, const char* key, const std::vector& defaultValue) { - if (!fl_map_contains_not_null(map, key)) { - return defaultValue; - } - FlValue* value = fl_value_lookup_string(map, key); - if (fl_value_get_type(value) != FL_VALUE_TYPE_LIST) { - return defaultValue; - } - std::vector result; - size_t len = fl_value_get_length(value); - result.reserve(len); - for (size_t i = 0; i < len; i++) { - FlValue* item = fl_value_get_list_value(value, i); - if (fl_value_get_type(item) == FL_VALUE_TYPE_STRING) { - result.push_back(std::string(fl_value_get_string(item))); - } - } - return result; -} - -// ============================================================================ -// FlValue extraction helpers (get_optional_fl_map_value) -// ============================================================================ - -template -static inline std::optional get_optional_fl_map_value(FlValue* map, const char* key); - -// Specialization for bool -template <> -inline std::optional get_optional_fl_map_value(FlValue* map, const char* key) { - if (!fl_map_contains_not_null(map, key)) { - return std::nullopt; - } - FlValue* value = fl_value_lookup_string(map, key); - if (fl_value_get_type(value) == FL_VALUE_TYPE_BOOL) { - return std::make_optional(fl_value_get_bool(value)); - } - return std::nullopt; -} - -// Specialization for int64_t -template <> -inline std::optional get_optional_fl_map_value(FlValue* map, const char* key) { - if (!fl_map_contains_not_null(map, key)) { - return std::nullopt; - } - FlValue* value = fl_value_lookup_string(map, key); - if (fl_value_get_type(value) == FL_VALUE_TYPE_INT) { - return std::make_optional(fl_value_get_int(value)); - } - return std::nullopt; -} - -// Specialization for int32_t -template <> -inline std::optional get_optional_fl_map_value(FlValue* map, const char* key) { - if (!fl_map_contains_not_null(map, key)) { - return std::nullopt; - } - FlValue* value = fl_value_lookup_string(map, key); - if (fl_value_get_type(value) == FL_VALUE_TYPE_INT) { - return std::make_optional(static_cast(fl_value_get_int(value))); - } - return std::nullopt; -} - -// Specialization for double -template <> -inline std::optional get_optional_fl_map_value(FlValue* map, const char* key) { - if (!fl_map_contains_not_null(map, key)) { - return std::nullopt; - } - FlValue* value = fl_value_lookup_string(map, key); - if (fl_value_get_type(value) == FL_VALUE_TYPE_FLOAT) { - return std::make_optional(fl_value_get_float(value)); - } - if (fl_value_get_type(value) == FL_VALUE_TYPE_INT) { - return std::make_optional(static_cast(fl_value_get_int(value))); - } - return std::nullopt; -} - -// Specialization for std::string -template <> -inline std::optional get_optional_fl_map_value(FlValue* map, - const char* key) { - if (!fl_map_contains_not_null(map, key)) { - return std::nullopt; - } - FlValue* value = fl_value_lookup_string(map, key); - if (fl_value_get_type(value) == FL_VALUE_TYPE_STRING) { - return std::make_optional(std::string(fl_value_get_string(value))); - } - return std::nullopt; -} - -// Specialization for std::vector -template <> -inline std::optional> get_optional_fl_map_value>( - FlValue* map, const char* key) { - if (!fl_map_contains_not_null(map, key)) { - return std::nullopt; - } - FlValue* value = fl_value_lookup_string(map, key); - if (fl_value_get_type(value) != FL_VALUE_TYPE_LIST) { - return std::nullopt; - } - std::vector result; - size_t len = fl_value_get_length(value); - result.reserve(len); - for (size_t i = 0; i < len; i++) { - FlValue* item = fl_value_get_list_value(value, i); - if (fl_value_get_type(item) == FL_VALUE_TYPE_STRING) { - result.push_back(std::string(fl_value_get_string(item))); - } - } - return std::make_optional(result); -} - -// Specialization for std::vector -template <> -inline std::optional> get_optional_fl_map_value>( - FlValue* map, const char* key) { - if (!fl_map_contains_not_null(map, key)) { - return std::nullopt; - } - FlValue* value = fl_value_lookup_string(map, key); - if (fl_value_get_type(value) == FL_VALUE_TYPE_UINT8_LIST) { - size_t len = fl_value_get_length(value); - const uint8_t* data = fl_value_get_uint8_list(value); - return std::make_optional(std::vector(data, data + len)); - } - return std::nullopt; -} - -// Specialization for std::map -template <> -inline std::optional> -get_optional_fl_map_value>(FlValue* map, const char* key) { - if (!fl_map_contains_not_null(map, key)) { - return std::nullopt; - } - FlValue* value = fl_value_lookup_string(map, key); - if (fl_value_get_type(value) != FL_VALUE_TYPE_MAP) { - return std::nullopt; - } - std::map result; - size_t len = fl_value_get_length(value); - for (size_t i = 0; i < len; i++) { - FlValue* map_key = fl_value_get_map_key(value, i); - FlValue* map_val = fl_value_get_map_value(value, i); - if (fl_value_get_type(map_key) == FL_VALUE_TYPE_STRING && - fl_value_get_type(map_val) == FL_VALUE_TYPE_STRING) { - result[fl_value_get_string(map_key)] = fl_value_get_string(map_val); - } - } - return std::make_optional(result); -} - -// ============================================================================ -// FlValue type helpers -// ============================================================================ - -static inline FlValue* fl_value_lookup_string_safe(FlValue* map, const char* key) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return nullptr; - } - return fl_value_lookup_string(map, key); -} - -static inline FlValue* get_fl_map_value_raw(FlValue* map, const char* key) { - return fl_value_lookup_string_safe(map, key); -} - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_FLUTTER_H_ diff --git a/flutter_inappwebview_linux/linux/utils/gl_context.h b/flutter_inappwebview_linux/linux/utils/gl_context.h deleted file mode 100644 index 4d51d99693..0000000000 --- a/flutter_inappwebview_linux/linux/utils/gl_context.h +++ /dev/null @@ -1,88 +0,0 @@ -// GL context utilities for checking if EGL/GLX context is current. -// -// IMPORTANT: We use dlsym to call eglGetCurrentContext/glXGetCurrentContext -// directly from libEGL/libGLX because libepoxy's wrappers go through -// epoxy_get_proc_address which ASSERTS that a context must be current, -// causing a catch-22 situation when we need to check if a context exists. - -#ifndef FLUTTER_INAPPWEBVIEW_LINUX_UTILS_GL_CONTEXT_H_ -#define FLUTTER_INAPPWEBVIEW_LINUX_UTILS_GL_CONTEXT_H_ - -#include -#include - -// EGL_NO_CONTEXT is typically defined as nullptr/0, but we define it here -// to avoid including EGL headers which would conflict with epoxy -#ifndef EGL_NO_CONTEXT -#define EGL_NO_CONTEXT nullptr -#endif - -namespace flutter_inappwebview_plugin { - -/** - * Check if we have a current EGL or GLX context. - * This MUST be called before any GL/EGL operations to avoid crashes from - * libepoxy when no context is current. - * - * @return true if a GL context is current on this thread, false otherwise. - */ -inline bool HasCurrentGLContext() { - // Use cached function pointers to avoid repeated dlsym calls - static void* (*egl_get_current_context)(void) = nullptr; - static void* (*glx_get_current_context)(void) = nullptr; - static bool initialized = false; - - if (!initialized) { - initialized = true; - - // Try to load and get eglGetCurrentContext - // First try NOLOAD (already loaded), then try loading it - void* egl_lib = dlopen("libEGL.so.1", RTLD_NOW | RTLD_NOLOAD); - if (egl_lib == nullptr) { - egl_lib = dlopen("libEGL.so", RTLD_NOW | RTLD_NOLOAD); - } - if (egl_lib == nullptr) { - // Library not loaded yet, try to load it - egl_lib = dlopen("libEGL.so.1", RTLD_NOW); - } - if (egl_lib != nullptr) { - egl_get_current_context = reinterpret_cast( - dlsym(egl_lib, "eglGetCurrentContext")); - } - - // Also try GLX for X11 environments - void* glx_lib = dlopen("libGLX.so.0", RTLD_NOW | RTLD_NOLOAD); - if (glx_lib == nullptr) { - glx_lib = dlopen("libGL.so.1", RTLD_NOW | RTLD_NOLOAD); - } - if (glx_lib == nullptr) { - glx_lib = dlopen("libGL.so", RTLD_NOW | RTLD_NOLOAD); - } - if (glx_lib != nullptr) { - glx_get_current_context = reinterpret_cast( - dlsym(glx_lib, "glXGetCurrentContext")); - } - } - - // Check EGL context first - if (egl_get_current_context != nullptr) { - void* ctx = egl_get_current_context(); - if (ctx != nullptr && ctx != EGL_NO_CONTEXT) { - return true; - } - } - - // Check GLX context - if (glx_get_current_context != nullptr) { - void* ctx = glx_get_current_context(); - if (ctx != nullptr) { - return true; - } - } - - return false; -} - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_LINUX_UTILS_GL_CONTEXT_H_ diff --git a/flutter_inappwebview_linux/linux/utils/log.h b/flutter_inappwebview_linux/linux/utils/log.h deleted file mode 100644 index ec6b957865..0000000000 --- a/flutter_inappwebview_linux/linux/utils/log.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_UTIL_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_UTIL_H_ - -#include - -#include -#include -#include - -#include "string.h" - -namespace flutter_inappwebview_plugin { - -template -static inline void debugLog(const std::basic_string& msg, const bool& isError = false, - const std::string& filename = "", const int& line = 0) { -#ifndef NDEBUG - std::basic_string debugMsg = msg; - if (!filename.empty() && line > 0) { - auto filenameSplit = split(filename, std::string{"/flutter_inappwebview_linux/"}); - std::string reduceFilenamePath = - filenameSplit.size() > 0 ? "flutter_inappwebview_linux/" + filenameSplit.back() : filename; - debugMsg = reduceFilenamePath + "(" + std::to_string(line) + "): " + debugMsg; - } - - // Use g_message for GLib-based logging - if (isError) { - g_warning("[flutter_inappwebview] %s", std::string(debugMsg).c_str()); - } else { - g_message("[flutter_inappwebview] %s", std::string(debugMsg).c_str()); - } -#endif -} - -static inline void debugLog(const char* msg, const bool& isError = false, - const std::string& filename = "", const int& line = 0) { - debugLog(std::string(msg), isError, filename, line); -} - -static inline void debugLog(const bool& value, const bool& isError = false, - const std::string& filename = "", const int& line = 0) { - debugLog(value ? "true" : "false", isError, filename, line); -} - -template ::value, T>::type> -static inline void debugLog(const T& value, const bool& isError = false, - const std::string& filename = "", const int& line = 0) { - debugLog(std::to_string(value), isError, filename, line); -} - -static inline void errorLog(const std::string& msg, const std::string& filename = "", - const int& line = 0) { - debugLog(msg, true, filename, line); -} - -// GError logging helper -static inline void logGError(GError* error, const std::string& filename = "", const int& line = 0) { - if (error != nullptr) { - std::string msg = "GError: " + std::string(error->message) + - " (domain: " + std::to_string(error->domain) + - ", code: " + std::to_string(error->code) + ")"; - debugLog(msg, true, filename, line); - } -} - -// Success check with logging for GError - returns true if NO error -static inline bool succeededOrLog(GError** error, const std::string& filename = "", - const int& line = 0) { - if (error != nullptr && *error != nullptr) { - logGError(*error, filename, line); - g_error_free(*error); - *error = nullptr; - return false; - } - return true; -} - -// Failed check with logging for GError - returns true if there IS an error -static inline bool failedAndLog(GError** error, const std::string& filename = "", - const int& line = 0) { - if (error != nullptr && *error != nullptr) { - logGError(*error, filename, line); - g_error_free(*error); - *error = nullptr; - return true; - } - return false; -} - -// Log GError without returning status -static inline void failedLog(GError** error, const std::string& filename = "", - const int& line = 0) { - if (error != nullptr && *error != nullptr) { - logGError(*error, filename, line); - g_error_free(*error); - *error = nullptr; - } -} - -} // namespace flutter_inappwebview_plugin - -#ifndef NDEBUG -#define debugLog(value) debugLog(value, false, __FILE__, __LINE__) -#define logGError(error) logGError(error, __FILE__, __LINE__) -#define succeededOrLog(error) succeededOrLog(error, __FILE__, __LINE__) -#define failedAndLog(error) failedAndLog(error, __FILE__, __LINE__) -#define failedLog(error) failedLog(error, __FILE__, __LINE__) -#endif - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_UTIL_H_ diff --git a/flutter_inappwebview_linux/linux/utils/map.h b/flutter_inappwebview_linux/linux/utils/map.h deleted file mode 100644 index 1c10b745fc..0000000000 --- a/flutter_inappwebview_linux/linux/utils/map.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_MAP_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_MAP_H_ - -#include -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -template -struct is_mappish_impl : std::false_type {}; - -template -struct is_mappish_impl< - T, std::void_t()[std::declval()])>> - : std::true_type {}; - -template -struct is_mappish : is_mappish_impl::type {}; - -template -static inline bool map_contains(const std::map& map, const K& key) { - return map.find(key) != map.end(); -} - -template -static inline T map_at_or_null(const std::map& map, const K& key) { - auto itr = map.find(key); - return itr != map.end() ? itr->second : nullptr; -} - -template -static inline std::optional map_at_optional(const std::map& map, const K& key) { - auto itr = map.find(key); - return itr != map.end() ? std::make_optional(itr->second) : std::nullopt; -} - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_MAP_H_ diff --git a/flutter_inappwebview_linux/linux/utils/software_rendering.cc b/flutter_inappwebview_linux/linux/utils/software_rendering.cc deleted file mode 100644 index c549e80104..0000000000 --- a/flutter_inappwebview_linux/linux/utils/software_rendering.cc +++ /dev/null @@ -1,200 +0,0 @@ -// Utility to detect if software rendering should be used -// This checks for VM environments where DMA-BUF/GPU acceleration may not work properly - -#include "software_rendering.h" - -#include -#include -#include -#include -#include - -#include "log.h" - -namespace flutter_inappwebview_plugin { - -namespace { - -// Check if we're running in a virtual machine by reading system files. -// This is a standard approach used by systemd-detect-virt, virt-what, etc. -// These files are readable by any process and contain only hardware ID info. -bool IsRunningInVirtualMachine() { - // Known VM product name indicators - const char* vm_indicators[] = { - "QEMU", "KVM", "VMware", "VirtualBox", "Parallels", "Xen", - "Microsoft Virtual", "Hyper-V", "UTM", "Virtual Machine", - "Bochs", "innotek", "Oracle", nullptr - }; - - // Check /sys/class/dmi/id/product_name - FILE* f = fopen("/sys/class/dmi/id/product_name", "r"); - if (f) { - char buf[256] = {0}; - if (fgets(buf, sizeof(buf), f)) { - fclose(f); - for (const char** indicator = vm_indicators; *indicator; indicator++) { - if (strcasestr(buf, *indicator)) { - debugLog("VM detected via product_name: " + std::string(buf)); - return true; - } - } - } else { - fclose(f); - } - } - - // Check /sys/class/dmi/id/sys_vendor - f = fopen("/sys/class/dmi/id/sys_vendor", "r"); - if (f) { - char buf[256] = {0}; - if (fgets(buf, sizeof(buf), f)) { - fclose(f); - for (const char** indicator = vm_indicators; *indicator; indicator++) { - if (strcasestr(buf, *indicator)) { - debugLog("VM detected via sys_vendor: " + std::string(buf)); - return true; - } - } - } else { - fclose(f); - } - } - - // Check /proc/cpuinfo for hypervisor flag (x86/x64) - f = fopen("/proc/cpuinfo", "r"); - if (f) { - char line[512]; - while (fgets(line, sizeof(line), f)) { - if (strstr(line, "flags") && strstr(line, "hypervisor")) { - fclose(f); - debugLog("VM detected via hypervisor CPU flag"); - return true; - } - } - fclose(f); - } - - return false; -} - -// Check if we have a known good GPU driver that works well with DMA-BUF -bool HasKnownGoodGpuDriver() { - const char* dri_paths[] = { - "/sys/class/drm/card0/device/driver", - "/sys/class/drm/renderD128/device/driver", - nullptr - }; - - // Known good drivers that work well with DMA-BUF - const char* good_drivers[] = { - "nvidia", // Nvidia proprietary driver - "nouveau", // Nvidia open-source driver - "amdgpu", // AMD GPU driver - "radeon", // Older AMD driver - "i915", // Intel integrated graphics - "xe", // Intel Xe graphics (newer) - nullptr - }; - - for (const char** path = dri_paths; *path; path++) { - char link_target[256] = {0}; - ssize_t len = readlink(*path, link_target, sizeof(link_target) - 1); - if (len > 0) { - link_target[len] = '\0'; - for (const char** driver = good_drivers; *driver; driver++) { - if (strstr(link_target, *driver)) { - debugLog("Known good GPU driver detected: " + std::string(link_target)); - return true; - } - } - } - } - - return false; -} - -// Check if the GPU driver is known to have DMA-BUF issues -bool HasProblematicGpuDriver() { - // If we have a known good driver, it's not problematic - if (HasKnownGoodGpuDriver()) { - return false; - } - - const char* dri_paths[] = { - "/sys/class/drm/card0/device/driver", - "/sys/class/drm/renderD128/device/driver", - nullptr - }; - - for (const char** path = dri_paths; *path; path++) { - char link_target[256] = {0}; - ssize_t len = readlink(*path, link_target, sizeof(link_target) - 1); - if (len > 0) { - link_target[len] = '\0'; - // virtio-gpu and vmwgfx have known issues in VMs - if (strstr(link_target, "virtio") || strstr(link_target, "vmwgfx")) { - debugLog("Problematic GPU driver detected: " + std::string(link_target)); - return true; - } - } - } - - return false; -} - -} // namespace - -bool ShouldUseSoftwareRendering() { - // Check user override: skip detection - const char* skip_check = getenv("FLUTTER_INAPPWEBVIEW_SKIP_DMABUF_CHECK"); - if (skip_check && (strcmp(skip_check, "1") == 0 || strcasecmp(skip_check, "true") == 0)) { - return false; - } - - // Already set by user or another component - const char* already_sw = getenv("LIBGL_ALWAYS_SOFTWARE"); - if (already_sw && (strcmp(already_sw, "1") == 0 || strcasecmp(already_sw, "true") == 0)) { - return true; // Already in software mode - } - - // If we have a known good GPU driver, use hardware rendering - if (HasKnownGoodGpuDriver()) { - debugLog("Known good GPU driver found, using hardware rendering"); - return false; - } - - const bool in_vm = IsRunningInVirtualMachine(); - - // Detect VM environment - if (in_vm) { - return true; - } - - // Detect problematic GPU drivers only inside a VM - if (in_vm && HasProblematicGpuDriver()) { - return true; - } - - return false; -} - -bool ApplySoftwareRenderingIfNeeded() { - // Already set - nothing to do - const char* already_sw = getenv("LIBGL_ALWAYS_SOFTWARE"); - if (already_sw && (strcmp(already_sw, "1") == 0 || strcasecmp(already_sw, "true") == 0)) { - debugLog("Software rendering already enabled (LIBGL_ALWAYS_SOFTWARE set)"); - return true; - } - - if (ShouldUseSoftwareRendering()) { - // Set BEFORE any EGL/GL initialization - setenv("LIBGL_ALWAYS_SOFTWARE", "1", 0); // Don't override if already set - debugLog("Auto-enabled software rendering for VM/problematic GPU environment"); - return true; - } - - debugLog("Using hardware GPU rendering"); - return false; -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/utils/software_rendering.h b/flutter_inappwebview_linux/linux/utils/software_rendering.h deleted file mode 100644 index b51e274143..0000000000 --- a/flutter_inappwebview_linux/linux/utils/software_rendering.h +++ /dev/null @@ -1,28 +0,0 @@ -// Utility to detect if software rendering should be used -// This checks for VM environments where DMA-BUF/GPU acceleration may not work properly - -#ifndef FLUTTER_INAPPWEBVIEW_LINUX_UTILS_SOFTWARE_RENDERING_H_ -#define FLUTTER_INAPPWEBVIEW_LINUX_UTILS_SOFTWARE_RENDERING_H_ - -namespace flutter_inappwebview_plugin { - -// Check if software rendering should be automatically enabled. -// This detects VM environments (UTM, QEMU, VMware, VirtualBox, etc.) where -// GPU acceleration via DMA-BUF may not work correctly. -// -// Environment variables: -// - LIBGL_ALWAYS_SOFTWARE=1 : Force software rendering (standard WebKit flag) -// - FLUTTER_INAPPWEBVIEW_SKIP_DMABUF_CHECK=1 : Skip detection, use hardware -// -// If this returns true, LIBGL_ALWAYS_SOFTWARE=1 should be set BEFORE any -// EGL/GL/WPE initialization to ensure WebKit uses SHM buffers. -bool ShouldUseSoftwareRendering(); - -// Apply software rendering environment if needed. -// Call this ONCE at plugin initialization, BEFORE any WebView is created. -// Returns true if software rendering was enabled. -bool ApplySoftwareRenderingIfNeeded(); - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_LINUX_UTILS_SOFTWARE_RENDERING_H_ diff --git a/flutter_inappwebview_linux/linux/utils/string.h b/flutter_inappwebview_linux/linux/utils/string.h deleted file mode 100644 index a2796d0889..0000000000 --- a/flutter_inappwebview_linux/linux/utils/string.h +++ /dev/null @@ -1,186 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_STRING_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_STRING_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -template -struct is_string : std::false_type {}; - -// Partial specialization - parameters used to qualify the specialization -template -struct is_string> : std::true_type {}; - -template -using is_basic_string = is_string>; - -template -static inline bool string_equals(const std::basic_string& s1, const std::basic_string& s2) { - return s1.compare(s2) == 0; -} - -template -static inline bool string_equals(const std::basic_string& s1, const char* s2) { - return s1.compare(s2) == 0; -} - -template -static inline bool string_equals(const char* s1, const std::basic_string& s2) { - return s2.compare(s1) == 0; -} - -template -static inline bool string_equals(const std::optional>& s1, - const std::basic_string& s2) { - return s1.has_value() ? string_equals(s1.value(), s2) : false; -} - -template -static inline bool string_equals(const std::basic_string& s1, - const std::optional>& s2) { - return s2.has_value() ? string_equals(s1, s2.value()) : false; -} - -template -static inline bool string_equals(const std::optional>& s1, - const std::optional>& s2) { - return s1.has_value() && s2.has_value() ? string_equals(s1.value(), s2.value()) : true; -} - -static inline void replace_all(std::string& source, const std::string& from, - const std::string& to) { - std::string newString; - newString.reserve(source.length()); // avoids a few memory allocations - - std::string::size_type lastPos = 0; - std::string::size_type findPos; - - while (std::string::npos != (findPos = source.find(from, lastPos))) { - newString.append(source, lastPos, findPos - lastPos); - newString += to; - lastPos = findPos + from.length(); - } - - // Care for the rest after last occurrence - newString += source.substr(lastPos); - - source.swap(newString); -} - -static inline std::string replace_all_copy(const std::string& source, const std::string& from, - const std::string& to) { - std::string newString; - newString.reserve(source.length()); // avoids a few memory allocations - - std::string::size_type lastPos = 0; - std::string::size_type findPos; - - while (std::string::npos != (findPos = source.find(from, lastPos))) { - newString.append(source, lastPos, findPos - lastPos); - newString += to; - lastPos = findPos + from.length(); - } - - // Care for the rest after last occurrence - newString += source.substr(lastPos); - - return newString; -} - -template -static inline std::basic_string join(const std::vector>& vec, - const std::basic_string& delim) { - return vec.empty() ? std::basic_string{""} - : std::accumulate(++vec.begin(), vec.end(), *vec.begin(), - [&delim](auto& a, auto& b) { return a + delim + b; }); -} - -template -static inline std::basic_string join(const std::vector>& vec, - const char* delim) { - return join(vec, std::basic_string{delim}); -} - -template -static inline std::vector> split(const std::basic_string& s, - std::basic_string delimiter) { - size_t pos_start = 0, pos_end, delim_len = delimiter.length(); - std::basic_string token; - std::vector> res; - - while ((pos_end = s.find(delimiter, pos_start)) != std::basic_string::npos) { - token = s.substr(pos_start, pos_end - pos_start); - pos_start = pos_end + delim_len; - res.push_back(token); - } - - res.push_back(s.substr(pos_start)); - return res; -} - -template -void to_lowercase(std::basic_string& s) { - std::transform(s.begin(), s.end(), s.begin(), - [](const T v) { return static_cast(std::tolower(v)); }); -} - -template -std::basic_string to_lowercase_copy(const std::basic_string& s) { - std::basic_string s2 = s; - std::transform(s2.begin(), s2.end(), s2.begin(), - [](const T v) { return static_cast(std::tolower(v)); }); - return s2; -} - -template -void to_uppercase(std::basic_string& s) { - std::transform(s.begin(), s.end(), s.begin(), - [](const T v) { return static_cast(std::toupper(v)); }); -} - -template -std::basic_string to_uppercase_copy(const std::basic_string& s) { - std::basic_string s2 = s; - std::transform(s2.begin(), s2.end(), s2.begin(), - [](const T v) { return static_cast(std::toupper(v)); }); - return s2; -} - -template -bool starts_with(const std::basic_string& str, const std::basic_string& prefix) { - return str.size() >= prefix.size() && str.compare(0, prefix.size(), prefix) == 0; -} - -template -bool ends_with(const std::basic_string& str, const std::basic_string& suffix) { - return str.size() >= suffix.size() && - str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; -} - -constexpr uint32_t string_hash(const std::string_view data) noexcept { - uint32_t hash = 5381; - for (const auto& e : data) - hash = ((hash << 5) + hash) + e; - return hash; -}; - -static inline std::string trim(const std::string& str) { - size_t first = str.find_first_not_of(" \t\n\r\f\v"); - if (std::string::npos == first) { - return str; - } - size_t last = str.find_last_not_of(" \t\n\r\f\v"); - return str.substr(first, (last - first + 1)); -} - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_STRING_H_ diff --git a/flutter_inappwebview_linux/linux/utils/uri.h b/flutter_inappwebview_linux/linux/utils/uri.h deleted file mode 100644 index bdf89570bd..0000000000 --- a/flutter_inappwebview_linux/linux/utils/uri.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_URI_UTIL_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_URI_UTIL_H_ - -#include -#include -#include - -#include "string.h" - -namespace flutter_inappwebview_plugin { - -// Extract origin (scheme + host + port) from a URL -static inline std::string get_origin_from_url(const std::string& url) { - // Try to parse using regex for common URL formats - try { - // Pattern: scheme://host[:port][/path...] - std::regex url_regex(R"(^([a-zA-Z][a-zA-Z0-9+.-]*):\/\/([^:\/\?#]+)(?::(\d+))?)", - std::regex::ECMAScript); - std::smatch match; - - if (std::regex_search(url, match, url_regex)) { - std::string scheme = match[1].str(); - std::string host = match[2].str(); - std::string port_str = match[3].str(); - - std::string origin = scheme + "://" + host; - - if (!port_str.empty()) { - int port = std::stoi(port_str); - // Only add port if it's not the default for the scheme - bool isDefaultPort = (string_equals(scheme, "http") && port == 80) || - (string_equals(scheme, "https") && port == 443); - if (!isDefaultPort) { - origin += ":" + port_str; - } - } - - return origin; - } - } catch (const std::regex_error&) { - // Fallback to simple string parsing - } - - // Fallback: simple string parsing - auto urlSplit = split(url, std::string{"://"}); - if (urlSplit.size() > 1) { - auto scheme = urlSplit[0]; - auto afterScheme = urlSplit[1]; - auto afterSchemeSplit = split(afterScheme, std::string{"/"}); - auto hostPort = afterSchemeSplit[0]; - - // Further split to remove query string if present - auto hostPortSplit = split(hostPort, std::string{"?"}); - hostPort = hostPortSplit[0]; - - return scheme + "://" + hostPort; - } - - return url; -} - -// Check if a URL is valid -static inline bool is_valid_url(const std::string& url) { - if (url.empty()) { - return false; - } - - try { - std::regex url_regex(R"(^[a-zA-Z][a-zA-Z0-9+.-]*:\/\/[^\s]+$)", std::regex::ECMAScript); - return std::regex_match(url, url_regex); - } catch (const std::regex_error&) { - // Fallback: check for basic URL structure - return url.find("://") != std::string::npos; - } -} - -// Extract scheme from URL -static inline std::string get_scheme_from_url(const std::string& url) { - auto pos = url.find("://"); - if (pos != std::string::npos) { - return url.substr(0, pos); - } - return ""; -} - -// Extract host from URL -static inline std::string get_host_from_url(const std::string& url) { - auto urlSplit = split(url, std::string{"://"}); - if (urlSplit.size() > 1) { - auto afterScheme = urlSplit[1]; - auto afterSchemeSplit = split(afterScheme, std::string{"/"}); - auto hostPort = afterSchemeSplit[0]; - - // Remove port if present - auto colonPos = hostPort.find(':'); - if (colonPos != std::string::npos) { - return hostPort.substr(0, colonPos); - } - return hostPort; - } - return ""; -} - -// URL encode a string -static inline std::string url_encode(const std::string& value) { - std::ostringstream escaped; - escaped.fill('0'); - escaped << std::hex; - - for (auto c : value) { - // Keep alphanumeric and other accepted characters intact - if (std::isalnum(static_cast(c)) || c == '-' || c == '_' || c == '.' || - c == '~') { - escaped << c; - } else { - // Percent-encode other characters - escaped << '%' << std::setw(2) << static_cast(static_cast(c)); - } - } - - return escaped.str(); -} - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_URI_UTIL_H_ diff --git a/flutter_inappwebview_linux/linux/utils/util.h b/flutter_inappwebview_linux/linux/utils/util.h deleted file mode 100644 index 95210c5a92..0000000000 --- a/flutter_inappwebview_linux/linux/utils/util.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_H_ - -#include -#include - -#include -#include -#include -#include - -#include - -namespace flutter_inappwebview_plugin { - -// Helper for static_assert in constexpr if -template -inline constexpr bool always_false_v = false; - -template -static inline std::optional make_pointer_optional(const T* value) { - return value == nullptr ? std::nullopt : std::make_optional(*value); -} - -static inline std::string variant_to_string(const std::variant& var) { - return std::visit( - [](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) - return arg; - else if constexpr (std::is_arithmetic_v) - return std::to_string(arg); - else - static_assert(always_false_v, "non-exhaustive visitor!"); - }, - var); -} - -// === Application ID Utilities === -// Used for creating app-specific storage paths (credentials, content filters, etc.) - -static inline bool is_allowed_app_id_char(char c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || - c == '.' || c == '_' || c == '-'; -} - -static inline std::string sanitize_app_id(std::string id) { - std::string out; - out.reserve(id.size()); - - bool last_was_underscore = false; - for (char c : id) { - char mapped = is_allowed_app_id_char(c) ? c : '_'; - if (mapped == '_' && last_was_underscore) { - continue; - } - out.push_back(mapped); - last_was_underscore = (mapped == '_'); - } - - // Trim underscores. - while (!out.empty() && out.front() == '_') { - out.erase(out.begin()); - } - while (!out.empty() && out.back() == '_') { - out.pop_back(); - } - - if (out.size() > 128) { - out.resize(128); - } - if (out.empty()) { - out = "unknown_app"; - } - return out; -} - -static inline std::string resolve_app_id_from_gapplication() { - GApplication* app = g_application_get_default(); - if (app == nullptr) { - return ""; - } - const gchar* id = g_application_get_application_id(app); - if (id == nullptr || id[0] == '\0') { - return ""; - } - return std::string(id); -} - -static inline std::string basename_of_path(const std::string& path) { - if (path.empty()) { - return ""; - } - size_t last_slash = path.find_last_of('/'); - if (last_slash == std::string::npos) { - return path; - } - if (last_slash + 1 >= path.size()) { - return ""; - } - return path.substr(last_slash + 1); -} - -static inline std::string resolve_app_id_from_executable_basename() { - char buf[PATH_MAX + 1]; - ssize_t len = readlink("/proc/self/exe", buf, PATH_MAX); - if (len <= 0) { - return ""; - } - buf[len] = '\0'; - std::string exe_path(buf); - - return basename_of_path(exe_path); -} - -/// Resolves a sanitized application ID for use in storage paths. -/// Tries GApplication ID first, falls back to executable name. -static inline std::string resolve_application_id_sanitized() { - std::string raw = resolve_app_id_from_gapplication(); - if (raw.empty()) { - raw = resolve_app_id_from_executable_basename(); - } - return sanitize_app_id(raw); -} - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_H_ diff --git a/flutter_inappwebview_linux/linux/utils/uuid.h b/flutter_inappwebview_linux/linux/utils/uuid.h deleted file mode 100644 index 9626b4290c..0000000000 --- a/flutter_inappwebview_linux/linux/utils/uuid.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_UUID_UTIL_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_UUID_UTIL_H_ - -#include -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -// Generate a UUID v4 string using standard C++ random -static inline std::string get_uuid() { - static std::random_device rd; - static std::mt19937 gen(rd()); - static std::uniform_int_distribution dis(0, 0xFFFFFFFF); - - uint32_t data1 = dis(gen); - uint16_t data2 = static_cast(dis(gen) & 0xFFFF); - uint16_t data3 = static_cast((dis(gen) & 0x0FFF) | 0x4000); // Version 4 - uint16_t data4 = static_cast((dis(gen) & 0x3FFF) | 0x8000); // Variant 1 - uint32_t data5_hi = dis(gen); - uint16_t data5_lo = static_cast(dis(gen) & 0xFFFF); - - std::ostringstream oss; - oss << std::hex << std::setfill('0') << std::setw(8) << data1 << "-" << std::setw(4) << data2 - << "-" << std::setw(4) << data3 << "-" << std::setw(4) << data4 << "-" << std::setw(8) - << data5_hi << std::setw(4) << data5_lo; - - return oss.str(); -} - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_UUID_UTIL_H_ diff --git a/flutter_inappwebview_linux/linux/utils/vector.h b/flutter_inappwebview_linux/linux/utils/vector.h deleted file mode 100644 index cb8f4c38a6..0000000000 --- a/flutter_inappwebview_linux/linux/utils/vector.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_VECTOR_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_VECTOR_H_ - -#include -#include -#include -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -template -struct is_vector_impl : std::false_type {}; - -template -struct is_vector_impl>::value>> - : std::true_type {}; - -template -struct is_vector_impl< - T, std::enable_if_t::value_type>::iterator>::value>> - : std::true_type {}; - -template -struct is_vector : is_vector_impl::type {}; - -template -static inline void vector_remove(std::vector& vec, const T& el) { - vec.erase(std::remove(vec.begin(), vec.end(), el), vec.end()); -} - -template -static inline void vector_remove_if(std::vector& vec, UnaryPredicate&& predicate) { - vec.erase(std::remove_if(vec.begin(), vec.end(), std::forward(predicate)), - vec.end()); -} - -template -static inline void vector_remove_erase(std::vector& vec, const T& el) { - vec.erase(std::remove(vec.begin(), vec.end(), el), vec.end()); -} - -template -static inline void vector_remove_erase_if(std::vector& vec, UnaryPredicate&& predicate) { - vec.erase(std::remove_if(vec.begin(), vec.end(), std::forward(predicate)), - vec.end()); -} - -template -static inline bool vector_contains(const std::vector& vec, const T& value) { - return std::find(vec.begin(), vec.end(), value) != vec.end(); -} - -template -static inline bool vector_contains_if(const std::vector& vec, UnaryPredicate&& predicate) { - return std::find_if(vec.begin(), vec.end(), std::forward(predicate)) != vec.end(); -} - -template -static inline auto functional_map(Iterator begin, Iterator end, Func&& func) - -> std::vector()))> { - using value_type = decltype(func(std::declval())); - - std::vector out_vector; - out_vector.reserve(std::distance(begin, end)); - - std::transform(begin, end, std::back_inserter(out_vector), std::forward(func)); - - return out_vector; -} - -template -static inline auto functional_map(const T& iterable, Func&& func) - -> std::vector()))> { - return functional_map(std::begin(iterable), std::end(iterable), std::forward(func)); -} - -template -static inline auto functional_map(const std::optional& iterable, Func&& func) - -> std::vector()))> { - if (!iterable.has_value()) { - return {}; - } - return functional_map(iterable.value(), std::forward(func)); -} - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_VECTOR_H_ diff --git a/flutter_inappwebview_linux/linux/web_message/web_message_channel.cc b/flutter_inappwebview_linux/linux/web_message/web_message_channel.cc deleted file mode 100644 index 7763fbd7b1..0000000000 --- a/flutter_inappwebview_linux/linux/web_message/web_message_channel.cc +++ /dev/null @@ -1,151 +0,0 @@ -#include "web_message_channel.h" - -#include - -#include "../in_app_webview/in_app_webview.h" -#include "../utils/flutter.h" -#include "../utils/log.h" - -namespace flutter_inappwebview_plugin { - -namespace { -// Helper to compare method names -bool string_equals(const gchar* a, const char* b) { - return strcmp(a, b) == 0; -} -} // namespace - -WebMessageChannel::WebMessageChannel(FlBinaryMessenger* messenger, - const std::string& channelId, - InAppWebView* webView) - : ChannelDelegate(messenger, std::string(METHOD_CHANNEL_NAME_PREFIX) + channelId), - id_(channelId), - webView_(webView) { -} - -WebMessageChannel::~WebMessageChannel() { - debugLog("dealloc WebMessageChannel"); - webView_ = nullptr; -} - -void WebMessageChannel::dispose() { - unregisterMethodCallHandler(); - webView_ = nullptr; -} - -void WebMessageChannel::HandleMethodCall(FlMethodCall* method_call) { - if (webView_ == nullptr) { - fl_method_call_respond_success(method_call, fl_value_new_null(), nullptr); - return; - } - - const gchar* methodName = fl_method_call_get_name(method_call); - FlValue* args = fl_method_call_get_args(method_call); - - if (string_equals(methodName, "setWebMessageCallback")) { - // Set the onmessage callback for a port - int64_t portIndex = get_fl_map_value(args, "index", 0); - - webView_->setWebMessageCallback(id_, static_cast(portIndex)); - - g_autoptr(FlValue) result = fl_value_new_bool(true); - fl_method_call_respond_success(method_call, result, nullptr); - return; - } - - if (string_equals(methodName, "postMessage")) { - // Post a message on a port - int64_t portIndex = get_fl_map_value(args, "index", 0); - FlValue* message_value = get_fl_map_value_raw(args, "message"); - - std::string messageData = ""; - int64_t messageType = 0; // 0 = string, 1 = arrayBuffer - - if (message_value != nullptr && fl_value_get_type(message_value) == FL_VALUE_TYPE_MAP) { - FlValue* data_value = fl_value_lookup_string(message_value, "data"); - FlValue* type_value = fl_value_lookup_string(message_value, "type"); - - if (data_value != nullptr) { - if (fl_value_get_type(data_value) == FL_VALUE_TYPE_STRING) { - messageData = fl_value_get_string(data_value); - } else if (fl_value_get_type(data_value) == FL_VALUE_TYPE_UINT8_LIST) { - // Convert bytes to comma-separated values for JavaScript - const uint8_t* bytes = fl_value_get_uint8_list(data_value); - size_t length = fl_value_get_length(data_value); - for (size_t i = 0; i < length; i++) { - if (i > 0) messageData += ","; - messageData += std::to_string(bytes[i]); - } - } - } - if (type_value != nullptr && fl_value_get_type(type_value) == FL_VALUE_TYPE_INT) { - messageType = fl_value_get_int(type_value); - } - } - - webView_->postWebMessageOnPort(id_, static_cast(portIndex), messageData, messageType); - - g_autoptr(FlValue) result = fl_value_new_bool(true); - fl_method_call_respond_success(method_call, result, nullptr); - return; - } - - if (string_equals(methodName, "close")) { - // Close a port - int64_t portIndex = get_fl_map_value(args, "index", 0); - - webView_->closeWebMessagePort(id_, static_cast(portIndex)); - - g_autoptr(FlValue) result = fl_value_new_bool(true); - fl_method_call_respond_success(method_call, result, nullptr); - return; - } - - fl_method_call_respond_not_implemented(method_call, nullptr); -} - -void WebMessageChannel::onMessage(int portIndex, const std::string* message, - int64_t messageType) { - if (channel_ == nullptr) { - return; - } - - FlValue* messageMap = nullptr; - if (message != nullptr) { - FlValue* dataValue = nullptr; - if (messageType == 1) { - // ArrayBuffer - convert comma-separated values to byte array - std::vector bytes; - std::string value; - for (char c : *message) { - if (c == ',') { - if (!value.empty()) { - bytes.push_back(static_cast(std::stoi(value))); - value.clear(); - } - } else { - value += c; - } - } - if (!value.empty()) { - bytes.push_back(static_cast(std::stoi(value))); - } - dataValue = fl_value_new_uint8_list(bytes.data(), bytes.size()); - } else { - dataValue = make_fl_value(*message); - } - messageMap = to_fl_map({ - {"data", dataValue}, - {"type", make_fl_value(messageType)}, - }); - } - - g_autoptr(FlValue) args = to_fl_map({ - {"index", make_fl_value(portIndex)}, - {"message", messageMap != nullptr ? messageMap : fl_value_new_null()}, - }); - - invokeMethod("onMessage", args); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/web_message/web_message_channel.h b/flutter_inappwebview_linux/linux/web_message/web_message_channel.h deleted file mode 100644 index 590833fd1d..0000000000 --- a/flutter_inappwebview_linux/linux/web_message/web_message_channel.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_MESSAGE_CHANNEL_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_MESSAGE_CHANNEL_H_ - -#include - -#include -#include - -#include "../types/channel_delegate.h" - -namespace flutter_inappwebview_plugin { - -class InAppWebView; - -/** - * Native C++ representation of a WebMessageChannel. - * - * Each WebMessageChannel has its own MethodChannel for communication - * with the Dart side. This allows the Dart side to call port-specific - * methods like setWebMessageCallback, postMessage, and close. - */ -class WebMessageChannel : public ChannelDelegate { - public: - static constexpr const char* METHOD_CHANNEL_NAME_PREFIX = - "com.pichillilorenzo/flutter_inappwebview_web_message_channel_"; - - WebMessageChannel(FlBinaryMessenger* messenger, const std::string& channelId, - InAppWebView* webView); - ~WebMessageChannel(); - - const std::string& id() const { return id_; } - - /** - * Dispose of this WebMessageChannel, releasing resources and unregistering - * the method call handler. - */ - void dispose(); - - /** - * Send a message to the Dart side on a specific port. - * - * @param portIndex The port index (0 or 1) - * @param message The message data (may be null) - * @param messageType 0 for string, 1 for arrayBuffer - */ - void onMessage(int portIndex, const std::string* message, int64_t messageType); - - // ChannelDelegate override - void HandleMethodCall(FlMethodCall* method_call) override; - - private: - std::string id_; - InAppWebView* webView_; // Weak reference - InAppWebView owns WebMessageChannels -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_MESSAGE_CHANNEL_H_ diff --git a/flutter_inappwebview_linux/linux/web_message/web_message_listener.cc b/flutter_inappwebview_linux/linux/web_message/web_message_listener.cc deleted file mode 100644 index cab66e9a10..0000000000 --- a/flutter_inappwebview_linux/linux/web_message/web_message_listener.cc +++ /dev/null @@ -1,203 +0,0 @@ -#include "web_message_listener.h" - -#include -#include -#include - -#include "../in_app_webview/in_app_webview.h" -#include "../utils/flutter.h" -#include "../utils/log.h" -#include "web_message_listener_channel_delegate.h" - -namespace flutter_inappwebview_plugin { - -std::unique_ptr WebMessageListener::fromFlValue( - FlBinaryMessenger* messenger, - FlValue* map, - InAppWebView* webView) { - if (map == nullptr || fl_value_get_type(map) != FL_VALUE_TYPE_MAP) { - return nullptr; - } - - std::string id = get_fl_map_value(map, "id", ""); - std::string jsObjectName = get_fl_map_value(map, "jsObjectName", ""); - - std::set allowedOriginRules; - FlValue* rules_value = fl_value_lookup_string(map, "allowedOriginRules"); - if (rules_value != nullptr && fl_value_get_type(rules_value) == FL_VALUE_TYPE_LIST) { - size_t length = fl_value_get_length(rules_value); - for (size_t i = 0; i < length; i++) { - FlValue* rule = fl_value_get_list_value(rules_value, i); - if (rule != nullptr && fl_value_get_type(rule) == FL_VALUE_TYPE_STRING) { - allowedOriginRules.insert(fl_value_get_string(rule)); - } - } - } - - if (id.empty() || jsObjectName.empty()) { - errorLog("WebMessageListener::fromFlValue: missing id or jsObjectName"); - return nullptr; - } - - return std::make_unique( - messenger, id, jsObjectName, allowedOriginRules, webView); -} - -WebMessageListener::WebMessageListener(FlBinaryMessenger* messenger, - const std::string& id, - const std::string& jsObjectName, - const std::set& allowedOriginRules, - InAppWebView* webView) - : id_(id), - jsObjectName_(jsObjectName), - allowedOriginRules_(allowedOriginRules), - webView_(webView) { - // Create the channel name following the pattern: - // com.pichillilorenzo/flutter_inappwebview_web_message_listener_{id}_{jsObjectName} - std::string channelName = std::string(METHOD_CHANNEL_NAME_PREFIX) + id + "_" + jsObjectName; - - channelDelegate_ = std::make_unique( - this, messenger, channelName); -} - -WebMessageListener::~WebMessageListener() { - debugLog("dealloc WebMessageListener"); - dispose(); -} - -bool WebMessageListener::isOriginAllowed(const std::string& scheme, - const std::string& host, - int port) const { - for (const auto& rule : allowedOriginRules_) { - // Wildcard matches all origins - if (rule == "*") { - return true; - } - - // Skip empty rules - if (rule.empty()) { - continue; - } - - // Parse the rule: scheme://host[:port] - size_t schemeEnd = rule.find("://"); - if (schemeEnd == std::string::npos) { - continue; - } - - std::string ruleScheme = rule.substr(0, schemeEnd); - std::string rest = rule.substr(schemeEnd + 3); - - std::string ruleHost; - int rulePort = 0; - - size_t portStart = rest.find(':'); - if (portStart != std::string::npos) { - ruleHost = rest.substr(0, portStart); - try { - rulePort = std::stoi(rest.substr(portStart + 1)); - } catch (...) { - rulePort = 0; - } - } else { - ruleHost = rest; - } - - // Normalize ports (use default for scheme if not specified) - int normalizedRulePort = rulePort; - if (normalizedRulePort == 0) { - normalizedRulePort = (ruleScheme == "https") ? 443 : 80; - } - - int normalizedPort = port; - if (normalizedPort == 0) { - normalizedPort = (scheme == "https") ? 443 : 80; - } - - // Check scheme match - if (scheme != ruleScheme) { - continue; - } - - // Check port match - if (normalizedPort != normalizedRulePort) { - continue; - } - - // Check host match (including wildcard subdomain matching) - if (ruleHost.empty() || host == ruleHost) { - return true; - } - - // Handle wildcard subdomain matching: *.example.com - if (ruleHost.size() > 2 && ruleHost[0] == '*' && ruleHost[1] == '.') { - std::string suffix = ruleHost.substr(1); // .example.com - if (host.size() > suffix.size() && - host.compare(host.size() - suffix.size(), suffix.size(), suffix) == 0) { - return true; - } - } - } - - return false; -} - -void WebMessageListener::onPostMessage(const std::string* messageData, - int64_t messageType, - const std::string& sourceOrigin, - bool isMainFrame) { - if (channelDelegate_ == nullptr) { - return; - } - - // Parse the origin to check if it's allowed - std::string scheme; - std::string host; - int port = 0; - - if (!sourceOrigin.empty()) { - size_t schemeEnd = sourceOrigin.find("://"); - if (schemeEnd != std::string::npos) { - scheme = sourceOrigin.substr(0, schemeEnd); - std::string rest = sourceOrigin.substr(schemeEnd + 3); - - size_t portStart = rest.find(':'); - size_t pathStart = rest.find('/'); - - if (portStart != std::string::npos && (pathStart == std::string::npos || portStart < pathStart)) { - host = rest.substr(0, portStart); - size_t portEnd = (pathStart != std::string::npos) ? pathStart : rest.size(); - try { - port = std::stoi(rest.substr(portStart + 1, portEnd - portStart - 1)); - } catch (...) { - port = 0; - } - } else if (pathStart != std::string::npos) { - host = rest.substr(0, pathStart); - } else { - host = rest; - } - } - } - - // Check if this origin is allowed (unless origin is empty/about:blank) - if (!sourceOrigin.empty() && sourceOrigin != "null") { - if (!isOriginAllowed(scheme, host, port)) { - debugLog("WebMessageListener: Origin not allowed: " + sourceOrigin); - return; - } - } - - // Invoke the callback on the Dart side via the dedicated channel - channelDelegate_->onPostMessage(messageData, messageType, &sourceOrigin, isMainFrame); -} - -void WebMessageListener::dispose() { - if (channelDelegate_) { - channelDelegate_->dispose(); - channelDelegate_.reset(); - } - webView_ = nullptr; -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/web_message/web_message_listener.h b/flutter_inappwebview_linux/linux/web_message/web_message_listener.h deleted file mode 100644 index b5a105a2b1..0000000000 --- a/flutter_inappwebview_linux/linux/web_message/web_message_listener.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_MESSAGE_LISTENER_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_MESSAGE_LISTENER_H_ - -#include - -#include -#include -#include - -namespace flutter_inappwebview_plugin { - -class InAppWebView; -class WebMessageListenerChannelDelegate; - -/** - * Native C++ representation of a WebMessageListener. - * - * Each WebMessageListener has its own MethodChannel for communication - * with the Dart side. This follows the federated plugin pattern where - * callbacks are routed through a dedicated channel (not the main WebView channel). - * - * Channel name pattern: - * com.pichillilorenzo/flutter_inappwebview_web_message_listener_{id}_{jsObjectName} - * - * This matches the iOS/Android architecture where: - * - WebMessageListener is a native class with its own channelDelegate - * - onPostMessage callbacks go directly to Dart via the dedicated channel - * - postMessage (reply) is handled via the dedicated channel - */ -class WebMessageListener { - public: - static constexpr const char* METHOD_CHANNEL_NAME_PREFIX = - "com.pichillilorenzo/flutter_inappwebview_web_message_listener_"; - - /** - * Create a WebMessageListener from a Flutter map value. - * - * Expected map structure: - * - id: String - unique identifier for this listener - * - jsObjectName: String - name of the JS object injected into pages - * - allowedOriginRules: List - origin rules for allowed sources - */ - static std::unique_ptr fromFlValue( - FlBinaryMessenger* messenger, - FlValue* map, - InAppWebView* webView); - - WebMessageListener(FlBinaryMessenger* messenger, - const std::string& id, - const std::string& jsObjectName, - const std::set& allowedOriginRules, - InAppWebView* webView); - ~WebMessageListener(); - - const std::string& id() const { return id_; } - const std::string& jsObjectName() const { return jsObjectName_; } - const std::set& allowedOriginRules() const { return allowedOriginRules_; } - WebMessageListenerChannelDelegate* channelDelegate() const { return channelDelegate_.get(); } - - /** - * Check if the given origin is allowed by the origin rules. - * - * @param scheme URL scheme (e.g., "https") - * @param host Hostname (e.g., "example.com") - * @param port Port number (0 for default) - * @return true if the origin is allowed - */ - bool isOriginAllowed(const std::string& scheme, - const std::string& host, - int port) const; - - /** - * Called when JavaScript posts a message through this listener. - * Routes the callback to Dart via the dedicated channel. - * - * @param messageData The message data (string or array buffer as JSON) - * @param messageType 0 for string, 1 for arrayBuffer - * @param sourceOrigin The origin URL that sent the message - * @param isMainFrame Whether the message came from the main frame - */ - void onPostMessage(const std::string* messageData, - int64_t messageType, - const std::string& sourceOrigin, - bool isMainFrame); - - /** - * Dispose of this WebMessageListener, releasing resources. - */ - void dispose(); - - // Allow channel delegate to access webView_ - friend class WebMessageListenerChannelDelegate; - - // Public accessor for webView (needed by channel delegate) - InAppWebView* webView() const { return webView_; } - - private: - std::string id_; - std::string jsObjectName_; - std::set allowedOriginRules_; - InAppWebView* webView_; // Weak reference - InAppWebView owns WebMessageListeners - std::unique_ptr channelDelegate_; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_MESSAGE_LISTENER_H_ diff --git a/flutter_inappwebview_linux/linux/web_message/web_message_listener_channel_delegate.cc b/flutter_inappwebview_linux/linux/web_message/web_message_listener_channel_delegate.cc deleted file mode 100644 index 6d3753ec99..0000000000 --- a/flutter_inappwebview_linux/linux/web_message/web_message_listener_channel_delegate.cc +++ /dev/null @@ -1,195 +0,0 @@ -#include "web_message_listener_channel_delegate.h" - -#include - -#include "../in_app_webview/in_app_webview.h" -#include "../utils/flutter.h" -#include "../utils/log.h" -#include "web_message_listener.h" - -namespace flutter_inappwebview_plugin { - -namespace { -// Helper to compare method names -bool string_equals(const gchar* a, const char* b) { - return strcmp(a, b) == 0; -} -} // namespace - -WebMessageListenerChannelDelegate::WebMessageListenerChannelDelegate( - WebMessageListener* webMessageListener, - FlBinaryMessenger* messenger, - const std::string& channelName) - : ChannelDelegate(messenger, channelName), - webMessageListener_(webMessageListener) { -} - -WebMessageListenerChannelDelegate::~WebMessageListenerChannelDelegate() { - debugLog("dealloc WebMessageListenerChannelDelegate"); - webMessageListener_ = nullptr; -} - -void WebMessageListenerChannelDelegate::HandleMethodCall(FlMethodCall* method_call) { - if (webMessageListener_ == nullptr) { - fl_method_call_respond_success(method_call, fl_value_new_null(), nullptr); - return; - } - - const gchar* methodName = fl_method_call_get_name(method_call); - FlValue* args = fl_method_call_get_args(method_call); - - if (string_equals(methodName, "postMessage")) { - // Handle reply from Dart to JavaScript - // This is called when JavaScriptReplyProxy.postMessage() is invoked on the Dart side - - InAppWebView* webView = webMessageListener_->webView(); - if (webView == nullptr || webView->webview() == nullptr) { - g_autoptr(FlValue) result = fl_value_new_bool(false); - fl_method_call_respond_success(method_call, result, nullptr); - return; - } - - FlValue* message_value = get_fl_map_value_raw(args, "message"); - - std::string messageData = ""; - int64_t messageType = 0; // 0 = string, 1 = arrayBuffer - - if (message_value != nullptr && fl_value_get_type(message_value) == FL_VALUE_TYPE_MAP) { - FlValue* data_value = fl_value_lookup_string(message_value, "data"); - FlValue* type_value = fl_value_lookup_string(message_value, "type"); - - if (data_value != nullptr) { - if (fl_value_get_type(data_value) == FL_VALUE_TYPE_STRING) { - messageData = fl_value_get_string(data_value); - } else if (fl_value_get_type(data_value) == FL_VALUE_TYPE_UINT8_LIST) { - // Convert bytes to comma-separated values for JavaScript - const uint8_t* bytes = fl_value_get_uint8_list(data_value); - size_t length = fl_value_get_length(data_value); - for (size_t i = 0; i < length; i++) { - if (i > 0) messageData += ","; - messageData += std::to_string(bytes[i]); - } - } - } - if (type_value != nullptr && fl_value_get_type(type_value) == FL_VALUE_TYPE_INT) { - messageType = fl_value_get_int(type_value); - } - } - - // Build the JavaScript message expression - std::string messageDataJs; - if (messageType == 1) { - // ArrayBuffer - messageData contains comma-separated byte values - messageDataJs = "new Uint8Array([" + messageData + "]).buffer"; - } else { - // String - escape for JavaScript - std::string escaped; - escaped.reserve(messageData.size() * 2); - for (char c : messageData) { - switch (c) { - case '\\': escaped += "\\\\"; break; - case '"': escaped += "\\\""; break; - case '\n': escaped += "\\n"; break; - case '\r': escaped += "\\r"; break; - case '\t': escaped += "\\t"; break; - default: escaped += c; break; - } - } - messageDataJs = "\"" + escaped + "\""; - } - - // Escape the jsObjectName for JavaScript - std::string jsObjectNameEscaped = webMessageListener_->jsObjectName(); - size_t pos = 0; - while ((pos = jsObjectNameEscaped.find("'", pos)) != std::string::npos) { - jsObjectNameEscaped.replace(pos, 1, "\\'"); - pos += 2; - } - - // Build JavaScript to dispatch message to the listener's callbacks - // This matches iOS WebMessageListenerChannelDelegate.postMessage behavior - std::string js = R"JS( -(function() { - var webMessageListener = window[')JS" + jsObjectNameEscaped + R"JS(']; - if (webMessageListener != null) { - var event = {data: )JS" + messageDataJs + R"JS(}; - if (webMessageListener.onmessage != null) { - webMessageListener.onmessage(event); - } - for (var listener of webMessageListener.listeners) { - listener(event); - } - } -})(); -)JS"; - - // Execute the JavaScript - webView->evaluateJavascript(js, std::nullopt, nullptr); - - g_autoptr(FlValue) result = fl_value_new_bool(true); - fl_method_call_respond_success(method_call, result, nullptr); - return; - } - - fl_method_call_respond_not_implemented(method_call, nullptr); -} - -void WebMessageListenerChannelDelegate::onPostMessage(const std::string* messageData, - int64_t messageType, - const std::string* sourceOrigin, - bool isMainFrame) const { - if (channel_ == nullptr) { - return; - } - - // Build message map if there's message data - FlValue* messageMap = nullptr; - if (messageData != nullptr) { - FlValue* dataValue = nullptr; - if (messageType == 1) { - // ArrayBuffer - convert comma-separated values to byte array - std::vector bytes; - std::string value; - for (char c : *messageData) { - if (c == ',') { - if (!value.empty()) { - try { - bytes.push_back(static_cast(std::stoi(value))); - } catch (...) {} - value.clear(); - } - } else { - value += c; - } - } - if (!value.empty()) { - try { - bytes.push_back(static_cast(std::stoi(value))); - } catch (...) {} - } - dataValue = fl_value_new_uint8_list(bytes.data(), bytes.size()); - } else { - dataValue = make_fl_value(*messageData); - } - messageMap = to_fl_map({ - {"data", dataValue}, - {"type", make_fl_value(messageType)}, - }); - } - - g_autoptr(FlValue) args = to_fl_map({ - {"message", messageMap != nullptr ? messageMap : fl_value_new_null()}, - {"sourceOrigin", sourceOrigin != nullptr ? make_fl_value(*sourceOrigin) : fl_value_new_null()}, - {"isMainFrame", make_fl_value(isMainFrame)}, - }); - - invokeMethod("onPostMessage", args); -} - -void WebMessageListenerChannelDelegate::dispose() { - debugLog("WebMessageListenerChannelDelegate::dispose"); - unregisterMethodCallHandler(); - webMessageListener_ = nullptr; -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/web_message/web_message_listener_channel_delegate.h b/flutter_inappwebview_linux/linux/web_message/web_message_listener_channel_delegate.h deleted file mode 100644 index 53d2403977..0000000000 --- a/flutter_inappwebview_linux/linux/web_message/web_message_listener_channel_delegate.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_MESSAGE_LISTENER_CHANNEL_DELEGATE_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_MESSAGE_LISTENER_CHANNEL_DELEGATE_H_ - -#include - -#include -#include - -#include "../types/channel_delegate.h" - -namespace flutter_inappwebview_plugin { - -class WebMessageListener; - -/** - * Channel delegate for WebMessageListener. - * - * Handles method calls from Dart (like postMessage for replies) - * and invokes callbacks to Dart (like onPostMessage when JS posts a message). - * - * This follows the federated plugin pattern matching iOS/Android: - * - Dedicated MethodChannel per WebMessageListener instance - * - Channel name: com.pichillilorenzo/flutter_inappwebview_web_message_listener_{id}_{jsObjectName} - */ -class WebMessageListenerChannelDelegate : public ChannelDelegate { - public: - WebMessageListenerChannelDelegate(WebMessageListener* webMessageListener, - FlBinaryMessenger* messenger, - const std::string& channelName); - ~WebMessageListenerChannelDelegate() override; - - /** - * Handle method calls from Dart. - * Currently handles: - * - postMessage: Send a reply message from native to JavaScript - */ - void HandleMethodCall(FlMethodCall* method_call) override; - - /** - * Invoke onPostMessage callback on the Dart side. - * Called when JavaScript posts a message through the WebMessageListener. - * - * @param messageData The message data (may be null) - * @param messageType 0 for string, 1 for arrayBuffer - * @param sourceOrigin The origin URL that sent the message (may be null) - * @param isMainFrame Whether the message came from the main frame - */ - void onPostMessage(const std::string* messageData, - int64_t messageType, - const std::string* sourceOrigin, - bool isMainFrame) const; - - void dispose(); - - private: - WebMessageListener* webMessageListener_; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_MESSAGE_LISTENER_CHANNEL_DELEGATE_H_ diff --git a/flutter_inappwebview_linux/linux/web_storage_manager.cc b/flutter_inappwebview_linux/linux/web_storage_manager.cc deleted file mode 100644 index cb73773237..0000000000 --- a/flutter_inappwebview_linux/linux/web_storage_manager.cc +++ /dev/null @@ -1,373 +0,0 @@ -#include "web_storage_manager.h" - -#include - -#include "plugin_instance.h" -#include "utils/flutter.h" -#include "utils/log.h" - -namespace flutter_inappwebview_plugin { - -namespace { -// Helper to compare method names -bool string_equals(const gchar* a, const char* b) { - return strcmp(a, b) == 0; -} -} // namespace - -WebStorageManager::WebStorageManager(PluginInstance* plugin) - : plugin_(plugin), channel_(nullptr), data_manager_(nullptr) { - // Get the binary messenger from the plugin - FlBinaryMessenger* messenger = plugin_->messenger(); - - // Create the method channel - channel_ = fl_method_channel_new( - messenger, - "com.pichillilorenzo/flutter_inappwebview_webstoragemanager", - FL_METHOD_CODEC(fl_standard_method_codec_new())); - - // Set the method call handler - fl_method_channel_set_method_call_handler( - channel_, HandleMethodCall, this, nullptr); - - // Get the default website data manager from the network session - WebKitNetworkSession* session = webkit_network_session_get_default(); - if (session != nullptr) { - data_manager_ = webkit_network_session_get_website_data_manager(session); - // data_manager_ is owned by session, don't unref it - } -} - -WebStorageManager::~WebStorageManager() { - if (channel_ != nullptr) { - fl_method_channel_set_method_call_handler(channel_, nullptr, nullptr, nullptr); - g_object_unref(channel_); - channel_ = nullptr; - } - // data_manager_ is owned by the network session, don't unref it - data_manager_ = nullptr; - plugin_ = nullptr; -} - -void WebStorageManager::HandleMethodCall(FlMethodChannel* channel, - FlMethodCall* method_call, - gpointer user_data) { - auto* self = static_cast(user_data); - const gchar* method = fl_method_call_get_name(method_call); - - if (string_equals(method, "fetchDataRecords")) { - self->fetchDataRecords(method_call); - } else if (string_equals(method, "removeDataFor")) { - self->removeDataFor(method_call); - } else if (string_equals(method, "removeDataModifiedSince")) { - self->removeDataModifiedSince(method_call); - } else { - fl_method_call_respond_not_implemented(method_call, nullptr); - } -} - -WebKitWebsiteDataTypes WebStorageManager::parseDataTypes(FlValue* dataTypesValue) { - WebKitWebsiteDataTypes types = static_cast(0); - - if (dataTypesValue == nullptr || - fl_value_get_type(dataTypesValue) != FL_VALUE_TYPE_LIST) { - return types; - } - - size_t length = fl_value_get_length(dataTypesValue); - for (size_t i = 0; i < length; i++) { - FlValue* item = fl_value_get_list_value(dataTypesValue, i); - if (fl_value_get_type(item) != FL_VALUE_TYPE_STRING) { - continue; - } - - const char* typeStr = fl_value_get_string(item); - - if (strcmp(typeStr, "WEBKIT_WEBSITE_DATA_DISK_CACHE") == 0) { - types = static_cast(types | WEBKIT_WEBSITE_DATA_DISK_CACHE); - } else if (strcmp(typeStr, "WEBKIT_WEBSITE_DATA_MEMORY_CACHE") == 0) { - types = static_cast(types | WEBKIT_WEBSITE_DATA_MEMORY_CACHE); - } else if (strcmp(typeStr, "WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE") == 0) { - types = static_cast(types | WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE); - } else if (strcmp(typeStr, "WEBKIT_WEBSITE_DATA_COOKIES") == 0) { - types = static_cast(types | WEBKIT_WEBSITE_DATA_COOKIES); - } else if (strcmp(typeStr, "WEBKIT_WEBSITE_DATA_SESSION_STORAGE") == 0) { - types = static_cast(types | WEBKIT_WEBSITE_DATA_SESSION_STORAGE); - } else if (strcmp(typeStr, "WEBKIT_WEBSITE_DATA_LOCAL_STORAGE") == 0) { - types = static_cast(types | WEBKIT_WEBSITE_DATA_LOCAL_STORAGE); - } else if (strcmp(typeStr, "WEBKIT_WEBSITE_DATA_INDEXEDDB_DATABASES") == 0) { - types = static_cast(types | WEBKIT_WEBSITE_DATA_INDEXEDDB_DATABASES); - } else if (strcmp(typeStr, "WEBKIT_WEBSITE_DATA_SERVICE_WORKER_REGISTRATIONS") == 0) { - types = static_cast(types | WEBKIT_WEBSITE_DATA_SERVICE_WORKER_REGISTRATIONS); - } - } - - return types; -} - -FlValue* WebStorageManager::dataTypesToFlValue(WebKitWebsiteDataTypes types) { - g_autoptr(FlValue) list = fl_value_new_list(); - - if (types & WEBKIT_WEBSITE_DATA_DISK_CACHE) { - fl_value_append_take(list, fl_value_new_string("WEBKIT_WEBSITE_DATA_DISK_CACHE")); - } - if (types & WEBKIT_WEBSITE_DATA_MEMORY_CACHE) { - fl_value_append_take(list, fl_value_new_string("WEBKIT_WEBSITE_DATA_MEMORY_CACHE")); - } - if (types & WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE) { - fl_value_append_take(list, fl_value_new_string("WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE")); - } - if (types & WEBKIT_WEBSITE_DATA_COOKIES) { - fl_value_append_take(list, fl_value_new_string("WEBKIT_WEBSITE_DATA_COOKIES")); - } - if (types & WEBKIT_WEBSITE_DATA_SESSION_STORAGE) { - fl_value_append_take(list, fl_value_new_string("WEBKIT_WEBSITE_DATA_SESSION_STORAGE")); - } - if (types & WEBKIT_WEBSITE_DATA_LOCAL_STORAGE) { - fl_value_append_take(list, fl_value_new_string("WEBKIT_WEBSITE_DATA_LOCAL_STORAGE")); - } - if (types & WEBKIT_WEBSITE_DATA_INDEXEDDB_DATABASES) { - fl_value_append_take(list, fl_value_new_string("WEBKIT_WEBSITE_DATA_INDEXEDDB_DATABASES")); - } - if (types & WEBKIT_WEBSITE_DATA_SERVICE_WORKER_REGISTRATIONS) { - fl_value_append_take(list, fl_value_new_string("WEBKIT_WEBSITE_DATA_SERVICE_WORKER_REGISTRATIONS")); - } - - return fl_value_ref(list); -} - -void WebStorageManager::fetchDataRecords(FlMethodCall* method_call) { - FlValue* args = fl_method_call_get_args(method_call); - FlValue* dataTypesValue = fl_value_lookup_string(args, "dataTypes"); - - WebKitWebsiteDataTypes types = parseDataTypes(dataTypesValue); - - // Store method_call for async callback - g_object_ref(method_call); - - webkit_website_data_manager_fetch( - data_manager_, - types, - nullptr, // GCancellable - [](GObject* source_object, GAsyncResult* res, gpointer user_data) { - auto* method_call = static_cast(user_data); - auto* data_manager = WEBKIT_WEBSITE_DATA_MANAGER(source_object); - - GError* error = nullptr; - GList* records = webkit_website_data_manager_fetch_finish( - data_manager, res, &error); - - if (error != nullptr) { - fl_method_call_respond_error( - method_call, - "FETCH_ERROR", - error->message, - nullptr, - nullptr); - g_error_free(error); - g_object_unref(method_call); - return; - } - - g_autoptr(FlValue) result = fl_value_new_list(); - - for (GList* l = records; l != nullptr; l = l->next) { - WebKitWebsiteData* data = static_cast(l->data); - const char* name = webkit_website_data_get_name(data); - WebKitWebsiteDataTypes dataTypes = webkit_website_data_get_types(data); - - g_autoptr(FlValue) record = (name != nullptr) - ? to_fl_map({ - {"displayName", make_fl_value(name)}, - {"dataTypes", WebStorageManager::dataTypesToFlValue(dataTypes)}, - }) - : to_fl_map({ - {"dataTypes", WebStorageManager::dataTypesToFlValue(dataTypes)}, - }); - - fl_value_append(result, record); - } - - g_list_free_full(records, reinterpret_cast(webkit_website_data_unref)); - - fl_method_call_respond_success(method_call, result, nullptr); - g_object_unref(method_call); - }, - method_call); -} - -void WebStorageManager::removeDataFor(FlMethodCall* method_call) { - FlValue* args = fl_method_call_get_args(method_call); - FlValue* dataTypesValue = fl_value_lookup_string(args, "dataTypes"); - FlValue* recordListValue = fl_value_lookup_string(args, "recordList"); - - WebKitWebsiteDataTypes types = parseDataTypes(dataTypesValue); - - if (recordListValue == nullptr || - fl_value_get_type(recordListValue) != FL_VALUE_TYPE_LIST || - fl_value_get_length(recordListValue) == 0) { - // No records to delete - fl_method_call_respond_success(method_call, fl_value_new_bool(TRUE), nullptr); - return; - } - - // Extract display names from the record list - std::vector displayNames; - size_t length = fl_value_get_length(recordListValue); - for (size_t i = 0; i < length; i++) { - FlValue* record = fl_value_get_list_value(recordListValue, i); - FlValue* displayNameValue = fl_value_lookup_string(record, "displayName"); - if (displayNameValue != nullptr && - fl_value_get_type(displayNameValue) == FL_VALUE_TYPE_STRING) { - displayNames.push_back(fl_value_get_string(displayNameValue)); - } - } - - if (displayNames.empty()) { - fl_method_call_respond_success(method_call, fl_value_new_bool(TRUE), nullptr); - return; - } - - // We need to first fetch records to get WebKitWebsiteData pointers, - // then remove matching ones - struct RemoveContext { - FlMethodCall* method_call; - WebKitWebsiteDataManager* data_manager; - WebKitWebsiteDataTypes types; - std::vector displayNames; - }; - - auto* ctx = new RemoveContext{method_call, data_manager_, types, std::move(displayNames)}; - g_object_ref(method_call); - - webkit_website_data_manager_fetch( - data_manager_, - types, - nullptr, - [](GObject* source_object, GAsyncResult* res, gpointer user_data) { - auto* ctx = static_cast(user_data); - auto* data_manager = WEBKIT_WEBSITE_DATA_MANAGER(source_object); - - GError* error = nullptr; - GList* all_records = webkit_website_data_manager_fetch_finish( - data_manager, res, &error); - - if (error != nullptr) { - fl_method_call_respond_error( - ctx->method_call, "FETCH_ERROR", error->message, nullptr, nullptr); - g_error_free(error); - g_object_unref(ctx->method_call); - delete ctx; - return; - } - - // Find matching records - GList* matching_records = nullptr; - for (GList* l = all_records; l != nullptr; l = l->next) { - WebKitWebsiteData* data = static_cast(l->data); - const char* name = webkit_website_data_get_name(data); - if (name != nullptr) { - for (const auto& displayName : ctx->displayNames) { - if (displayName == name) { - matching_records = g_list_prepend(matching_records, - webkit_website_data_ref(data)); - break; - } - } - } - } - - g_list_free_full(all_records, - reinterpret_cast(webkit_website_data_unref)); - - if (matching_records == nullptr) { - fl_method_call_respond_success(ctx->method_call, - fl_value_new_bool(TRUE), nullptr); - g_object_unref(ctx->method_call); - delete ctx; - return; - } - - // Now remove the matching records - webkit_website_data_manager_remove( - ctx->data_manager, - ctx->types, - matching_records, - nullptr, - [](GObject* source_object, GAsyncResult* res, gpointer user_data) { - auto* ctx = static_cast(user_data); - auto* data_manager = WEBKIT_WEBSITE_DATA_MANAGER(source_object); - - GError* error = nullptr; - gboolean success = webkit_website_data_manager_remove_finish( - data_manager, res, &error); - - if (error != nullptr) { - fl_method_call_respond_error( - ctx->method_call, "REMOVE_ERROR", error->message, nullptr, nullptr); - g_error_free(error); - } else { - fl_method_call_respond_success(ctx->method_call, - fl_value_new_bool(success), nullptr); - } - - g_object_unref(ctx->method_call); - delete ctx; - }, - ctx); - - g_list_free_full(matching_records, - reinterpret_cast(webkit_website_data_unref)); - }, - ctx); -} - -void WebStorageManager::removeDataModifiedSince(FlMethodCall* method_call) { - FlValue* args = fl_method_call_get_args(method_call); - FlValue* dataTypesValue = fl_value_lookup_string(args, "dataTypes"); - FlValue* timestampValue = fl_value_lookup_string(args, "timestamp"); - - WebKitWebsiteDataTypes types = parseDataTypes(dataTypesValue); - - // Get timestamp (seconds since epoch) - gint64 timestamp = 0; - if (timestampValue != nullptr && - fl_value_get_type(timestampValue) == FL_VALUE_TYPE_INT) { - timestamp = fl_value_get_int(timestampValue); - } - - // Convert to GDateTime - GDateTime* datetime = g_date_time_new_from_unix_utc(timestamp); - GTimeSpan timespan = g_date_time_to_unix(datetime); - g_date_time_unref(datetime); - - g_object_ref(method_call); - - webkit_website_data_manager_clear( - data_manager_, - types, - timespan, - nullptr, // GCancellable - [](GObject* source_object, GAsyncResult* res, gpointer user_data) { - auto* method_call = static_cast(user_data); - auto* data_manager = WEBKIT_WEBSITE_DATA_MANAGER(source_object); - - GError* error = nullptr; - gboolean success = webkit_website_data_manager_clear_finish( - data_manager, res, &error); - - if (error != nullptr) { - fl_method_call_respond_error( - method_call, "CLEAR_ERROR", error->message, nullptr, nullptr); - g_error_free(error); - } else { - fl_method_call_respond_success(method_call, - fl_value_new_bool(success), nullptr); - } - - g_object_unref(method_call); - }, - method_call); -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/web_storage_manager.h b/flutter_inappwebview_linux/linux/web_storage_manager.h deleted file mode 100644 index 6cd7e2f97b..0000000000 --- a/flutter_inappwebview_linux/linux/web_storage_manager.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_LINUX_WEB_STORAGE_MANAGER_H_ -#define FLUTTER_INAPPWEBVIEW_LINUX_WEB_STORAGE_MANAGER_H_ - -#include -#include - -#include -#include - -namespace flutter_inappwebview_plugin { - -class PluginInstance; - -/// WebStorageManager handles website data management using WPE WebKit's -/// WebKitWebsiteDataManager API. -class WebStorageManager { - public: - /// Creates a new WebStorageManager. - /// @param plugin The plugin instance for accessing messenger. - explicit WebStorageManager(PluginInstance* plugin); - ~WebStorageManager(); - - /// Get the plugin instance - PluginInstance* plugin() const { return plugin_; } - - // Prevent copying - WebStorageManager(const WebStorageManager&) = delete; - WebStorageManager& operator=(const WebStorageManager&) = delete; - - private: - PluginInstance* plugin_ = nullptr; - - /// Handle method calls from Flutter. - static void HandleMethodCall(FlMethodChannel* channel, - FlMethodCall* method_call, - gpointer user_data); - - /// Fetch website data records. - void fetchDataRecords(FlMethodCall* method_call); - - /// Remove data for specific records. - void removeDataFor(FlMethodCall* method_call); - - /// Remove data modified since a specific date. - void removeDataModifiedSince(FlMethodCall* method_call); - - /// Convert string list to WebKitWebsiteDataTypes bitmask. - static WebKitWebsiteDataTypes parseDataTypes(FlValue* dataTypesValue); - - /// Convert WebKitWebsiteDataTypes bitmask to string list. - static FlValue* dataTypesToFlValue(WebKitWebsiteDataTypes types); - - /// The Flutter method channel. - FlMethodChannel* channel_; - - /// The website data manager. - WebKitWebsiteDataManager* data_manager_; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_LINUX_WEB_STORAGE_MANAGER_H_ diff --git a/flutter_inappwebview_linux/linux/webview_environment.cc b/flutter_inappwebview_linux/linux/webview_environment.cc deleted file mode 100644 index 2340139551..0000000000 --- a/flutter_inappwebview_linux/linux/webview_environment.cc +++ /dev/null @@ -1,281 +0,0 @@ -#include "webview_environment.h" - -#include - -#include -#include - -#include "plugin_instance.h" -#include "utils/flutter.h" -#include "utils/log.h" - -namespace flutter_inappwebview_plugin { - -namespace { -// Helper to compare method names -bool string_equals(const gchar* a, const char* b) { - return strcmp(a, b) == 0; -} -} // namespace - -// ============================================================================ -// WebViewEnvironmentInstanceChannelDelegate Implementation -// ============================================================================ - -WebViewEnvironmentInstanceChannelDelegate::WebViewEnvironmentInstanceChannelDelegate( - FlBinaryMessenger* messenger, - const std::string& id, - std::function disposeCallback) - : ChannelDelegate(messenger, - "com.pichillilorenzo/flutter_webview_environment_" + id), - id_(id), - disposeCallback_(std::move(disposeCallback)) {} - -WebViewEnvironmentInstanceChannelDelegate::~WebViewEnvironmentInstanceChannelDelegate() { - debugLog("dealloc WebViewEnvironmentInstanceChannelDelegate id=" + id_); - if (context_ != nullptr) { - g_object_unref(context_); - context_ = nullptr; - } -} - -void WebViewEnvironmentInstanceChannelDelegate::HandleMethodCall(FlMethodCall* method_call) { - const gchar* method = fl_method_call_get_name(method_call); - - if (string_equals(method, "dispose")) { - // Dispose this instance - call the callback to remove from parent's map - disposeCallback_(id_); - fl_method_call_respond_success(method_call, fl_value_new_null(), nullptr); - } else if (string_equals(method, "isSpellCheckingEnabled")) { - bool enabled = isSpellCheckingEnabled(); - fl_method_call_respond_success(method_call, fl_value_new_bool(enabled), nullptr); - } else if (string_equals(method, "getSpellCheckingLanguages")) { - auto languages = getSpellCheckingLanguages(); - FlValue* list = fl_value_new_list(); - for (const auto& lang : languages) { - fl_value_append_take(list, fl_value_new_string(lang.c_str())); - } - fl_method_call_respond_success(method_call, list, nullptr); - } else if (string_equals(method, "getCacheModel")) { - int model = getCacheModel(); - fl_method_call_respond_success(method_call, fl_value_new_int(model), nullptr); - } else if (string_equals(method, "isAutomationAllowed")) { - bool allowed = isAutomationAllowed(); - fl_method_call_respond_success(method_call, fl_value_new_bool(allowed), nullptr); - } else { - fl_method_call_respond_not_implemented(method_call, nullptr); - } -} - -bool WebViewEnvironmentInstanceChannelDelegate::isSpellCheckingEnabled() const { - if (context_ == nullptr) { - return false; - } - return webkit_web_context_get_spell_checking_enabled(context_); -} - -std::vector WebViewEnvironmentInstanceChannelDelegate::getSpellCheckingLanguages() const { - std::vector result; - if (context_ == nullptr) { - return result; - } - const gchar* const* languages = webkit_web_context_get_spell_checking_languages(context_); - if (languages != nullptr) { - for (int i = 0; languages[i] != nullptr; i++) { - result.push_back(std::string(languages[i])); - } - } - return result; -} - -int WebViewEnvironmentInstanceChannelDelegate::getCacheModel() const { - if (context_ == nullptr) { - return 1; // Default: WEBKIT_CACHE_MODEL_WEB_BROWSER - } - return static_cast(webkit_web_context_get_cache_model(context_)); -} - -bool WebViewEnvironmentInstanceChannelDelegate::isAutomationAllowed() const { - if (context_ == nullptr) { - return false; - } - return webkit_web_context_is_automation_allowed(context_); -} - -// ============================================================================ -// WebViewEnvironment Implementation -// ============================================================================ - -WebKitWebContext* WebViewEnvironment::getWebContext(const std::string& id) const { - if (id.empty()) { - return nullptr; - } - auto* delegate = getInstance(id); - if (delegate == nullptr) { - return nullptr; - } - return delegate->context(); -} - -WebViewEnvironment::WebViewEnvironment(PluginInstance* plugin) - : ChannelDelegate(plugin->messenger(), METHOD_CHANNEL_NAME), - plugin_(plugin), - messenger_(plugin->messenger()) {} - -WebViewEnvironment::~WebViewEnvironment() { - debugLog("dealloc WebViewEnvironment"); - // Clean up all instances - instances_.clear(); - plugin_ = nullptr; -} - -void WebViewEnvironment::HandleMethodCall(FlMethodCall* method_call) { - const gchar* method = fl_method_call_get_name(method_call); - FlValue* args = fl_method_call_get_args(method_call); - - if (string_equals(method, "getAvailableVersion")) { - std::string version = getAvailableVersion(); - fl_method_call_respond_success(method_call, fl_value_new_string(version.c_str()), nullptr); - } else if (string_equals(method, "create")) { - auto id = get_fl_map_value(args, "id", ""); - if (id.empty()) { - fl_method_call_respond_error(method_call, "INVALID_ARGUMENT", "Missing 'id' argument", - nullptr, nullptr); - return; - } - FlValue* settings = fl_value_lookup_string(args, "settings"); - create(id, settings); - fl_method_call_respond_success(method_call, fl_value_new_null(), nullptr); - } else { - fl_method_call_respond_not_implemented(method_call, nullptr); - } -} - -std::string WebViewEnvironment::getAvailableVersion() { - // Get the WPE WebKit version using the webkit version functions - guint major = webkit_get_major_version(); - guint minor = webkit_get_minor_version(); - guint micro = webkit_get_micro_version(); - - std::ostringstream version; - version << major << "." << minor << "." << micro; - return version.str(); -} - -void WebViewEnvironment::create(const std::string& id, FlValue* settings) { - debugLog("WebViewEnvironment::create id=" + id); - - // Check if we need to use a specific timezone override - // This must be set at construction time via the time-zone-override property - auto timeZoneOverride = get_optional_fl_map_value(settings, "timeZoneOverride"); - - WebKitWebContext* context = nullptr; - if (timeZoneOverride.has_value() && !timeZoneOverride->empty()) { - // Create WebContext with timezone override property - context = WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, - "time-zone-override", timeZoneOverride->c_str(), - nullptr)); - } else { - // Create a default WebKitWebContext - context = webkit_web_context_new(); - } - - if (context == nullptr) { - errorLog("WebViewEnvironment::create - Failed to create WebKitWebContext"); - return; - } - - // Apply settings from creation params - if (settings != nullptr && fl_value_get_type(settings) == FL_VALUE_TYPE_MAP) { - // cacheModel - auto cacheModel = get_optional_fl_map_value(settings, "cacheModel"); - if (cacheModel.has_value()) { - webkit_web_context_set_cache_model(context, - static_cast(cacheModel.value())); - } - - // spellCheckingEnabled - auto spellCheckingEnabled = get_optional_fl_map_value(settings, "spellCheckingEnabled"); - if (spellCheckingEnabled.has_value()) { - webkit_web_context_set_spell_checking_enabled(context, spellCheckingEnabled.value()); - } - - // spellCheckingLanguages - auto spellCheckingLanguages = get_optional_fl_map_value>( - settings, "spellCheckingLanguages"); - if (spellCheckingLanguages.has_value() && !spellCheckingLanguages->empty()) { - // Convert to null-terminated array of C strings - std::vector langs; - for (const auto& lang : *spellCheckingLanguages) { - langs.push_back(lang.c_str()); - } - langs.push_back(nullptr); // Null terminate - webkit_web_context_set_spell_checking_languages(context, langs.data()); - } - - // preferredLanguages - auto preferredLanguages = get_optional_fl_map_value>( - settings, "preferredLanguages"); - if (preferredLanguages.has_value() && !preferredLanguages->empty()) { - std::vector langs; - for (const auto& lang : *preferredLanguages) { - langs.push_back(lang.c_str()); - } - langs.push_back(nullptr); - webkit_web_context_set_preferred_languages(context, langs.data()); - } - - // automationAllowed - auto automationAllowed = get_optional_fl_map_value(settings, "automationAllowed"); - if (automationAllowed.has_value()) { - webkit_web_context_set_automation_allowed(context, automationAllowed.value()); - } - - // webProcessExtensionsDirectory - auto extensionsDir = get_optional_fl_map_value( - settings, "webProcessExtensionsDirectory"); - if (extensionsDir.has_value() && !extensionsDir->empty()) { - webkit_web_context_set_web_process_extensions_directory(context, extensionsDir->c_str()); - } - - // sandboxPaths - auto sandboxPaths = get_optional_fl_map_value>( - settings, "sandboxPaths"); - if (sandboxPaths.has_value()) { - for (const auto& path : *sandboxPaths) { - if (!path.empty()) { - webkit_web_context_add_path_to_sandbox(context, path.c_str(), FALSE); - } - } - } - } - - // Create instance channel delegate - auto instanceDelegate = std::make_unique( - messenger_, id, - [this](const std::string& envId) { disposeEnvironment(envId); }); - instanceDelegate->setContext(context); - - // Store in map - instances_[id] = std::move(instanceDelegate); -} - -void WebViewEnvironment::disposeEnvironment(const std::string& id) { - debugLog("WebViewEnvironment::disposeEnvironment id=" + id); - - auto it = instances_.find(id); - if (it != instances_.end()) { - // Remove from map - this will trigger destructor which cleans up context - instances_.erase(it); - } -} - -WebViewEnvironmentInstanceChannelDelegate* WebViewEnvironment::getInstance(const std::string& id) const { - auto it = instances_.find(id); - if (it != instances_.end()) { - return it->second.get(); - } - return nullptr; -} - -} // namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_linux/linux/webview_environment.h b/flutter_inappwebview_linux/linux/webview_environment.h deleted file mode 100644 index 0e44ec6e5d..0000000000 --- a/flutter_inappwebview_linux/linux/webview_environment.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_WEBVIEW_ENVIRONMENT_H_ -#define FLUTTER_INAPPWEBVIEW_PLUGIN_WEBVIEW_ENVIRONMENT_H_ - -#include -#include - -#include -#include -#include -#include - -#include "types/channel_delegate.h" - -namespace flutter_inappwebview_plugin { - -class PluginInstance; - -/** - * Instance channel delegate for individual WebViewEnvironment instances. - * Handles instance-specific method calls like dispose, isSpellCheckingEnabled, etc. - */ -class WebViewEnvironmentInstanceChannelDelegate : public ChannelDelegate { - public: - WebViewEnvironmentInstanceChannelDelegate(FlBinaryMessenger* messenger, - const std::string& id, - std::function disposeCallback); - ~WebViewEnvironmentInstanceChannelDelegate() override; - - void HandleMethodCall(FlMethodCall* method_call) override; - - WebKitWebContext* context() const { return context_; } - void setContext(WebKitWebContext* context) { context_ = context; } - - // Getter methods for WebContext properties - bool isSpellCheckingEnabled() const; - std::vector getSpellCheckingLanguages() const; - int getCacheModel() const; - bool isAutomationAllowed() const; - - private: - std::string id_; - WebKitWebContext* context_ = nullptr; - std::function disposeCallback_; -}; - -/** - * Manages WebView Environment operations for WPE WebKit. - * Provides access to the WPE WebKit version information and - * WebKitWebContext instance management. - */ -class WebViewEnvironment : public ChannelDelegate { - public: - static constexpr const char* METHOD_CHANNEL_NAME = - "com.pichillilorenzo/flutter_webview_environment"; - - WebViewEnvironment(PluginInstance* plugin); - ~WebViewEnvironment() override; - - /// Get the plugin instance - PluginInstance* plugin() const { return plugin_; } - - void HandleMethodCall(FlMethodCall* method_call) override; - - /** - * Get the WPE WebKit version string (e.g., "2.42.0"). - */ - static std::string getAvailableVersion(); - - /** - * Get the WebKitWebContext for the given environment ID. - * Returns nullptr if not found. - */ - WebKitWebContext* getWebContext(const std::string& id) const; - - private: - PluginInstance* plugin_ = nullptr; - FlBinaryMessenger* messenger_; - - // Map of environment ID -> instance channel delegate - std::map> instances_; - - /** - * Create a new WebViewEnvironment instance with the given ID and settings. - */ - void create(const std::string& id, FlValue* settings); - - /** - * Dispose an environment instance by ID. - */ - void disposeEnvironment(const std::string& id); - - /** - * Get a WebViewEnvironment instance by ID. - * Returns nullptr if not found. - */ - WebViewEnvironmentInstanceChannelDelegate* getInstance(const std::string& id) const; -}; - -} // namespace flutter_inappwebview_plugin - -#endif // FLUTTER_INAPPWEBVIEW_PLUGIN_WEBVIEW_ENVIRONMENT_H_ diff --git a/flutter_inappwebview_linux/pubspec.yaml b/flutter_inappwebview_linux/pubspec.yaml deleted file mode 100644 index 2a96f65cfd..0000000000 --- a/flutter_inappwebview_linux/pubspec.yaml +++ /dev/null @@ -1,82 +0,0 @@ -name: flutter_inappwebview_linux -description: "Linux implementation of flutter_inappwebview plugin using WPE WebKit." -version: 0.1.0-beta.1 -homepage: https://inappwebview.dev/ -repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_linux -issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues -funding: - - https://inappwebview.dev/donate/ -topics: - - html - - webview - - webview-flutter - - inappwebview - - browser - -environment: - sdk: ^3.8.0 - flutter: ">=3.32.0" - -dependencies: - flutter: - sdk: flutter - flutter_inappwebview_platform_interface: ^1.4.0-beta.3 - # path: ../flutter_inappwebview_platform_interface - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^6.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - # This section identifies this Flutter project as a plugin project. - # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) - # which should be registered in the plugin registry. This is required for - # using method channels. - # The Android 'package' specifies package in which the registered class is. - # This is required for using method channels on Android. - # The 'ffiPlugin' specifies that native code should be built and bundled. - # This is required for using `dart:ffi`. - # All these are used by the tooling to maintain consistency when - # adding or updating assets for this project. - plugin: - implements: flutter_inappwebview - platforms: - linux: - pluginClass: FlutterInappwebviewLinuxPlugin - dartPluginClass: LinuxInAppWebViewPlatform - - # To add assets to your plugin package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/to/asset-from-package - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/to/resolution-aware-images - - # To add custom fonts to your plugin package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/to/font-from-package diff --git a/flutter_inappwebview_macos/.gitignore b/flutter_inappwebview_macos/.gitignore deleted file mode 100644 index e896ebf609..0000000000 --- a/flutter_inappwebview_macos/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock -**/doc/api/ -.dart_tool/ -.packages -build/ - -.build/ -.swiftpm/ \ No newline at end of file diff --git a/flutter_inappwebview_macos/.metadata b/flutter_inappwebview_macos/.metadata deleted file mode 100644 index 650038ed0a..0000000000 --- a/flutter_inappwebview_macos/.metadata +++ /dev/null @@ -1,30 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e" - channel: "stable" - -project_type: plugin - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - - platform: macos - create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/flutter_inappwebview_macos/CHANGELOG.md b/flutter_inappwebview_macos/CHANGELOG.md deleted file mode 100644 index 4bdbe83a51..0000000000 --- a/flutter_inappwebview_macos/CHANGELOG.md +++ /dev/null @@ -1,112 +0,0 @@ -## 1.2.0-beta.3 - -- Updated flutter_inappwebview_platform_interface version to ^1.4.0-beta.3 -- Implemented `saveState`, `restoreState` InAppWebViewController methods -- Implemented `PlatformProxyController` class -- Add Swift Package Manager support [#2409](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2409) -- Fixed internal javascript callback handlers when the WebView has windowId not null -- Fixed crash of unhandled `onPrintRequest` WebView event -- Fixed "When useShouldInterceptAjaxRequest is true, some ajax requests doesn't work" [#2197](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2197) -- Fixed "iOS App rejected by apple for violating Guideline 2.5.1 - Performance - Software Requirements | Flutter 3.35.x seems to use non-public or deprecated APIs" [#2754](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2754) -- Fixed "InAppWebViewController.goTo" implementation -- Merged "🐛 fix MacOS: when using the `WebMessageListener` `onPostMessage` method, the message parameter is unexpectedly empty" [#2481](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2481) (thanks to [imoyakin](https://github.com/imoyakin)) -- Merged "fix #2484, Remove not-empty assert for Cookie.value" [#2486](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2486) (thanks to [laishere](https://github.com/laishere)) - -## 1.2.0-beta.2 - -- Updated flutter_inappwebview_platform_interface version to ^1.4.0-beta.2 -- Implemented `alpha` property of `InAppWebViewSettings` - -## 1.2.0-beta.1 - -- Updated flutter_inappwebview_platform_interface version to ^1.4.0-beta.1 -- Implemented `requestFocus`, `clearFocus` WebView methods -- Updated ConsoleLogJS internal PluginScript to main-frame only as using it on non-main frames could cause issues such as [#1738](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738) -- Added support for `UserScript.allowedOriginRules` parameter -- Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error -- Merged "change priority of DispatchQueue" [#2322](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2322) (thanks to [nnnlog](https://github.com/nnnlog)) -- Implemented workaround for "[macOS] Copy Shortcut does not work if TextField outside of WebView has focus" [#2380](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2380) - -## 1.1.2 - -- Updated flutter_inappwebview_platform_interface version to ^1.3.0 - -## 1.1.1 - -- Updated flutter_inappwebview_platform_interface version to ^1.2.0 - -## 1.1.0+3 - -- Updated flutter_inappwebview_platform_interface version - -## ## 1.1.0+2 - -- Updated pubspec.yaml - -## 1.1.0+1 - -- Fixed "v6.1.0 fails to compile on Xcode 15" [#2288](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2288) - -## 1.1.0 - -- Added `InAppWebView` support -- Added privacy manifest -- Updates minimum supported SDK version to Flutter 3.24/Dart 3.5. -- Fixed "[MACOS] launching InAppBrowser with 'hidden: true' calls onExit immediately" [#1939](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1939) -- Fixed XCode 16 build - -## 1.0.11 - -- Updated `flutter_inappwebview_platform_interface` version dependency to `^1.0.10` - -## 1.0.10 - -- Updated `flutter_inappwebview_platform_interface` version dependency to `^1.0.9` -- Fix typos and other code improvements (thanks to [michalsrutek](https://github.com/michalsrutek)) -- Fixed "runtime issue of SecTrustCopyExceptions 'This method should not be called on the main thread as it may lead to UI unresponsiveness.' when using onReceivedServerTrustAuthRequest" [#1924](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1924) - -## 1.0.9 - -- Updated `flutter_inappwebview_platform_interface` version dependency to `^1.0.8` - -## 1.0.8 - -- Updated `flutter_inappwebview_platform_interface` version dependency to `^1.0.7` -- Implemented `InAppBrowser.onMainWindowWillClose` event - -## 1.0.7 - -- Implemented `InAppWebViewSettings.interceptOnlyAsyncAjaxRequests` -- Updated `useShouldInterceptAjaxRequest` automatic infer logic -- Updated `CookieManager` methods return value -- Fixed "iOS crash at public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)" [#1912](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1912) - -## 1.0.6 - -- Fixed error in InterceptAjaxRequestJS 'Failed to set responseType property' -- Fixed shouldInterceptAjaxRequest javascript code when overriding XMLHttpRequest.open method parameters - -## 1.0.5 - -- Fixed "getFavicons: _TypeError: type '_Map' is not a subtype of type 'Iterable'" [#1897](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1897) - -## 1.0.4 - -- Possible fix for "iOS Fatal Crash" [#1894](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1894) - -## 1.0.3 - -- Call `super.dispose();` on `InAppBrowser` implementation - -## 1.0.2 - -- Fixed "Cloudflare Turnstile failure" [#1738](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738) - -## 1.0.1 - -- Added `PlatformPrintJobController.onComplete` setter -- Updated `flutter_inappwebview_platform_interface` version dependency to `^1.0.2` - -## 1.0.0 - -Initial release. diff --git a/flutter_inappwebview_macos/LICENSE b/flutter_inappwebview_macos/LICENSE deleted file mode 100644 index 6ccd8da42c..0000000000 --- a/flutter_inappwebview_macos/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2023 Lorenzo Pichilli - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/flutter_inappwebview_macos/README.md b/flutter_inappwebview_macos/README.md deleted file mode 100644 index 7af883d583..0000000000 --- a/flutter_inappwebview_macos/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# flutter\_inappwebview\_macos - -The Apple macOS WKWebView implementation of [`flutter_inappwebview`](https://pub.dev/packages/flutter_inappwebview). - -## Usage - -This package is [endorsed](https://flutter.dev/docs/development/packages-and-plugins/developing-packages#endorsed-federated-plugin), -which means you can simply use `flutter_inappwebview` -normally. This package will be automatically included in your app when you do, -so you do not need to add it to your `pubspec.yaml`. - -However, if you `import` this package to use any of its APIs directly, you -should add it to your `pubspec.yaml` as usual. \ No newline at end of file diff --git a/flutter_inappwebview_macos/analysis_options.yaml b/flutter_inappwebview_macos/analysis_options.yaml deleted file mode 100644 index e2d13ab58a..0000000000 --- a/flutter_inappwebview_macos/analysis_options.yaml +++ /dev/null @@ -1,16 +0,0 @@ -include: package:flutter_lints/flutter.yaml - -linter: - rules: - constant_identifier_names: ignore - deprecated_member_use_from_same_package: ignore - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options -analyzer: - errors: - constant_identifier_names: ignore - deprecated_member_use: ignore - deprecated_member_use_from_same_package: ignore - unnecessary_cast: ignore - unnecessary_import: ignore diff --git a/flutter_inappwebview_macos/build.yaml b/flutter_inappwebview_macos/build.yaml deleted file mode 100644 index e2b3acf338..0000000000 --- a/flutter_inappwebview_macos/build.yaml +++ /dev/null @@ -1,5 +0,0 @@ -targets: - $default: - sources: - exclude: - - example/**.dart diff --git a/flutter_inappwebview_macos/example/.gitignore b/flutter_inappwebview_macos/example/.gitignore deleted file mode 100644 index 6c319542b3..0000000000 --- a/flutter_inappwebview_macos/example/.gitignore +++ /dev/null @@ -1,46 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.build/ -.buildlog/ -.history -.svn/ -.swiftpm/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/flutter_inappwebview_macos/example/README.md b/flutter_inappwebview_macos/example/README.md deleted file mode 100644 index 1e75fecb06..0000000000 --- a/flutter_inappwebview_macos/example/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# flutter_inappwebview_macos_example - -Demonstrates how to use the flutter_inappwebview_macos plugin. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/flutter_inappwebview_macos/example/analysis_options.yaml b/flutter_inappwebview_macos/example/analysis_options.yaml deleted file mode 100644 index 0d2902135c..0000000000 --- a/flutter_inappwebview_macos/example/analysis_options.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at https://dart.dev/lints. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/flutter_inappwebview_macos/example/integration_test/plugin_integration_test.dart b/flutter_inappwebview_macos/example/integration_test/plugin_integration_test.dart deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/flutter_inappwebview_macos/example/lib/main.dart b/flutter_inappwebview_macos/example/lib/main.dart deleted file mode 100644 index 7ab4dbe7d1..0000000000 --- a/flutter_inappwebview_macos/example/lib/main.dart +++ /dev/null @@ -1,158 +0,0 @@ -import 'dart:async'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import 'package:flutter_inappwebview_macos/flutter_inappwebview_macos.dart'; -import 'package:url_launcher/url_launcher.dart'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - - runApp(const MaterialApp(home: MyApp())); -} - -class MyApp extends StatefulWidget { - const MyApp({super.key}); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - final GlobalKey webViewKey = GlobalKey(); - - MacOSInAppWebViewController? webViewController; - InAppWebViewSettings settings = - InAppWebViewSettings(); - - String url = ""; - double progress = 0; - final urlController = TextEditingController(); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text("Official InAppWebView website")), - body: SafeArea( - child: Column(children: [ - TextField( - decoration: const InputDecoration(prefixIcon: Icon(Icons.search)), - controller: urlController, - keyboardType: TextInputType.url, - onSubmitted: (value) { - var url = WebUri(value); - if (url.scheme.isEmpty) { - url = WebUri("https://www.google.com/search?q=$value"); - } - webViewController?.loadUrl(urlRequest: URLRequest(url: url)); - }, - ), - Expanded( - child: Stack( - children: [ - MacOSInAppWebViewWidget( - MacOSInAppWebViewWidgetCreationParams( - key: webViewKey, - initialUrlRequest: - URLRequest(url: WebUri("https://inappwebview.dev/")), - initialSettings: settings, - onWebViewCreated: (controller) { - webViewController = - controller as MacOSInAppWebViewController; - }, - onLoadStart: (controller, url) { - setState(() { - this.url = url.toString(); - urlController.text = this.url; - }); - }, - onPermissionRequest: (controller, request) async { - return PermissionResponse( - resources: request.resources, - action: PermissionResponseAction.GRANT); - }, - shouldOverrideUrlLoading: - (controller, navigationAction) async { - var uri = navigationAction.request.url!; - - if (![ - "http", - "https", - "file", - "chrome", - "data", - "javascript", - "about" - ].contains(uri.scheme)) { - if (await canLaunchUrl(uri)) { - // Launch the App - await launchUrl( - uri, - ); - // and cancel the request - return NavigationActionPolicy.CANCEL; - } - } - - return NavigationActionPolicy.ALLOW; - }, - onLoadStop: (controller, url) async { - setState(() { - this.url = url.toString(); - urlController.text = this.url; - }); - }, - onReceivedError: (controller, request, error) { - // Handle error - }, - onProgressChanged: (controller, progress) { - setState(() { - this.progress = progress / 100; - urlController.text = url; - }); - }, - onUpdateVisitedHistory: (controller, url, isReload) { - setState(() { - this.url = url.toString(); - urlController.text = this.url; - }); - }, - onConsoleMessage: (controller, consoleMessage) { - if (kDebugMode) { - print(consoleMessage); - } - }, - ), - ).build(context), - progress < 1.0 - ? LinearProgressIndicator(value: progress) - : Container(), - ], - ), - ), - OverflowBar( - alignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - child: const Icon(Icons.arrow_back), - onPressed: () { - webViewController?.goBack(); - }, - ), - ElevatedButton( - child: const Icon(Icons.arrow_forward), - onPressed: () { - webViewController?.goForward(); - }, - ), - ElevatedButton( - child: const Icon(Icons.refresh), - onPressed: () { - webViewController?.reload(); - }, - ), - ], - ), - ]))); - } -} diff --git a/flutter_inappwebview_macos/example/macos/.gitignore b/flutter_inappwebview_macos/example/macos/.gitignore deleted file mode 100644 index 746adbb6b9..0000000000 --- a/flutter_inappwebview_macos/example/macos/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Flutter-related -**/Flutter/ephemeral/ -**/Pods/ - -# Xcode-related -**/dgph -**/xcuserdata/ diff --git a/flutter_inappwebview_macos/example/macos/Flutter/Flutter-Debug.xcconfig b/flutter_inappwebview_macos/example/macos/Flutter/Flutter-Debug.xcconfig deleted file mode 100644 index 4b81f9b2d2..0000000000 --- a/flutter_inappwebview_macos/example/macos/Flutter/Flutter-Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/flutter_inappwebview_macos/example/macos/Flutter/Flutter-Release.xcconfig b/flutter_inappwebview_macos/example/macos/Flutter/Flutter-Release.xcconfig deleted file mode 100644 index 5caa9d1579..0000000000 --- a/flutter_inappwebview_macos/example/macos/Flutter/Flutter-Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/flutter_inappwebview_macos/example/macos/Flutter/GeneratedPluginRegistrant.swift b/flutter_inappwebview_macos/example/macos/Flutter/GeneratedPluginRegistrant.swift deleted file mode 100644 index f76e8b04e3..0000000000 --- a/flutter_inappwebview_macos/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// Generated file. Do not edit. -// - -import FlutterMacOS -import Foundation - -import flutter_inappwebview_macos -import url_launcher_macos - -func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) - UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) -} diff --git a/flutter_inappwebview_macos/example/macos/Podfile b/flutter_inappwebview_macos/example/macos/Podfile deleted file mode 100644 index b52666a103..0000000000 --- a/flutter_inappwebview_macos/example/macos/Podfile +++ /dev/null @@ -1,43 +0,0 @@ -platform :osx, '10.15' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_macos_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) - target 'RunnerTests' do - inherit! :search_paths - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_macos_build_settings(target) - end -end diff --git a/flutter_inappwebview_macos/example/macos/Podfile.lock b/flutter_inappwebview_macos/example/macos/Podfile.lock deleted file mode 100644 index 9d359e124a..0000000000 --- a/flutter_inappwebview_macos/example/macos/Podfile.lock +++ /dev/null @@ -1,16 +0,0 @@ -PODS: - - FlutterMacOS (1.0.0) - -DEPENDENCIES: - - FlutterMacOS (from `Flutter/ephemeral`) - -EXTERNAL SOURCES: - FlutterMacOS: - :path: Flutter/ephemeral - -SPEC CHECKSUMS: - FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 - -PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 - -COCOAPODS: 1.16.2 diff --git a/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/project.pbxproj b/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 8d05a7e4ce..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,847 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXAggregateTarget section */ - 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; - buildPhases = ( - 33CC111E2044C6BF0003C045 /* ShellScript */, - ); - dependencies = ( - ); - name = "Flutter Assemble"; - productName = FLX; - }; -/* End PBXAggregateTarget section */ - -/* Begin PBXBuildFile section */ - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 5865C7EF826F3708B24277A6 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BC4FAAB28A9FBB9F65043C2F /* Pods_Runner.framework */; }; - 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; - AB9251333617BAF83D6CAE09 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A67F9B8915AAB585F409D1C7 /* Pods_RunnerTests.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC10EC2044A3C60003C045; - remoteInfo = Runner; - }; - 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC111A2044C6BA0003C045; - remoteInfo = FLX; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Bundle Framework"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* flutter_inappwebview_macos_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = flutter_inappwebview_macos_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; - 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; - 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; - 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 37150E3659707123204F69E7 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; - 58192BE30369BC3CB0110B07 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; - 6DD4117DFAAB8F5859E2F7F3 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 848397DF1E6BD385DBB5C3B6 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - A67F9B8915AAB585F409D1C7 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - BC4FAAB28A9FBB9F65043C2F /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - E7F5F1EDBE08376F16DB1756 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - FD6E737E8611AC59C71843B9 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 331C80D2294CF70F00263BE5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - AB9251333617BAF83D6CAE09 /* Pods_RunnerTests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EA2044A3C60003C045 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, - 5865C7EF826F3708B24277A6 /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 331C80D6294CF71000263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C80D7294CF71000263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 33BA886A226E78AF003329D5 /* Configs */ = { - isa = PBXGroup; - children = ( - 33E5194F232828860026EE4D /* AppInfo.xcconfig */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, - ); - path = Configs; - sourceTree = ""; - }; - 33CC10E42044A3C60003C045 = { - isa = PBXGroup; - children = ( - 33FAB671232836740065AC1E /* Runner */, - 33CEB47122A05771004F2AC0 /* Flutter */, - 331C80D6294CF71000263BE5 /* RunnerTests */, - 33CC10EE2044A3C60003C045 /* Products */, - D73912EC22F37F3D000D13A0 /* Frameworks */, - 99DA5C11C23F4D8DC2C5D2B9 /* Pods */, - ); - sourceTree = ""; - }; - 33CC10EE2044A3C60003C045 /* Products */ = { - isa = PBXGroup; - children = ( - 33CC10ED2044A3C60003C045 /* flutter_inappwebview_macos_example.app */, - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 33CC11242044D66E0003C045 /* Resources */ = { - isa = PBXGroup; - children = ( - 33CC10F22044A3C60003C045 /* Assets.xcassets */, - 33CC10F42044A3C60003C045 /* MainMenu.xib */, - 33CC10F72044A3C60003C045 /* Info.plist */, - ); - name = Resources; - path = ..; - sourceTree = ""; - }; - 33CEB47122A05771004F2AC0 /* Flutter */ = { - isa = PBXGroup; - children = ( - 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - ); - path = Flutter; - sourceTree = ""; - }; - 33FAB671232836740065AC1E /* Runner */ = { - isa = PBXGroup; - children = ( - 33CC10F02044A3C60003C045 /* AppDelegate.swift */, - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, - 33E51913231747F40026EE4D /* DebugProfile.entitlements */, - 33E51914231749380026EE4D /* Release.entitlements */, - 33CC11242044D66E0003C045 /* Resources */, - 33BA886A226E78AF003329D5 /* Configs */, - ); - path = Runner; - sourceTree = ""; - }; - 99DA5C11C23F4D8DC2C5D2B9 /* Pods */ = { - isa = PBXGroup; - children = ( - FD6E737E8611AC59C71843B9 /* Pods-Runner.debug.xcconfig */, - E7F5F1EDBE08376F16DB1756 /* Pods-Runner.release.xcconfig */, - 6DD4117DFAAB8F5859E2F7F3 /* Pods-Runner.profile.xcconfig */, - 37150E3659707123204F69E7 /* Pods-RunnerTests.debug.xcconfig */, - 58192BE30369BC3CB0110B07 /* Pods-RunnerTests.release.xcconfig */, - 848397DF1E6BD385DBB5C3B6 /* Pods-RunnerTests.profile.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; - D73912EC22F37F3D000D13A0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - BC4FAAB28A9FBB9F65043C2F /* Pods_Runner.framework */, - A67F9B8915AAB585F409D1C7 /* Pods_RunnerTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C80D4294CF70F00263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - 19C41905C33A44573E03C5AA /* [CP] Check Pods Manifest.lock */, - 331C80D1294CF70F00263BE5 /* Sources */, - 331C80D2294CF70F00263BE5 /* Frameworks */, - 331C80D3294CF70F00263BE5 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 331C80DA294CF71000263BE5 /* PBXTargetDependency */, - ); - name = RunnerTests; - productName = RunnerTests; - productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 33CC10EC2044A3C60003C045 /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - F5A44A140DBA26297483F1F8 /* [CP] Check Pods Manifest.lock */, - 33CC10E92044A3C60003C045 /* Sources */, - 33CC10EA2044A3C60003C045 /* Frameworks */, - 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, - 3399D490228B24CF009A79C7 /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - 33CC11202044C79F0003C045 /* PBXTargetDependency */, - ); - name = Runner; - packageProductDependencies = ( - 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, - ); - productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* flutter_inappwebview_macos_example.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 33CC10E52044A3C60003C045 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C80D4294CF70F00263BE5 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = 33CC10EC2044A3C60003C045; - }; - 33CC10EC2044A3C60003C045 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.Sandbox = { - enabled = 1; - }; - }; - }; - 33CC111A2044C6BA0003C045 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 33CC10E42044A3C60003C045; - packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, - ); - productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 33CC10EC2044A3C60003C045 /* Runner */, - 331C80D4294CF70F00263BE5 /* RunnerTests */, - 33CC111A2044C6BA0003C045 /* Flutter Assemble */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 331C80D3294CF70F00263BE5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EB2044A3C60003C045 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 19C41905C33A44573E03C5AA /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 3399D490228B24CF009A79C7 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; - }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, - ); - outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; - }; - F5A44A140DBA26297483F1F8 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 331C80D1294CF70F00263BE5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10E92044A3C60003C045 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC10EC2044A3C60003C045 /* Runner */; - targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; - }; - 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; - targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 33CC10F52044A3C60003C045 /* Base */, - ); - name = MainMenu.xib; - path = Runner; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 331C80DB294CF71000263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 37150E3659707123204F69E7 /* Pods-RunnerTests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = PFP8UV45Y6; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterInappwebviewMacosExample.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flutter_inappwebview_macos_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flutter_inappwebview_macos_example"; - }; - name = Debug; - }; - 331C80DC294CF71000263BE5 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 58192BE30369BC3CB0110B07 /* Pods-RunnerTests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = PFP8UV45Y6; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterInappwebviewMacosExample.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flutter_inappwebview_macos_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flutter_inappwebview_macos_example"; - }; - name = Release; - }; - 331C80DD294CF71000263BE5 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 848397DF1E6BD385DBB5C3B6 /* Pods-RunnerTests.profile.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = PFP8UV45Y6; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterInappwebviewMacosExample.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flutter_inappwebview_macos_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flutter_inappwebview_macos_example"; - }; - name = Profile; - }; - 338D0CE9231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Profile; - }; - 338D0CEA231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = PFP8UV45Y6; - ENABLE_APP_SANDBOX = YES; - ENABLE_INCOMING_NETWORK_CONNECTIONS = NO; - ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; - ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = YES; - ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO; - ENABLE_RESOURCE_ACCESS_CALENDARS = NO; - ENABLE_RESOURCE_ACCESS_CAMERA = YES; - ENABLE_RESOURCE_ACCESS_CONTACTS = NO; - ENABLE_RESOURCE_ACCESS_LOCATION = NO; - ENABLE_RESOURCE_ACCESS_PRINTING = YES; - ENABLE_RESOURCE_ACCESS_USB = NO; - ENABLE_USER_SELECTED_FILES = readwrite; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Profile; - }; - 338D0CEB231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Profile; - }; - 33CC10F92044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 33CC10FA2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Release; - }; - 33CC10FC2044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = PFP8UV45Y6; - ENABLE_APP_SANDBOX = YES; - ENABLE_INCOMING_NETWORK_CONNECTIONS = NO; - ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; - ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = YES; - ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO; - ENABLE_RESOURCE_ACCESS_CALENDARS = NO; - ENABLE_RESOURCE_ACCESS_CAMERA = YES; - ENABLE_RESOURCE_ACCESS_CONTACTS = NO; - ENABLE_RESOURCE_ACCESS_LOCATION = NO; - ENABLE_RESOURCE_ACCESS_PRINTING = YES; - ENABLE_RESOURCE_ACCESS_USB = NO; - ENABLE_USER_SELECTED_FILES = readwrite; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 33CC10FD2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = PFP8UV45Y6; - ENABLE_APP_SANDBOX = YES; - ENABLE_INCOMING_NETWORK_CONNECTIONS = YES; - ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; - ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = YES; - ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO; - ENABLE_RESOURCE_ACCESS_CALENDARS = NO; - ENABLE_RESOURCE_ACCESS_CAMERA = YES; - ENABLE_RESOURCE_ACCESS_CONTACTS = NO; - ENABLE_RESOURCE_ACCESS_LOCATION = NO; - ENABLE_RESOURCE_ACCESS_PRINTING = YES; - ENABLE_RESOURCE_ACCESS_USB = NO; - ENABLE_USER_SELECTED_FILES = readwrite; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 33CC111C2044C6BA0003C045 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 33CC111D2044C6BA0003C045 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 331C80DB294CF71000263BE5 /* Debug */, - 331C80DC294CF71000263BE5 /* Release */, - 331C80DD294CF71000263BE5 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10F92044A3C60003C045 /* Debug */, - 33CC10FA2044A3C60003C045 /* Release */, - 338D0CE9231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10FC2044A3C60003C045 /* Debug */, - 33CC10FD2044A3C60003C045 /* Release */, - 338D0CEA231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC111C2044C6BA0003C045 /* Debug */, - 33CC111D2044C6BA0003C045 /* Release */, - 338D0CEB231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { - isa = XCLocalSwiftPackageReference; - relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; - }; -/* End XCLocalSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { - isa = XCSwiftPackageProductDependency; - productName = FlutterGeneratedPluginSwiftPackage; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 33CC10E52044A3C60003C045 /* Project object */; -} diff --git a/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index eb9351a474..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,14 +0,0 @@ -{ - "pins" : [ - { - "identity" : "swift-collections", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-collections.git", - "state" : { - "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", - "version" : "1.3.0" - } - } - ], - "version" : 2 -} diff --git a/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index c7d27fa253..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_inappwebview_macos/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/flutter_inappwebview_macos/example/macos/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14c7..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/flutter_inappwebview_macos/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_inappwebview_macos/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/flutter_inappwebview_macos/example/macos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved b/flutter_inappwebview_macos/example/macos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index eb9351a474..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,14 +0,0 @@ -{ - "pins" : [ - { - "identity" : "swift-collections", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-collections.git", - "state" : { - "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", - "version" : "1.3.0" - } - } - ], - "version" : 2 -} diff --git a/flutter_inappwebview_macos/example/macos/Runner/AppDelegate.swift b/flutter_inappwebview_macos/example/macos/Runner/AppDelegate.swift deleted file mode 100644 index b3c1761412..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Cocoa -import FlutterMacOS - -@main -class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } - - override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { - return true - } -} diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index a2ec33f19f..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" - }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png deleted file mode 100644 index 82b6f9d9a3..0000000000 Binary files a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png and /dev/null differ diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png deleted file mode 100644 index 13b35eba55..0000000000 Binary files a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png and /dev/null differ diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png deleted file mode 100644 index 0a3f5fa40f..0000000000 Binary files a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png and /dev/null differ diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png deleted file mode 100644 index bdb57226d5..0000000000 Binary files a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png and /dev/null differ diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png deleted file mode 100644 index f083318e09..0000000000 Binary files a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png and /dev/null differ diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png deleted file mode 100644 index 326c0e72c9..0000000000 Binary files a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png and /dev/null differ diff --git a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png deleted file mode 100644 index 2f1632cfdd..0000000000 Binary files a/flutter_inappwebview_macos/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png and /dev/null differ diff --git a/flutter_inappwebview_macos/example/macos/Runner/Base.lproj/MainMenu.xib b/flutter_inappwebview_macos/example/macos/Runner/Base.lproj/MainMenu.xib deleted file mode 100644 index 80e867a4e0..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,343 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_inappwebview_macos/example/macos/Runner/Configs/AppInfo.xcconfig b/flutter_inappwebview_macos/example/macos/Runner/Configs/AppInfo.xcconfig deleted file mode 100644 index ce19f930c0..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner/Configs/AppInfo.xcconfig +++ /dev/null @@ -1,14 +0,0 @@ -// Application-level settings for the Runner target. -// -// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the -// future. If not, the values below would default to using the project name when this becomes a -// 'flutter create' template. - -// The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = flutter_inappwebview_macos_example - -// The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterInappwebviewMacosExample - -// The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2023 com.pichillilorenzo. All rights reserved. diff --git a/flutter_inappwebview_macos/example/macos/Runner/Configs/Debug.xcconfig b/flutter_inappwebview_macos/example/macos/Runner/Configs/Debug.xcconfig deleted file mode 100644 index 36b0fd9464..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner/Configs/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Debug.xcconfig" -#include "Warnings.xcconfig" diff --git a/flutter_inappwebview_macos/example/macos/Runner/Configs/Release.xcconfig b/flutter_inappwebview_macos/example/macos/Runner/Configs/Release.xcconfig deleted file mode 100644 index dff4f49561..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner/Configs/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Release.xcconfig" -#include "Warnings.xcconfig" diff --git a/flutter_inappwebview_macos/example/macos/Runner/Configs/Warnings.xcconfig b/flutter_inappwebview_macos/example/macos/Runner/Configs/Warnings.xcconfig deleted file mode 100644 index 42bcbf4780..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner/Configs/Warnings.xcconfig +++ /dev/null @@ -1,13 +0,0 @@ -WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings -GCC_WARN_UNDECLARED_SELECTOR = YES -CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES -CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES -CLANG_WARN_PRAGMA_PACK = YES -CLANG_WARN_STRICT_PROTOTYPES = YES -CLANG_WARN_COMMA = YES -GCC_WARN_STRICT_SELECTOR_MATCH = YES -CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES -GCC_WARN_SHADOW = YES -CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/flutter_inappwebview_macos/example/macos/Runner/DebugProfile.entitlements b/flutter_inappwebview_macos/example/macos/Runner/DebugProfile.entitlements deleted file mode 100644 index dddb8a30c8..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner/DebugProfile.entitlements +++ /dev/null @@ -1,12 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - - diff --git a/flutter_inappwebview_macos/example/macos/Runner/Info.plist b/flutter_inappwebview_macos/example/macos/Runner/Info.plist deleted file mode 100644 index 15f20bedca..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner/Info.plist +++ /dev/null @@ -1,55 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - NSAppTransportSecurity - - NSAllowsLocalNetworking - - NSAllowsArbitraryLoadsInWebContent - - NSAllowsArbitraryLoads - - - NSMicrophoneUsageDescription - InAppWebView requires access to mic. - NSLocationWhenInUseUsageDescription - Need location - NSLocationAlwaysUsageDescription - Need location - NSLocationAlwaysAndWhenInUseUsageDescription - Need location - NSLocalNetworkUsageDescription - Allow Flutter tools on your computer to connect and debug your application. - NSDocumentsFolderUsageDescription - InAppWebView requires access to documents folder - NSCameraUsageDescription - InAppWebView requires access to cam. - - diff --git a/flutter_inappwebview_macos/example/macos/Runner/MainFlutterWindow.swift b/flutter_inappwebview_macos/example/macos/Runner/MainFlutterWindow.swift deleted file mode 100644 index 3cc05eb234..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner/MainFlutterWindow.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Cocoa -import FlutterMacOS - -class MainFlutterWindow: NSWindow { - override func awakeFromNib() { - let flutterViewController = FlutterViewController() - let windowFrame = self.frame - self.contentViewController = flutterViewController - self.setFrame(windowFrame, display: true) - - RegisterGeneratedPlugins(registry: flutterViewController) - - super.awakeFromNib() - } -} diff --git a/flutter_inappwebview_macos/example/macos/Runner/Release.entitlements b/flutter_inappwebview_macos/example/macos/Runner/Release.entitlements deleted file mode 100644 index 852fa1a472..0000000000 --- a/flutter_inappwebview_macos/example/macos/Runner/Release.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - com.apple.security.app-sandbox - - - diff --git a/flutter_inappwebview_macos/example/macos/RunnerTests/RunnerTests.swift b/flutter_inappwebview_macos/example/macos/RunnerTests/RunnerTests.swift deleted file mode 100644 index fd89764510..0000000000 --- a/flutter_inappwebview_macos/example/macos/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,27 +0,0 @@ -import FlutterMacOS -import Cocoa -import XCTest - -@testable import flutter_inappwebview_macos - -// This demonstrates a simple unit test of the Swift portion of this plugin's implementation. -// -// See https://developer.apple.com/documentation/xctest for more information about using XCTest. - -class RunnerTests: XCTestCase { - - func testGetPlatformVersion() { - let plugin = FlutterInappwebviewMacosPlugin() - - let call = FlutterMethodCall(methodName: "getPlatformVersion", arguments: []) - - let resultExpectation = expectation(description: "result block must be called.") - plugin.handle(call) { result in - XCTAssertEqual(result as! String, - "macOS " + ProcessInfo.processInfo.operatingSystemVersionString) - resultExpectation.fulfill() - } - waitForExpectations(timeout: 1) - } - -} diff --git a/flutter_inappwebview_macos/example/pubspec.lock b/flutter_inappwebview_macos/example/pubspec.lock deleted file mode 100644 index 67c0030e0c..0000000000 --- a/flutter_inappwebview_macos/example/pubspec.lock +++ /dev/null @@ -1,374 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" - url: "https://pub.dev" - source: hosted - version: "2.11.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - file: - dependency: transitive - description: - name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_driver: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_inappwebview_internal_annotations: - dependency: transitive - description: - path: "../../dev_packages/flutter_inappwebview_internal_annotations" - relative: true - source: path - version: "1.3.0" - flutter_inappwebview_macos: - dependency: "direct main" - description: - path: ".." - relative: true - source: path - version: "1.2.0-beta.3" - flutter_inappwebview_platform_interface: - dependency: "direct main" - description: - path: "../../flutter_inappwebview_platform_interface" - relative: true - source: path - version: "1.4.0-beta.3" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 - url: "https://pub.dev" - source: hosted - version: "2.0.3" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - fuchsia_remote_debug_protocol: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - integration_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" - source: hosted - version: "11.0.2" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" - source: hosted - version: "3.0.10" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - lints: - dependency: transitive - description: - name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" - url: "https://pub.dev" - source: hosted - version: "1.17.0" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - platform: - dependency: transitive - description: - name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" - url: "https://pub.dev" - source: hosted - version: "3.1.5" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - process: - dependency: transitive - description: - name: process - sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" - url: "https://pub.dev" - source: hosted - version: "5.0.2" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_span: - dependency: transitive - description: - name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - sync_http: - dependency: transitive - description: - name: sync_http - sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" - url: "https://pub.dev" - source: hosted - version: "0.3.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test_api: - dependency: transitive - description: - name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 - url: "https://pub.dev" - source: hosted - version: "0.7.7" - url_launcher: - dependency: "direct main" - description: - name: url_launcher - sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.dev" - source: hosted - version: "6.3.2" - url_launcher_android: - dependency: transitive - description: - name: url_launcher_android - sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611" - url: "https://pub.dev" - source: hosted - version: "6.3.28" - url_launcher_ios: - dependency: transitive - description: - name: url_launcher_ios - sha256: cfde38aa257dae62ffe79c87fab20165dfdf6988c1d31b58ebf59b9106062aad - url: "https://pub.dev" - source: hosted - version: "6.3.6" - url_launcher_linux: - dependency: transitive - description: - name: url_launcher_linux - sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a - url: "https://pub.dev" - source: hosted - version: "3.2.2" - url_launcher_macos: - dependency: transitive - description: - name: url_launcher_macos - sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" - url: "https://pub.dev" - source: hosted - version: "3.2.5" - url_launcher_platform_interface: - dependency: transitive - description: - name: url_launcher_platform_interface - sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - url_launcher_web: - dependency: transitive - description: - name: url_launcher_web - sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f - url: "https://pub.dev" - source: hosted - version: "2.4.2" - url_launcher_windows: - dependency: transitive - description: - name: url_launcher_windows - sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" - url: "https://pub.dev" - source: hosted - version: "3.1.5" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" - source: hosted - version: "2.2.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" - url: "https://pub.dev" - source: hosted - version: "14.2.5" - web: - dependency: transitive - description: - name: web - sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - webdriver: - dependency: transitive - description: - name: webdriver - sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" - url: "https://pub.dev" - source: hosted - version: "3.0.3" -sdks: - dart: ">=3.10.0 <4.0.0" - flutter: ">=3.38.0" diff --git a/flutter_inappwebview_macos/example/pubspec.yaml b/flutter_inappwebview_macos/example/pubspec.yaml deleted file mode 100644 index 03b8d66ecd..0000000000 --- a/flutter_inappwebview_macos/example/pubspec.yaml +++ /dev/null @@ -1,91 +0,0 @@ -name: flutter_inappwebview_macos_example -description: Demonstrates how to use the flutter_inappwebview_macos plugin. -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -environment: - sdk: ">=2.17.0 <4.0.0" - flutter: ">=3.0.0" - -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. -dependencies: - flutter: - sdk: flutter - - flutter_inappwebview_macos: - # When depending on this package from a real application you should use: - # flutter_inappwebview_macos: ^x.y.z - # See https://dart.dev/tools/pub/dependencies#version-constraints - # The example app is bundled with the plugin so we use a path dependency on - # the parent directory to use the current plugin's version. - path: ../ - - flutter_inappwebview_platform_interface: - path: ../../flutter_inappwebview_platform_interface - - url_launcher: ^6.1.0 - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 - -dev_dependencies: - integration_test: - sdk: flutter - flutter_test: - sdk: flutter - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^2.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/flutter_inappwebview_macos/example/test/widget_test.dart b/flutter_inappwebview_macos/example/test/widget_test.dart deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/flutter_inappwebview_macos/lib/flutter_inappwebview_macos.dart b/flutter_inappwebview_macos/lib/flutter_inappwebview_macos.dart deleted file mode 100644 index b82fc696d3..0000000000 --- a/flutter_inappwebview_macos/lib/flutter_inappwebview_macos.dart +++ /dev/null @@ -1,3 +0,0 @@ -library flutter_inappwebview_macos; - -export 'src/main.dart'; diff --git a/flutter_inappwebview_macos/lib/src/cookie_manager.dart b/flutter_inappwebview_macos/lib/src/cookie_manager.dart deleted file mode 100755 index 0266f17b85..0000000000 --- a/flutter_inappwebview_macos/lib/src/cookie_manager.dart +++ /dev/null @@ -1,477 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; - -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import 'in_app_webview/headless_in_app_webview.dart'; -import 'platform_util.dart'; - -/// Object specifying creation parameters for creating a [MacOSCookieManager]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformCookieManagerCreationParams] for -/// more information. -@immutable -class MacOSCookieManagerCreationParams - extends PlatformCookieManagerCreationParams { - /// Creates a new [MacOSCookieManagerCreationParams] instance. - const MacOSCookieManagerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformCookieManagerCreationParams params, - ) : super(); - - /// Creates a [MacOSCookieManagerCreationParams] instance based on [PlatformCookieManagerCreationParams]. - factory MacOSCookieManagerCreationParams.fromPlatformCookieManagerCreationParams( - PlatformCookieManagerCreationParams params, - ) { - return MacOSCookieManagerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager} -class MacOSCookieManager extends PlatformCookieManager with ChannelController { - /// Creates a new [MacOSCookieManager]. - MacOSCookieManager(PlatformCookieManagerCreationParams params) - : super.implementation( - params is MacOSCookieManagerCreationParams - ? params - : MacOSCookieManagerCreationParams.fromPlatformCookieManagerCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_cookiemanager', - ); - handler = handleMethod; - initMethodCallHandler(); - } - - static final MacOSCookieManager _staticValue = MacOSCookieManager( - MacOSCookieManagerCreationParams(PlatformCookieManagerCreationParams()), - ); - - factory MacOSCookieManager.static() { - return _staticValue; - } - - static MacOSCookieManager? _instance; - - ///Gets the [MacOSCookieManager] shared instance. - static MacOSCookieManager instance() { - return (_instance != null) ? _instance! : _init(); - } - - static MacOSCookieManager _init() { - _instance = MacOSCookieManager( - MacOSCookieManagerCreationParams( - const PlatformCookieManagerCreationParams(), - ), - ); - return _instance!; - } - - Future _handleMethod(MethodCall call) async {} - - @override - Future setCookie({ - required WebUri url, - required String name, - required String value, - String path = "/", - String? domain, - int? expiresDate, - int? maxAge, - bool? isSecure, - bool? isHttpOnly, - HTTPCookieSameSitePolicy? sameSite, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - webViewController = webViewController ?? iosBelow11WebViewController; - - assert(url.toString().isNotEmpty); - assert(name.isNotEmpty); - assert(path.isNotEmpty); - - if (await _shouldUseJavascript()) { - await _setCookieWithJavaScript( - url: url, - name: name, - value: value, - domain: domain, - path: path, - expiresDate: expiresDate, - maxAge: maxAge, - isSecure: isSecure, - sameSite: sameSite, - webViewController: webViewController, - ); - return true; - } - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - args.putIfAbsent('name', () => name); - args.putIfAbsent('value', () => value); - args.putIfAbsent('domain', () => domain); - args.putIfAbsent('path', () => path); - args.putIfAbsent('expiresDate', () => expiresDate?.toString()); - args.putIfAbsent('maxAge', () => maxAge); - args.putIfAbsent('isSecure', () => isSecure); - args.putIfAbsent('isHttpOnly', () => isHttpOnly); - args.putIfAbsent('sameSite', () => sameSite?.toNativeValue()); - - return await channel?.invokeMethod('setCookie', args) ?? false; - } - - Future _setCookieWithJavaScript({ - required WebUri url, - required String name, - required String value, - String path = "/", - String? domain, - int? expiresDate, - int? maxAge, - bool? isSecure, - HTTPCookieSameSitePolicy? sameSite, - PlatformInAppWebViewController? webViewController, - }) async { - var cookieValue = name + "=" + value + "; Path=" + path; - - if (domain != null) cookieValue += "; Domain=" + domain; - - if (expiresDate != null) - cookieValue += "; Expires=" + await _getCookieExpirationDate(expiresDate); - - if (maxAge != null) cookieValue += "; Max-Age=" + maxAge.toString(); - - if (isSecure != null && isSecure) cookieValue += "; Secure"; - - if (sameSite != null && sameSite.isSupported()) - cookieValue += "; SameSite=" + sameSite.toNativeValue()!; - - cookieValue += ";"; - - if (webViewController != null) { - final javaScriptEnabled = - (await webViewController.getSettings())?.javaScriptEnabled ?? false; - if (javaScriptEnabled) { - await webViewController.evaluateJavascript( - source: 'document.cookie="$cookieValue"', - ); - return; - } - } - - final setCookieCompleter = Completer(); - final headlessWebView = MacOSHeadlessInAppWebView( - MacOSHeadlessInAppWebViewCreationParams( - initialUrlRequest: URLRequest(url: url), - onLoadStop: (controller, url) async { - await controller.evaluateJavascript( - source: 'document.cookie="$cookieValue"', - ); - setCookieCompleter.complete(); - }, - ), - ); - await headlessWebView.run(); - await setCookieCompleter.future; - await headlessWebView.dispose(); - } - - @override - Future> getCookies({ - required WebUri url, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - assert(url.toString().isNotEmpty); - - webViewController = webViewController ?? iosBelow11WebViewController; - - if (await _shouldUseJavascript()) { - return await _getCookiesWithJavaScript( - url: url, - webViewController: webViewController, - ); - } - - List cookies = []; - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - List cookieListMap = - await channel?.invokeMethod('getCookies', args) ?? []; - cookieListMap = cookieListMap.cast>(); - - cookieListMap.forEach((cookieMap) { - cookies.add( - Cookie( - name: cookieMap["name"], - value: cookieMap["value"], - expiresDate: cookieMap["expiresDate"], - isSessionOnly: cookieMap["isSessionOnly"], - domain: cookieMap["domain"], - sameSite: HTTPCookieSameSitePolicy.fromNativeValue( - cookieMap["sameSite"], - ), - isSecure: cookieMap["isSecure"], - isHttpOnly: cookieMap["isHttpOnly"], - path: cookieMap["path"], - ), - ); - }); - return cookies; - } - - Future> _getCookiesWithJavaScript({ - required WebUri url, - PlatformInAppWebViewController? webViewController, - }) async { - assert(url.toString().isNotEmpty); - - List cookies = []; - - if (webViewController != null) { - final javaScriptEnabled = - (await webViewController.getSettings())?.javaScriptEnabled ?? false; - if (javaScriptEnabled) { - List documentCookies = - (await webViewController.evaluateJavascript( - source: 'document.cookie', - ) - as String) - .split(';') - .map((documentCookie) => documentCookie.trim()) - .toList(); - documentCookies.forEach((documentCookie) { - List cookie = documentCookie.split('='); - if (cookie.length > 1) { - cookies.add(Cookie(name: cookie[0], value: cookie[1])); - } - }); - return cookies; - } - } - - final pageLoaded = Completer(); - final headlessWebView = MacOSHeadlessInAppWebView( - MacOSHeadlessInAppWebViewCreationParams( - initialUrlRequest: URLRequest(url: url), - onLoadStop: (controller, url) async { - pageLoaded.complete(); - }, - ), - ); - await headlessWebView.run(); - await pageLoaded.future; - - List documentCookies = - (await headlessWebView.webViewController!.evaluateJavascript( - source: 'document.cookie', - ) - as String) - .split(';') - .map((documentCookie) => documentCookie.trim()) - .toList(); - documentCookies.forEach((documentCookie) { - List cookie = documentCookie.split('='); - if (cookie.length > 1) { - cookies.add(Cookie(name: cookie[0], value: cookie[1])); - } - }); - await headlessWebView.dispose(); - return cookies; - } - - @override - Future getCookie({ - required WebUri url, - required String name, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - assert(url.toString().isNotEmpty); - assert(name.isNotEmpty); - - webViewController = webViewController ?? iosBelow11WebViewController; - - if (await _shouldUseJavascript()) { - List cookies = await _getCookiesWithJavaScript( - url: url, - webViewController: webViewController, - ); - return cookies.cast().firstWhere( - (cookie) => cookie!.name == name, - orElse: () => null, - ); - } - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - List cookies = - await channel?.invokeMethod('getCookies', args) ?? []; - cookies = cookies.cast>(); - for (var i = 0; i < cookies.length; i++) { - cookies[i] = cookies[i].cast(); - if (cookies[i]["name"] == name) - return Cookie( - name: cookies[i]["name"], - value: cookies[i]["value"], - expiresDate: cookies[i]["expiresDate"], - isSessionOnly: cookies[i]["isSessionOnly"], - domain: cookies[i]["domain"], - sameSite: HTTPCookieSameSitePolicy.fromNativeValue( - cookies[i]["sameSite"], - ), - isSecure: cookies[i]["isSecure"], - isHttpOnly: cookies[i]["isHttpOnly"], - path: cookies[i]["path"], - ); - } - return null; - } - - @override - Future deleteCookie({ - required WebUri url, - required String name, - String path = "/", - String? domain, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - assert(url.toString().isNotEmpty); - assert(name.isNotEmpty); - - webViewController = webViewController ?? iosBelow11WebViewController; - - if (await _shouldUseJavascript()) { - await _setCookieWithJavaScript( - url: url, - name: name, - value: "", - path: path, - domain: domain, - maxAge: -1, - webViewController: webViewController, - ); - return true; - } - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - args.putIfAbsent('name', () => name); - args.putIfAbsent('domain', () => domain); - args.putIfAbsent('path', () => path); - return await channel?.invokeMethod('deleteCookie', args) ?? false; - } - - @override - Future deleteCookies({ - required WebUri url, - String path = "/", - String? domain, - @Deprecated("Use webViewController instead") - PlatformInAppWebViewController? iosBelow11WebViewController, - PlatformInAppWebViewController? webViewController, - }) async { - assert(url.toString().isNotEmpty); - - webViewController = webViewController ?? iosBelow11WebViewController; - - if (await _shouldUseJavascript()) { - List cookies = await _getCookiesWithJavaScript( - url: url, - webViewController: webViewController, - ); - for (var i = 0; i < cookies.length; i++) { - await _setCookieWithJavaScript( - url: url, - name: cookies[i].name, - value: "", - path: path, - domain: domain, - maxAge: -1, - webViewController: webViewController, - ); - } - return true; - } - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - args.putIfAbsent('domain', () => domain); - args.putIfAbsent('path', () => path); - return await channel?.invokeMethod('deleteCookies', args) ?? false; - } - - @override - Future deleteAllCookies() async { - Map args = {}; - return await channel?.invokeMethod('deleteAllCookies', args) ?? false; - } - - @override - Future> getAllCookies() async { - List cookies = []; - - Map args = {}; - List cookieListMap = - await channel?.invokeMethod('getAllCookies', args) ?? []; - cookieListMap = cookieListMap.cast>(); - - cookieListMap.forEach((cookieMap) { - cookies.add( - Cookie( - name: cookieMap["name"], - value: cookieMap["value"], - expiresDate: cookieMap["expiresDate"], - isSessionOnly: cookieMap["isSessionOnly"], - domain: cookieMap["domain"], - sameSite: HTTPCookieSameSitePolicy.fromNativeValue( - cookieMap["sameSite"], - ), - isSecure: cookieMap["isSecure"], - isHttpOnly: cookieMap["isHttpOnly"], - path: cookieMap["path"], - ), - ); - }); - return cookies; - } - - Future _getCookieExpirationDate(int expiresDate) async { - var platformUtil = PlatformUtil.instance(); - var dateTime = DateTime.fromMillisecondsSinceEpoch(expiresDate).toUtc(); - return await platformUtil.formatDate( - date: dateTime, - format: 'EEE, dd MMM yyyy HH:mm:ss z', - locale: 'en_US', - timezone: 'GMT', - ); - } - - Future _shouldUseJavascript() async { - final platformUtil = PlatformUtil.instance(); - final systemVersion = await platformUtil.getSystemVersion(); - return systemVersion.compareTo("11") == -1; - } - - @override - void dispose() { - // empty - } -} - -extension InternalCookieManager on MacOSCookieManager { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_macos/lib/src/find_interaction/find_interaction_controller.dart b/flutter_inappwebview_macos/lib/src/find_interaction/find_interaction_controller.dart deleted file mode 100644 index 3ac58792b8..0000000000 --- a/flutter_inappwebview_macos/lib/src/find_interaction/find_interaction_controller.dart +++ /dev/null @@ -1,145 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [MacOSFindInteractionController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformFindInteractionControllerCreationParams] for -/// more information. -@immutable -class MacOSFindInteractionControllerCreationParams - extends PlatformFindInteractionControllerCreationParams { - /// Creates a new [MacOSFindInteractionControllerCreationParams] instance. - const MacOSFindInteractionControllerCreationParams({ - super.onFindResultReceived, - }); - - /// Creates a [MacOSFindInteractionControllerCreationParams] instance based on [PlatformFindInteractionControllerCreationParams]. - factory MacOSFindInteractionControllerCreationParams.fromPlatformFindInteractionControllerCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformFindInteractionControllerCreationParams params, - ) { - return MacOSFindInteractionControllerCreationParams( - onFindResultReceived: params.onFindResultReceived, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController} -class MacOSFindInteractionController extends PlatformFindInteractionController - with ChannelController { - /// Constructs a [MacOSFindInteractionController]. - MacOSFindInteractionController( - PlatformFindInteractionControllerCreationParams params, - ) : super.implementation( - params is MacOSFindInteractionControllerCreationParams - ? params - : MacOSFindInteractionControllerCreationParams.fromPlatformFindInteractionControllerCreationParams( - params, - ), - ); - - static final MacOSFindInteractionController _staticValue = - MacOSFindInteractionController( - MacOSFindInteractionControllerCreationParams(), - ); - - /// Provide static access. - factory MacOSFindInteractionController.static() { - return _staticValue; - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - debugLoggingSettings: - PlatformFindInteractionController.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - _debugLog(call.method, call.arguments); - - switch (call.method) { - case "onFindResultReceived": - if (onFindResultReceived != null) { - int activeMatchOrdinal = call.arguments["activeMatchOrdinal"]; - int numberOfMatches = call.arguments["numberOfMatches"]; - bool isDoneCounting = call.arguments["isDoneCounting"]; - onFindResultReceived!( - this, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findAll} - Future findAll({String? find}) async { - Map args = {}; - args.putIfAbsent('find', () => find); - await channel?.invokeMethod('findAll', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findNext} - Future findNext({bool forward = true}) async { - Map args = {}; - args.putIfAbsent('forward', () => forward); - await channel?.invokeMethod('findNext', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.clearMatches} - Future clearMatches() async { - Map args = {}; - await channel?.invokeMethod('clearMatches', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.setSearchText} - Future setSearchText(String? searchText) async { - Map args = {}; - args.putIfAbsent('searchText', () => searchText); - await channel?.invokeMethod('setSearchText', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getSearchText} - Future getSearchText() async { - Map args = {}; - return await channel?.invokeMethod('getSearchText', args); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getActiveFindSession} - Future getActiveFindSession() async { - Map args = {}; - Map? result = (await channel?.invokeMethod( - 'getActiveFindSession', - args, - ))?.cast(); - return FindSession.fromMap(result); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.dispose} - @override - void dispose({bool isKeepAlive = false}) { - disposeChannel(removeMethodCallHandler: !isKeepAlive); - } -} - -extension InternalFindInteractionController on MacOSFindInteractionController { - void init(dynamic id) { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_find_interaction_$id', - ); - handler = _handleMethod; - initMethodCallHandler(); - } -} diff --git a/flutter_inappwebview_macos/lib/src/find_interaction/main.dart b/flutter_inappwebview_macos/lib/src/find_interaction/main.dart deleted file mode 100644 index a7adaacf7b..0000000000 --- a/flutter_inappwebview_macos/lib/src/find_interaction/main.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'find_interaction_controller.dart' - hide InternalFindInteractionController; diff --git a/flutter_inappwebview_macos/lib/src/http_auth_credentials_database.dart b/flutter_inappwebview_macos/lib/src/http_auth_credentials_database.dart deleted file mode 100755 index b92e939ff1..0000000000 --- a/flutter_inappwebview_macos/lib/src/http_auth_credentials_database.dart +++ /dev/null @@ -1,176 +0,0 @@ -import 'dart:async'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [MacOSHttpAuthCredentialDatabase]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformHttpAuthCredentialDatabaseCreationParams] for -/// more information. -@immutable -class MacOSHttpAuthCredentialDatabaseCreationParams - extends PlatformHttpAuthCredentialDatabaseCreationParams { - /// Creates a new [MacOSHttpAuthCredentialDatabaseCreationParams] instance. - const MacOSHttpAuthCredentialDatabaseCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) : super(); - - /// Creates a [MacOSHttpAuthCredentialDatabaseCreationParams] instance based on [PlatformHttpAuthCredentialDatabaseCreationParams]. - factory MacOSHttpAuthCredentialDatabaseCreationParams.fromPlatformHttpAuthCredentialDatabaseCreationParams( - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) { - return MacOSHttpAuthCredentialDatabaseCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformHttpAuthCredentialDatabase} -class MacOSHttpAuthCredentialDatabase extends PlatformHttpAuthCredentialDatabase - with ChannelController { - /// Creates a new [MacOSHttpAuthCredentialDatabase]. - MacOSHttpAuthCredentialDatabase( - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) : super.implementation( - params is MacOSHttpAuthCredentialDatabaseCreationParams - ? params - : MacOSHttpAuthCredentialDatabaseCreationParams.fromPlatformHttpAuthCredentialDatabaseCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_credential_database', - ); - handler = handleMethod; - initMethodCallHandler(); - } - - static MacOSHttpAuthCredentialDatabase? _instance; - - ///Gets the database shared instance. - static MacOSHttpAuthCredentialDatabase instance() { - return (_instance != null) ? _instance! : _init(); - } - - static MacOSHttpAuthCredentialDatabase _init() { - _instance = MacOSHttpAuthCredentialDatabase( - MacOSHttpAuthCredentialDatabaseCreationParams( - const PlatformHttpAuthCredentialDatabaseCreationParams(), - ), - ); - return _instance!; - } - - static final MacOSHttpAuthCredentialDatabase _staticValue = - MacOSHttpAuthCredentialDatabase( - MacOSHttpAuthCredentialDatabaseCreationParams( - const PlatformHttpAuthCredentialDatabaseCreationParams(), - ), - ); - - factory MacOSHttpAuthCredentialDatabase.static() { - return _staticValue; - } - - Future _handleMethod(MethodCall call) async {} - - @override - Future> - getAllAuthCredentials() async { - Map args = {}; - List allCredentials = - await channel?.invokeMethod('getAllAuthCredentials', args) ?? []; - - List result = []; - - for (Map map in allCredentials) { - var element = URLProtectionSpaceHttpAuthCredentials.fromMap( - map.cast(), - ); - if (element != null) { - result.add(element); - } - } - return result; - } - - @override - Future> getHttpAuthCredentials({ - required URLProtectionSpace protectionSpace, - }) async { - Map args = {}; - args.putIfAbsent("host", () => protectionSpace.host); - args.putIfAbsent("protocol", () => protectionSpace.protocol); - args.putIfAbsent("realm", () => protectionSpace.realm); - args.putIfAbsent("port", () => protectionSpace.port); - List credentialList = - await channel?.invokeMethod('getHttpAuthCredentials', args) ?? []; - List credentials = []; - for (Map map in credentialList) { - var credential = URLCredential.fromMap(map.cast()); - if (credential != null) { - credentials.add(credential); - } - } - return credentials; - } - - @override - Future setHttpAuthCredential({ - required URLProtectionSpace protectionSpace, - required URLCredential credential, - }) async { - Map args = {}; - args.putIfAbsent("host", () => protectionSpace.host); - args.putIfAbsent("protocol", () => protectionSpace.protocol); - args.putIfAbsent("realm", () => protectionSpace.realm); - args.putIfAbsent("port", () => protectionSpace.port); - args.putIfAbsent("username", () => credential.username); - args.putIfAbsent("password", () => credential.password); - await channel?.invokeMethod('setHttpAuthCredential', args); - } - - @override - Future removeHttpAuthCredential({ - required URLProtectionSpace protectionSpace, - required URLCredential credential, - }) async { - Map args = {}; - args.putIfAbsent("host", () => protectionSpace.host); - args.putIfAbsent("protocol", () => protectionSpace.protocol); - args.putIfAbsent("realm", () => protectionSpace.realm); - args.putIfAbsent("port", () => protectionSpace.port); - args.putIfAbsent("username", () => credential.username); - args.putIfAbsent("password", () => credential.password); - await channel?.invokeMethod('removeHttpAuthCredential', args); - } - - @override - Future removeHttpAuthCredentials({ - required URLProtectionSpace protectionSpace, - }) async { - Map args = {}; - args.putIfAbsent("host", () => protectionSpace.host); - args.putIfAbsent("protocol", () => protectionSpace.protocol); - args.putIfAbsent("realm", () => protectionSpace.realm); - args.putIfAbsent("port", () => protectionSpace.port); - await channel?.invokeMethod('removeHttpAuthCredentials', args); - } - - @override - Future clearAllAuthCredentials() async { - Map args = {}; - await channel?.invokeMethod('clearAllAuthCredentials', args); - } - - @override - void dispose() { - // empty - } -} - -extension InternalHttpAuthCredentialDatabase - on MacOSHttpAuthCredentialDatabase { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_macos/lib/src/in_app_browser/in_app_browser.dart b/flutter_inappwebview_macos/lib/src/in_app_browser/in_app_browser.dart deleted file mode 100755 index 32dfc530a8..0000000000 --- a/flutter_inappwebview_macos/lib/src/in_app_browser/in_app_browser.dart +++ /dev/null @@ -1,402 +0,0 @@ -import 'dart:async'; -import 'dart:collection'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../find_interaction/find_interaction_controller.dart'; -import '../in_app_webview/in_app_webview_controller.dart'; - -/// Object specifying creation parameters for creating a [MacOSInAppBrowser]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformInAppBrowserCreationParams] for -/// more information. -class MacOSInAppBrowserCreationParams - extends PlatformInAppBrowserCreationParams { - /// Creates a new [MacOSInAppBrowserCreationParams] instance. - MacOSInAppBrowserCreationParams({ - super.contextMenu, - super.pullToRefreshController, - this.findInteractionController, - super.initialUserScripts, - super.windowId, - }); - - /// Creates a [MacOSInAppBrowserCreationParams] instance based on [PlatformInAppBrowserCreationParams]. - factory MacOSInAppBrowserCreationParams.fromPlatformInAppBrowserCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformInAppBrowserCreationParams params, - ) { - return MacOSInAppBrowserCreationParams( - contextMenu: params.contextMenu, - pullToRefreshController: params.pullToRefreshController, - findInteractionController: - params.findInteractionController as MacOSFindInteractionController?, - initialUserScripts: params.initialUserScripts, - windowId: params.windowId, - ); - } - - @override - final MacOSFindInteractionController? findInteractionController; -} - -///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser} -class MacOSInAppBrowser extends PlatformInAppBrowser with ChannelController { - @override - final String id = IdGenerator.generate(); - - /// Constructs a [MacOSInAppBrowser]. - MacOSInAppBrowser(PlatformInAppBrowserCreationParams params) - : super.implementation( - params is MacOSInAppBrowserCreationParams - ? params - : MacOSInAppBrowserCreationParams.fromPlatformInAppBrowserCreationParams( - params, - ), - ) { - _contextMenu = params.contextMenu; - } - - static final MacOSInAppBrowser _staticValue = MacOSInAppBrowser( - MacOSInAppBrowserCreationParams(), - ); - - /// Provide static access. - factory MacOSInAppBrowser.static() { - return _staticValue; - } - - MacOSInAppBrowserCreationParams get _macosParams => - params as MacOSInAppBrowserCreationParams; - - static const MethodChannel _staticChannel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappbrowser', - ); - - ContextMenu? _contextMenu; - - @override - ContextMenu? get contextMenu => _contextMenu; - - Map _menuItems = HashMap(); - bool _isOpened = false; - MacOSInAppWebViewController? _webViewController; - - @override - MacOSInAppWebViewController? get webViewController { - return _isOpened ? _webViewController : null; - } - - _init() { - channel = MethodChannel('com.pichillilorenzo/flutter_inappbrowser_$id'); - handler = _handleMethod; - initMethodCallHandler(); - - _webViewController = MacOSInAppWebViewController.fromInAppBrowser( - MacOSInAppWebViewControllerCreationParams(id: id), - channel!, - this, - this.initialUserScripts, - ); - _macosParams.findInteractionController?.init(id); - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - id: id, - debugLoggingSettings: PlatformInAppBrowser.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onBrowserCreated": - _debugLog(call.method, call.arguments); - eventHandler?.onBrowserCreated(); - break; - case "onMenuItemClicked": - _debugLog(call.method, call.arguments); - int id = call.arguments["id"].toInt(); - if (this._menuItems[id] != null) { - if (this._menuItems[id]?.onClick != null) { - this._menuItems[id]?.onClick!(); - } - } - break; - case "onMainWindowWillClose": - _debugLog(call.method, call.arguments); - eventHandler?.onMainWindowWillClose(); - break; - case "onExit": - _debugLog(call.method, call.arguments); - _isOpened = false; - final onExit = eventHandler?.onExit; - dispose(); - onExit?.call(); - break; - default: - return _webViewController?.handleMethod(call); - } - } - - Map _prepareOpenRequest({ - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) { - assert(!_isOpened, 'The browser is already opened.'); - _isOpened = true; - _init(); - - var initialSettings = - settings?.toMap() ?? - options?.toMap() ?? - InAppBrowserClassSettings().toMap(); - - Map pullToRefreshSettings = - pullToRefreshController?.settings.toMap() ?? - pullToRefreshController?.options.toMap() ?? - PullToRefreshSettings(enabled: false).toMap(); - - List> menuItemList = []; - _menuItems.forEach((key, value) { - menuItemList.add(value.toMap()); - }); - - Map args = {}; - args.putIfAbsent('id', () => id); - args.putIfAbsent('settings', () => initialSettings); - args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {}); - args.putIfAbsent('windowId', () => windowId); - args.putIfAbsent( - 'initialUserScripts', - () => initialUserScripts?.map((e) => e.toMap()).toList() ?? [], - ); - args.putIfAbsent('pullToRefreshSettings', () => pullToRefreshSettings); - args.putIfAbsent('menuItems', () => menuItemList); - return args; - } - - @override - Future openUrlRequest({ - required URLRequest urlRequest, - // ignore: deprecated_member_use_from_same_package - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) async { - assert(urlRequest.url != null && urlRequest.url.toString().isNotEmpty); - - Map args = _prepareOpenRequest( - options: options, - settings: settings, - ); - args.putIfAbsent('urlRequest', () => urlRequest.toMap()); - await _staticChannel.invokeMethod('open', args); - } - - @override - Future openFile({ - required String assetFilePath, - // ignore: deprecated_member_use_from_same_package - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) async { - assert(assetFilePath.isNotEmpty); - - Map args = _prepareOpenRequest( - options: options, - settings: settings, - ); - args.putIfAbsent('assetFilePath', () => assetFilePath); - await _staticChannel.invokeMethod('open', args); - } - - @override - Future openData({ - required String data, - String mimeType = "text/html", - String encoding = "utf8", - WebUri? baseUrl, - @Deprecated("Use historyUrl instead") Uri? androidHistoryUrl, - WebUri? historyUrl, - // ignore: deprecated_member_use_from_same_package - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) async { - Map args = _prepareOpenRequest( - options: options, - settings: settings, - ); - args.putIfAbsent('data', () => data); - args.putIfAbsent('mimeType', () => mimeType); - args.putIfAbsent('encoding', () => encoding); - args.putIfAbsent('baseUrl', () => baseUrl?.toString() ?? "about:blank"); - args.putIfAbsent( - 'historyUrl', - () => (historyUrl ?? androidHistoryUrl)?.toString() ?? "about:blank", - ); - await _staticChannel.invokeMethod('open', args); - } - - @override - Future openWithSystemBrowser({required WebUri url}) async { - assert(url.toString().isNotEmpty); - - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - return await _staticChannel.invokeMethod('openWithSystemBrowser', args); - } - - @override - void addMenuItem(InAppBrowserMenuItem menuItem) { - _menuItems[menuItem.id] = menuItem; - } - - @override - void addMenuItems(List menuItems) { - menuItems.forEach((menuItem) { - _menuItems[menuItem.id] = menuItem; - }); - } - - @override - bool removeMenuItem(InAppBrowserMenuItem menuItem) { - return _menuItems.remove(menuItem.id) != null; - } - - @override - void removeMenuItems(List menuItems) { - for (final menuItem in menuItems) { - removeMenuItem(menuItem); - } - } - - @override - void removeAllMenuItem() { - _menuItems.clear(); - } - - @override - bool hasMenuItem(InAppBrowserMenuItem menuItem) { - return _menuItems.containsKey(menuItem.id); - } - - @override - Future show() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - await channel?.invokeMethod('show', args); - } - - @override - Future hide() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - await channel?.invokeMethod('hide', args); - } - - @override - Future close() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - await channel?.invokeMethod('close', args); - } - - @override - Future isHidden() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - return await channel?.invokeMethod('isHidden', args) ?? false; - } - - @override - @Deprecated('Use setSettings instead') - Future setOptions({required InAppBrowserClassOptions options}) async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - args.putIfAbsent('settings', () => options.toMap()); - await channel?.invokeMethod('setSettings', args); - } - - @override - @Deprecated('Use getSettings instead') - Future getOptions() async { - assert(_isOpened, 'The browser is not opened.'); - Map args = {}; - - Map? options = await channel?.invokeMethod( - 'getSettings', - args, - ); - if (options != null) { - options = options.cast(); - return InAppBrowserClassOptions.fromMap(options as Map); - } - - return null; - } - - @override - Future setSettings({ - required InAppBrowserClassSettings settings, - }) async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - args.putIfAbsent('settings', () => settings.toMap()); - await channel?.invokeMethod('setSettings', args); - } - - @override - Future getSettings() async { - assert(_isOpened, 'The browser is not opened.'); - - Map args = {}; - - Map? settings = await channel?.invokeMethod( - 'getSettings', - args, - ); - if (settings != null) { - settings = settings.cast(); - return InAppBrowserClassSettings.fromMap( - settings as Map, - ); - } - - return null; - } - - @override - bool isOpened() { - return this._isOpened; - } - - @override - @mustCallSuper - void dispose() { - super.dispose(); - disposeChannel(); - _webViewController?.dispose(); - _webViewController = null; - pullToRefreshController?.dispose(); - findInteractionController?.dispose(); - } -} - -extension InternalInAppBrowser on MacOSInAppBrowser { - void setContextMenu(ContextMenu? contextMenu) { - _contextMenu = contextMenu; - } -} diff --git a/flutter_inappwebview_macos/lib/src/in_app_browser/main.dart b/flutter_inappwebview_macos/lib/src/in_app_browser/main.dart deleted file mode 100644 index e11eb8b182..0000000000 --- a/flutter_inappwebview_macos/lib/src/in_app_browser/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'in_app_browser.dart' hide InternalInAppBrowser; diff --git a/flutter_inappwebview_macos/lib/src/in_app_webview/_static_channel.dart b/flutter_inappwebview_macos/lib/src/in_app_webview/_static_channel.dart deleted file mode 100644 index a02f01ece1..0000000000 --- a/flutter_inappwebview_macos/lib/src/in_app_webview/_static_channel.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:flutter/services.dart'; - -const IN_APP_WEBVIEW_STATIC_CHANNEL = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_manager', -); diff --git a/flutter_inappwebview_macos/lib/src/in_app_webview/headless_in_app_webview.dart b/flutter_inappwebview_macos/lib/src/in_app_webview/headless_in_app_webview.dart deleted file mode 100644 index 466b964886..0000000000 --- a/flutter_inappwebview_macos/lib/src/in_app_webview/headless_in_app_webview.dart +++ /dev/null @@ -1,457 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import '../find_interaction/find_interaction_controller.dart'; -import 'in_app_webview_controller.dart'; - -/// Object specifying creation parameters for creating a [MacOSHeadlessInAppWebView]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformHeadlessInAppWebViewCreationParams] for -/// more information. -@immutable -class MacOSHeadlessInAppWebViewCreationParams - extends PlatformHeadlessInAppWebViewCreationParams { - /// Creates a new [MacOSHeadlessInAppWebViewCreationParams] instance. - MacOSHeadlessInAppWebViewCreationParams({ - super.controllerFromPlatform, - super.initialSize, - super.windowId, - super.onWebViewCreated, - super.onLoadStart, - super.onLoadStop, - @Deprecated('Use onReceivedError instead') super.onLoadError, - super.onReceivedError, - @Deprecated("Use onReceivedHttpError instead") super.onLoadHttpError, - super.onReceivedHttpError, - super.onProgressChanged, - super.onConsoleMessage, - super.shouldOverrideUrlLoading, - super.onLoadResource, - super.onScrollChanged, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStart, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStartRequest, - super.onDownloadStarting, - @Deprecated('Use onLoadResourceWithCustomScheme instead') - super.onLoadResourceCustomScheme, - super.onLoadResourceWithCustomScheme, - super.onCreateWindow, - super.onCloseWindow, - super.onJsAlert, - super.onJsConfirm, - super.onJsPrompt, - super.onReceivedHttpAuthRequest, - super.onReceivedServerTrustAuthRequest, - super.onReceivedClientCertRequest, - @Deprecated('Use FindInteractionController.onFindResultReceived instead') - super.onFindResultReceived, - super.shouldInterceptAjaxRequest, - super.onAjaxReadyStateChange, - super.onAjaxProgress, - super.shouldInterceptFetchRequest, - super.onUpdateVisitedHistory, - @Deprecated("Use onPrintRequest instead") super.onPrint, - super.onPrintRequest, - super.onLongPressHitTestResult, - super.onEnterFullscreen, - super.onExitFullscreen, - super.onPageCommitVisible, - super.onTitleChanged, - super.onWindowFocus, - super.onWindowBlur, - super.onOverScrolled, - super.onZoomScaleChanged, - @Deprecated('Use onSafeBrowsingHit instead') super.androidOnSafeBrowsingHit, - super.onSafeBrowsingHit, - @Deprecated('Use onPermissionRequest instead') - super.androidOnPermissionRequest, - super.onPermissionRequest, - @Deprecated('Use onGeolocationPermissionsShowPrompt instead') - super.androidOnGeolocationPermissionsShowPrompt, - super.onGeolocationPermissionsShowPrompt, - @Deprecated('Use onGeolocationPermissionsHidePrompt instead') - super.androidOnGeolocationPermissionsHidePrompt, - super.onGeolocationPermissionsHidePrompt, - @Deprecated('Use shouldInterceptRequest instead') - super.androidShouldInterceptRequest, - super.shouldInterceptRequest, - @Deprecated('Use onRenderProcessGone instead') - super.androidOnRenderProcessGone, - super.onRenderProcessGone, - @Deprecated('Use onRenderProcessResponsive instead') - super.androidOnRenderProcessResponsive, - super.onRenderProcessResponsive, - @Deprecated('Use onRenderProcessUnresponsive instead') - super.androidOnRenderProcessUnresponsive, - super.onRenderProcessUnresponsive, - @Deprecated('Use onFormResubmission instead') - super.androidOnFormResubmission, - super.onFormResubmission, - @Deprecated('Use onZoomScaleChanged instead') super.androidOnScaleChanged, - @Deprecated('Use onReceivedIcon instead') super.androidOnReceivedIcon, - super.onReceivedIcon, - @Deprecated('Use onReceivedTouchIconUrl instead') - super.androidOnReceivedTouchIconUrl, - super.onReceivedTouchIconUrl, - @Deprecated('Use onJsBeforeUnload instead') super.androidOnJsBeforeUnload, - super.onJsBeforeUnload, - @Deprecated('Use onReceivedLoginRequest instead') - super.androidOnReceivedLoginRequest, - super.onReceivedLoginRequest, - super.onPermissionRequestCanceled, - super.onRequestFocus, - @Deprecated('Use onWebContentProcessDidTerminate instead') - super.iosOnWebContentProcessDidTerminate, - super.onWebContentProcessDidTerminate, - @Deprecated( - 'Use onDidReceiveServerRedirectForProvisionalNavigation instead', - ) - super.iosOnDidReceiveServerRedirectForProvisionalNavigation, - super.onDidReceiveServerRedirectForProvisionalNavigation, - @Deprecated('Use onNavigationResponse instead') - super.iosOnNavigationResponse, - super.onNavigationResponse, - @Deprecated('Use shouldAllowDeprecatedTLS instead') - super.iosShouldAllowDeprecatedTLS, - super.shouldAllowDeprecatedTLS, - super.onCameraCaptureStateChanged, - super.onMicrophoneCaptureStateChanged, - super.onContentSizeChanged, - super.initialUrlRequest, - super.initialFile, - super.initialData, - @Deprecated('Use initialSettings instead') super.initialOptions, - super.initialSettings, - super.contextMenu, - super.initialUserScripts, - super.pullToRefreshController, - this.findInteractionController, - }); - - /// Creates a [MacOSHeadlessInAppWebViewCreationParams] instance based on [PlatformHeadlessInAppWebViewCreationParams]. - MacOSHeadlessInAppWebViewCreationParams.fromPlatformHeadlessInAppWebViewCreationParams( - PlatformHeadlessInAppWebViewCreationParams params, - ) : this( - controllerFromPlatform: params.controllerFromPlatform, - initialSize: params.initialSize, - windowId: params.windowId, - onWebViewCreated: params.onWebViewCreated, - onLoadStart: params.onLoadStart, - onLoadStop: params.onLoadStop, - onLoadError: params.onLoadError, - onReceivedError: params.onReceivedError, - onLoadHttpError: params.onLoadHttpError, - onReceivedHttpError: params.onReceivedHttpError, - onProgressChanged: params.onProgressChanged, - onConsoleMessage: params.onConsoleMessage, - shouldOverrideUrlLoading: params.shouldOverrideUrlLoading, - onLoadResource: params.onLoadResource, - onScrollChanged: params.onScrollChanged, - onDownloadStart: params.onDownloadStart, - onDownloadStartRequest: params.onDownloadStartRequest, - onDownloadStarting: params.onDownloadStarting, - onLoadResourceCustomScheme: params.onLoadResourceCustomScheme, - onLoadResourceWithCustomScheme: params.onLoadResourceWithCustomScheme, - onCreateWindow: params.onCreateWindow, - onCloseWindow: params.onCloseWindow, - onJsAlert: params.onJsAlert, - onJsConfirm: params.onJsConfirm, - onJsPrompt: params.onJsPrompt, - onReceivedHttpAuthRequest: params.onReceivedHttpAuthRequest, - onReceivedServerTrustAuthRequest: - params.onReceivedServerTrustAuthRequest, - onReceivedClientCertRequest: params.onReceivedClientCertRequest, - onFindResultReceived: params.onFindResultReceived, - shouldInterceptAjaxRequest: params.shouldInterceptAjaxRequest, - onAjaxReadyStateChange: params.onAjaxReadyStateChange, - onAjaxProgress: params.onAjaxProgress, - shouldInterceptFetchRequest: params.shouldInterceptFetchRequest, - onUpdateVisitedHistory: params.onUpdateVisitedHistory, - onPrint: params.onPrint, - onPrintRequest: params.onPrintRequest, - onLongPressHitTestResult: params.onLongPressHitTestResult, - onEnterFullscreen: params.onEnterFullscreen, - onExitFullscreen: params.onExitFullscreen, - onPageCommitVisible: params.onPageCommitVisible, - onTitleChanged: params.onTitleChanged, - onWindowFocus: params.onWindowFocus, - onWindowBlur: params.onWindowBlur, - onOverScrolled: params.onOverScrolled, - onZoomScaleChanged: params.onZoomScaleChanged, - androidOnSafeBrowsingHit: params.androidOnSafeBrowsingHit, - onSafeBrowsingHit: params.onSafeBrowsingHit, - androidOnPermissionRequest: params.androidOnPermissionRequest, - onPermissionRequest: params.onPermissionRequest, - androidOnGeolocationPermissionsShowPrompt: - params.androidOnGeolocationPermissionsShowPrompt, - onGeolocationPermissionsShowPrompt: - params.onGeolocationPermissionsShowPrompt, - androidOnGeolocationPermissionsHidePrompt: - params.androidOnGeolocationPermissionsHidePrompt, - onGeolocationPermissionsHidePrompt: - params.onGeolocationPermissionsHidePrompt, - androidShouldInterceptRequest: params.androidShouldInterceptRequest, - shouldInterceptRequest: params.shouldInterceptRequest, - androidOnRenderProcessGone: params.androidOnRenderProcessGone, - onRenderProcessGone: params.onRenderProcessGone, - androidOnRenderProcessResponsive: - params.androidOnRenderProcessResponsive, - onRenderProcessResponsive: params.onRenderProcessResponsive, - androidOnRenderProcessUnresponsive: - params.androidOnRenderProcessUnresponsive, - onRenderProcessUnresponsive: params.onRenderProcessUnresponsive, - androidOnFormResubmission: params.androidOnFormResubmission, - onFormResubmission: params.onFormResubmission, - androidOnScaleChanged: params.androidOnScaleChanged, - androidOnReceivedIcon: params.androidOnReceivedIcon, - onReceivedIcon: params.onReceivedIcon, - androidOnReceivedTouchIconUrl: params.androidOnReceivedTouchIconUrl, - onReceivedTouchIconUrl: params.onReceivedTouchIconUrl, - androidOnJsBeforeUnload: params.androidOnJsBeforeUnload, - onJsBeforeUnload: params.onJsBeforeUnload, - androidOnReceivedLoginRequest: params.androidOnReceivedLoginRequest, - onReceivedLoginRequest: params.onReceivedLoginRequest, - onPermissionRequestCanceled: params.onPermissionRequestCanceled, - onRequestFocus: params.onRequestFocus, - iosOnWebContentProcessDidTerminate: - params.iosOnWebContentProcessDidTerminate, - onWebContentProcessDidTerminate: params.onWebContentProcessDidTerminate, - iosOnDidReceiveServerRedirectForProvisionalNavigation: - params.iosOnDidReceiveServerRedirectForProvisionalNavigation, - onDidReceiveServerRedirectForProvisionalNavigation: - params.onDidReceiveServerRedirectForProvisionalNavigation, - iosOnNavigationResponse: params.iosOnNavigationResponse, - onNavigationResponse: params.onNavigationResponse, - iosShouldAllowDeprecatedTLS: params.iosShouldAllowDeprecatedTLS, - shouldAllowDeprecatedTLS: params.shouldAllowDeprecatedTLS, - onCameraCaptureStateChanged: params.onCameraCaptureStateChanged, - onMicrophoneCaptureStateChanged: params.onMicrophoneCaptureStateChanged, - onContentSizeChanged: params.onContentSizeChanged, - initialUrlRequest: params.initialUrlRequest, - initialFile: params.initialFile, - initialData: params.initialData, - initialOptions: params.initialOptions, - initialSettings: params.initialSettings, - contextMenu: params.contextMenu, - initialUserScripts: params.initialUserScripts, - pullToRefreshController: params.pullToRefreshController, - findInteractionController: - params.findInteractionController as MacOSFindInteractionController?, - ); - - @override - final MacOSFindInteractionController? findInteractionController; -} - -///{@macro flutter_inappwebview_platform_interface.PlatformHeadlessInAppWebView} -class MacOSHeadlessInAppWebView extends PlatformHeadlessInAppWebView - with ChannelController { - @override - late final String id; - - bool _started = false; - bool _running = false; - - static const MethodChannel _sharedChannel = const MethodChannel( - 'com.pichillilorenzo/flutter_headless_inappwebview', - ); - - MacOSInAppWebViewController? _webViewController; - - /// Constructs a [MacOSHeadlessInAppWebView]. - MacOSHeadlessInAppWebView(PlatformHeadlessInAppWebViewCreationParams params) - : super.implementation( - params is MacOSHeadlessInAppWebViewCreationParams - ? params - : MacOSHeadlessInAppWebViewCreationParams.fromPlatformHeadlessInAppWebViewCreationParams( - params, - ), - ) { - id = IdGenerator.generate(); - } - - static final MacOSHeadlessInAppWebView _staticValue = - MacOSHeadlessInAppWebView(MacOSHeadlessInAppWebViewCreationParams()); - - factory MacOSHeadlessInAppWebView.static() { - return _staticValue; - } - - @override - MacOSInAppWebViewController? get webViewController => _webViewController; - - dynamic _controllerFromPlatform; - - MacOSHeadlessInAppWebViewCreationParams get _macosParams => - params as MacOSHeadlessInAppWebViewCreationParams; - - _init() { - _webViewController = MacOSInAppWebViewController( - MacOSInAppWebViewControllerCreationParams(id: id, webviewParams: params), - ); - _controllerFromPlatform = - params.controllerFromPlatform?.call(_webViewController!) ?? - _webViewController!; - _macosParams.findInteractionController?.init(id); - channel = MethodChannel( - 'com.pichillilorenzo/flutter_headless_inappwebview_$id', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onWebViewCreated": - if (params.onWebViewCreated != null && _webViewController != null) { - params.onWebViewCreated!(_controllerFromPlatform); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - Future run() async { - if (_started) { - return; - } - _started = true; - _init(); - - final initialSettings = params.initialSettings ?? InAppWebViewSettings(); - _inferInitialSettings(initialSettings); - - Map settingsMap = - (params.initialSettings != null ? initialSettings.toMap() : null) ?? - params.initialOptions?.toMap() ?? - initialSettings.toMap(); - - Map pullToRefreshSettings = - _macosParams.pullToRefreshController?.params.settings.toMap() ?? - _macosParams.pullToRefreshController?.params.options.toMap() ?? - PullToRefreshSettings(enabled: false).toMap(); - - Map args = {}; - args.putIfAbsent('id', () => id); - args.putIfAbsent( - 'params', - () => { - 'initialUrlRequest': params.initialUrlRequest?.toMap(), - 'initialFile': params.initialFile, - 'initialData': params.initialData?.toMap(), - 'initialSettings': settingsMap, - 'contextMenu': params.contextMenu?.toMap() ?? {}, - 'windowId': params.windowId, - 'initialUserScripts': - params.initialUserScripts?.map((e) => e.toMap()).toList() ?? [], - 'pullToRefreshSettings': pullToRefreshSettings, - 'initialSize': params.initialSize.toMap(), - }, - ); - await _sharedChannel.invokeMethod('run', args); - _running = true; - } - - void _inferInitialSettings(InAppWebViewSettings settings) { - if (params.shouldOverrideUrlLoading != null && - settings.useShouldOverrideUrlLoading == null) { - settings.useShouldOverrideUrlLoading = true; - } - if (params.onLoadResource != null && settings.useOnLoadResource == null) { - settings.useOnLoadResource = true; - } - if ((params.onDownloadStartRequest != null || - params.onDownloadStarting != null) && - settings.useOnDownloadStart == null) { - settings.useOnDownloadStart = true; - } - if ((params.shouldInterceptAjaxRequest != null || - params.onAjaxProgress != null || - params.onAjaxReadyStateChange != null)) { - if (settings.useShouldInterceptAjaxRequest == null) { - settings.useShouldInterceptAjaxRequest = true; - } - if (params.onAjaxReadyStateChange != null && - settings.useOnAjaxReadyStateChange == null) { - settings.useOnAjaxReadyStateChange = true; - } - if (params.onAjaxProgress != null && settings.useOnAjaxProgress == null) { - settings.useOnAjaxProgress = true; - } - } - if (params.shouldInterceptFetchRequest != null && - settings.useShouldInterceptFetchRequest == null) { - settings.useShouldInterceptFetchRequest = true; - } - if (params.shouldInterceptRequest != null && - settings.useShouldInterceptRequest == null) { - settings.useShouldInterceptRequest = true; - } - if (params.onRenderProcessGone != null && - settings.useOnRenderProcessGone == null) { - settings.useOnRenderProcessGone = true; - } - if (params.onNavigationResponse != null && - settings.useOnNavigationResponse == null) { - settings.useOnNavigationResponse = true; - } - } - - @override - bool isRunning() { - return _running; - } - - @override - Future setSize(Size size) async { - if (!_running) { - return; - } - - Map args = {}; - args.putIfAbsent('size', () => size.toMap()); - await channel?.invokeMethod('setSize', args); - } - - @override - Future getSize() async { - if (!_running) { - return null; - } - - Map args = {}; - Map sizeMap = (await channel?.invokeMethod( - 'getSize', - args, - ))?.cast(); - return MapSize.fromMap(sizeMap); - } - - @override - Future dispose() async { - if (!_running) { - return; - } - Map args = {}; - await channel?.invokeMethod('dispose', args); - disposeChannel(); - _started = false; - _running = false; - _webViewController?.dispose(); - _webViewController = null; - _controllerFromPlatform = null; - _macosParams.pullToRefreshController?.dispose(); - _macosParams.findInteractionController?.dispose(); - } -} - -extension InternalHeadlessInAppWebView on MacOSHeadlessInAppWebView { - Future internalDispose() async { - _started = false; - _running = false; - } -} diff --git a/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview.dart b/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview.dart deleted file mode 100755 index b9528f5196..0000000000 --- a/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview.dart +++ /dev/null @@ -1,431 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../find_interaction/find_interaction_controller.dart'; -import 'headless_in_app_webview.dart'; -import 'in_app_webview_controller.dart'; - -/// Object specifying creation parameters for creating a [PlatformInAppWebViewWidget]. -/// -/// Platform specific implementations can add additional fields by extending -/// this class. -class MacOSInAppWebViewWidgetCreationParams - extends PlatformInAppWebViewWidgetCreationParams { - MacOSInAppWebViewWidgetCreationParams({ - super.controllerFromPlatform, - super.key, - super.layoutDirection, - super.gestureRecognizers, - super.headlessWebView, - super.keepAlive, - super.preventGestureDelay, - super.windowId, - super.onWebViewCreated, - super.onLoadStart, - super.onLoadStop, - @Deprecated('Use onReceivedError instead') super.onLoadError, - super.onReceivedError, - @Deprecated("Use onReceivedHttpError instead") super.onLoadHttpError, - super.onReceivedHttpError, - super.onProgressChanged, - super.onConsoleMessage, - super.shouldOverrideUrlLoading, - super.onLoadResource, - super.onScrollChanged, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStart, - @Deprecated('Use onDownloadStarting instead') super.onDownloadStartRequest, - super.onDownloadStarting, - @Deprecated('Use onLoadResourceWithCustomScheme instead') - super.onLoadResourceCustomScheme, - super.onLoadResourceWithCustomScheme, - super.onCreateWindow, - super.onCloseWindow, - super.onJsAlert, - super.onJsConfirm, - super.onJsPrompt, - super.onReceivedHttpAuthRequest, - super.onReceivedServerTrustAuthRequest, - super.onReceivedClientCertRequest, - @Deprecated('Use FindInteractionController.onFindResultReceived instead') - super.onFindResultReceived, - super.shouldInterceptAjaxRequest, - super.onAjaxReadyStateChange, - super.onAjaxProgress, - super.shouldInterceptFetchRequest, - super.onUpdateVisitedHistory, - @Deprecated("Use onPrintRequest instead") super.onPrint, - super.onPrintRequest, - super.onLongPressHitTestResult, - super.onEnterFullscreen, - super.onExitFullscreen, - super.onPageCommitVisible, - super.onTitleChanged, - super.onWindowFocus, - super.onWindowBlur, - super.onOverScrolled, - super.onZoomScaleChanged, - @Deprecated('Use onSafeBrowsingHit instead') super.androidOnSafeBrowsingHit, - super.onSafeBrowsingHit, - @Deprecated('Use onPermissionRequest instead') - super.androidOnPermissionRequest, - super.onPermissionRequest, - @Deprecated('Use onGeolocationPermissionsShowPrompt instead') - super.androidOnGeolocationPermissionsShowPrompt, - super.onGeolocationPermissionsShowPrompt, - @Deprecated('Use onGeolocationPermissionsHidePrompt instead') - super.androidOnGeolocationPermissionsHidePrompt, - super.onGeolocationPermissionsHidePrompt, - @Deprecated('Use shouldInterceptRequest instead') - super.androidShouldInterceptRequest, - super.shouldInterceptRequest, - @Deprecated('Use onRenderProcessGone instead') - super.androidOnRenderProcessGone, - super.onRenderProcessGone, - @Deprecated('Use onRenderProcessResponsive instead') - super.androidOnRenderProcessResponsive, - super.onRenderProcessResponsive, - @Deprecated('Use onRenderProcessUnresponsive instead') - super.androidOnRenderProcessUnresponsive, - super.onRenderProcessUnresponsive, - @Deprecated('Use onFormResubmission instead') - super.androidOnFormResubmission, - super.onFormResubmission, - @Deprecated('Use onZoomScaleChanged instead') super.androidOnScaleChanged, - @Deprecated('Use onReceivedIcon instead') super.androidOnReceivedIcon, - super.onReceivedIcon, - @Deprecated('Use onReceivedTouchIconUrl instead') - super.androidOnReceivedTouchIconUrl, - super.onReceivedTouchIconUrl, - @Deprecated('Use onJsBeforeUnload instead') super.androidOnJsBeforeUnload, - super.onJsBeforeUnload, - @Deprecated('Use onReceivedLoginRequest instead') - super.androidOnReceivedLoginRequest, - super.onReceivedLoginRequest, - super.onPermissionRequestCanceled, - super.onRequestFocus, - @Deprecated('Use onWebContentProcessDidTerminate instead') - super.iosOnWebContentProcessDidTerminate, - super.onWebContentProcessDidTerminate, - @Deprecated( - 'Use onDidReceiveServerRedirectForProvisionalNavigation instead', - ) - super.iosOnDidReceiveServerRedirectForProvisionalNavigation, - super.onDidReceiveServerRedirectForProvisionalNavigation, - @Deprecated('Use onNavigationResponse instead') - super.iosOnNavigationResponse, - super.onNavigationResponse, - @Deprecated('Use shouldAllowDeprecatedTLS instead') - super.iosShouldAllowDeprecatedTLS, - super.shouldAllowDeprecatedTLS, - super.onCameraCaptureStateChanged, - super.onMicrophoneCaptureStateChanged, - super.onContentSizeChanged, - super.initialUrlRequest, - super.initialFile, - super.initialData, - @Deprecated('Use initialSettings instead') super.initialOptions, - super.initialSettings, - super.contextMenu, - super.initialUserScripts, - super.pullToRefreshController, - this.findInteractionController, - }); - - /// Constructs a [MacOSInAppWebViewWidgetCreationParams] using a - /// [PlatformInAppWebViewWidgetCreationParams]. - MacOSInAppWebViewWidgetCreationParams.fromPlatformInAppWebViewWidgetCreationParams( - PlatformInAppWebViewWidgetCreationParams params, - ) : this( - controllerFromPlatform: params.controllerFromPlatform, - key: params.key, - layoutDirection: params.layoutDirection, - gestureRecognizers: params.gestureRecognizers, - headlessWebView: params.headlessWebView, - keepAlive: params.keepAlive, - preventGestureDelay: params.preventGestureDelay, - windowId: params.windowId, - onWebViewCreated: params.onWebViewCreated, - onLoadStart: params.onLoadStart, - onLoadStop: params.onLoadStop, - onLoadError: params.onLoadError, - onReceivedError: params.onReceivedError, - onLoadHttpError: params.onLoadHttpError, - onReceivedHttpError: params.onReceivedHttpError, - onProgressChanged: params.onProgressChanged, - onConsoleMessage: params.onConsoleMessage, - shouldOverrideUrlLoading: params.shouldOverrideUrlLoading, - onLoadResource: params.onLoadResource, - onScrollChanged: params.onScrollChanged, - onDownloadStart: params.onDownloadStart, - onDownloadStartRequest: params.onDownloadStartRequest, - onDownloadStarting: params.onDownloadStarting, - onLoadResourceCustomScheme: params.onLoadResourceCustomScheme, - onLoadResourceWithCustomScheme: params.onLoadResourceWithCustomScheme, - onCreateWindow: params.onCreateWindow, - onCloseWindow: params.onCloseWindow, - onJsAlert: params.onJsAlert, - onJsConfirm: params.onJsConfirm, - onJsPrompt: params.onJsPrompt, - onReceivedHttpAuthRequest: params.onReceivedHttpAuthRequest, - onReceivedServerTrustAuthRequest: - params.onReceivedServerTrustAuthRequest, - onReceivedClientCertRequest: params.onReceivedClientCertRequest, - onFindResultReceived: params.onFindResultReceived, - shouldInterceptAjaxRequest: params.shouldInterceptAjaxRequest, - onAjaxReadyStateChange: params.onAjaxReadyStateChange, - onAjaxProgress: params.onAjaxProgress, - shouldInterceptFetchRequest: params.shouldInterceptFetchRequest, - onUpdateVisitedHistory: params.onUpdateVisitedHistory, - onPrint: params.onPrint, - onPrintRequest: params.onPrintRequest, - onLongPressHitTestResult: params.onLongPressHitTestResult, - onEnterFullscreen: params.onEnterFullscreen, - onExitFullscreen: params.onExitFullscreen, - onPageCommitVisible: params.onPageCommitVisible, - onTitleChanged: params.onTitleChanged, - onWindowFocus: params.onWindowFocus, - onWindowBlur: params.onWindowBlur, - onOverScrolled: params.onOverScrolled, - onZoomScaleChanged: params.onZoomScaleChanged, - androidOnSafeBrowsingHit: params.androidOnSafeBrowsingHit, - onSafeBrowsingHit: params.onSafeBrowsingHit, - androidOnPermissionRequest: params.androidOnPermissionRequest, - onPermissionRequest: params.onPermissionRequest, - androidOnGeolocationPermissionsShowPrompt: - params.androidOnGeolocationPermissionsShowPrompt, - onGeolocationPermissionsShowPrompt: - params.onGeolocationPermissionsShowPrompt, - androidOnGeolocationPermissionsHidePrompt: - params.androidOnGeolocationPermissionsHidePrompt, - onGeolocationPermissionsHidePrompt: - params.onGeolocationPermissionsHidePrompt, - androidShouldInterceptRequest: params.androidShouldInterceptRequest, - shouldInterceptRequest: params.shouldInterceptRequest, - androidOnRenderProcessGone: params.androidOnRenderProcessGone, - onRenderProcessGone: params.onRenderProcessGone, - androidOnRenderProcessResponsive: - params.androidOnRenderProcessResponsive, - onRenderProcessResponsive: params.onRenderProcessResponsive, - androidOnRenderProcessUnresponsive: - params.androidOnRenderProcessUnresponsive, - onRenderProcessUnresponsive: params.onRenderProcessUnresponsive, - androidOnFormResubmission: params.androidOnFormResubmission, - onFormResubmission: params.onFormResubmission, - androidOnScaleChanged: params.androidOnScaleChanged, - androidOnReceivedIcon: params.androidOnReceivedIcon, - onReceivedIcon: params.onReceivedIcon, - androidOnReceivedTouchIconUrl: params.androidOnReceivedTouchIconUrl, - onReceivedTouchIconUrl: params.onReceivedTouchIconUrl, - androidOnJsBeforeUnload: params.androidOnJsBeforeUnload, - onJsBeforeUnload: params.onJsBeforeUnload, - androidOnReceivedLoginRequest: params.androidOnReceivedLoginRequest, - onReceivedLoginRequest: params.onReceivedLoginRequest, - onPermissionRequestCanceled: params.onPermissionRequestCanceled, - onRequestFocus: params.onRequestFocus, - iosOnWebContentProcessDidTerminate: - params.iosOnWebContentProcessDidTerminate, - onWebContentProcessDidTerminate: params.onWebContentProcessDidTerminate, - iosOnDidReceiveServerRedirectForProvisionalNavigation: - params.iosOnDidReceiveServerRedirectForProvisionalNavigation, - onDidReceiveServerRedirectForProvisionalNavigation: - params.onDidReceiveServerRedirectForProvisionalNavigation, - iosOnNavigationResponse: params.iosOnNavigationResponse, - onNavigationResponse: params.onNavigationResponse, - iosShouldAllowDeprecatedTLS: params.iosShouldAllowDeprecatedTLS, - shouldAllowDeprecatedTLS: params.shouldAllowDeprecatedTLS, - onCameraCaptureStateChanged: params.onCameraCaptureStateChanged, - onMicrophoneCaptureStateChanged: params.onMicrophoneCaptureStateChanged, - onContentSizeChanged: params.onContentSizeChanged, - initialUrlRequest: params.initialUrlRequest, - initialFile: params.initialFile, - initialData: params.initialData, - initialOptions: params.initialOptions, - initialSettings: params.initialSettings, - contextMenu: params.contextMenu, - initialUserScripts: params.initialUserScripts, - pullToRefreshController: params.pullToRefreshController, - findInteractionController: - params.findInteractionController as MacOSFindInteractionController?, - ); - - @override - final MacOSFindInteractionController? findInteractionController; -} - -///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewWidget} -class MacOSInAppWebViewWidget extends PlatformInAppWebViewWidget { - /// Constructs a [MacOSInAppWebViewWidget]. - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewWidget} - MacOSInAppWebViewWidget(PlatformInAppWebViewWidgetCreationParams params) - : super.implementation( - params is MacOSInAppWebViewWidgetCreationParams - ? params - : MacOSInAppWebViewWidgetCreationParams.fromPlatformInAppWebViewWidgetCreationParams( - params, - ), - ); - - MacOSInAppWebViewWidgetCreationParams get _macosParams => - params as MacOSInAppWebViewWidgetCreationParams; - - MacOSInAppWebViewController? _controller; - - MacOSHeadlessInAppWebView? get _macosHeadlessInAppWebView => - params.headlessWebView as MacOSHeadlessInAppWebView?; - - static final MacOSInAppWebViewWidget _staticValue = MacOSInAppWebViewWidget( - MacOSInAppWebViewWidgetCreationParams(), - ); - - factory MacOSInAppWebViewWidget.static() { - return _staticValue; - } - - @override - Widget build(BuildContext context) { - final initialSettings = params.initialSettings ?? InAppWebViewSettings(); - _inferInitialSettings(initialSettings); - - Map settingsMap = - (params.initialSettings != null ? initialSettings.toMap() : null) ?? - // ignore: deprecated_member_use_from_same_package - params.initialOptions?.toMap() ?? - initialSettings.toMap(); - - Map pullToRefreshSettings = - params.pullToRefreshController?.params.settings.toMap() ?? - // ignore: deprecated_member_use_from_same_package - params.pullToRefreshController?.params.options.toMap() ?? - PullToRefreshSettings(enabled: false).toMap(); - - if ((params.headlessWebView?.isRunning() ?? false) && - params.keepAlive != null) { - final headlessId = params.headlessWebView?.id; - if (headlessId != null) { - // force keep alive id to match headless webview id - params.keepAlive?.id = headlessId; - } - } - - return AppKitView( - viewType: 'com.pichillilorenzo/flutter_inappwebview', - onPlatformViewCreated: _onPlatformViewCreated, - gestureRecognizers: params.gestureRecognizers, - creationParams: { - 'initialUrlRequest': params.initialUrlRequest?.toMap(), - 'initialFile': params.initialFile, - 'initialData': params.initialData?.toMap(), - 'initialSettings': settingsMap, - 'contextMenu': params.contextMenu?.toMap() ?? {}, - 'windowId': params.windowId, - 'headlessWebViewId': params.headlessWebView?.isRunning() ?? false - ? params.headlessWebView?.id - : null, - 'initialUserScripts': - params.initialUserScripts?.map((e) => e.toMap()).toList() ?? [], - 'pullToRefreshSettings': pullToRefreshSettings, - 'keepAliveId': params.keepAlive?.id, - 'preventGestureDelay': params.preventGestureDelay, - }, - creationParamsCodec: const StandardMessageCodec(), - ); - } - - void _onPlatformViewCreated(int id) { - dynamic viewId = id; - if (params.headlessWebView?.isRunning() ?? false) { - viewId = params.headlessWebView?.id; - } - viewId = params.keepAlive?.id ?? viewId ?? id; - _macosHeadlessInAppWebView?.internalDispose(); - _controller = MacOSInAppWebViewController( - PlatformInAppWebViewControllerCreationParams( - id: viewId, - webviewParams: params, - ), - ); - _macosParams.findInteractionController?.init(viewId); - debugLog( - className: runtimeType.toString(), - id: viewId?.toString(), - debugLoggingSettings: PlatformInAppWebViewController.debugLoggingSettings, - method: "onWebViewCreated", - args: [], - ); - if (params.onWebViewCreated != null) { - params.onWebViewCreated!( - params.controllerFromPlatform?.call(_controller!) ?? _controller!, - ); - } - } - - void _inferInitialSettings(InAppWebViewSettings settings) { - if (params.shouldOverrideUrlLoading != null && - settings.useShouldOverrideUrlLoading == null) { - settings.useShouldOverrideUrlLoading = true; - } - if (params.onLoadResource != null && settings.useOnLoadResource == null) { - settings.useOnLoadResource = true; - } - if ((params.onDownloadStartRequest != null || - params.onDownloadStarting != null) && - settings.useOnDownloadStart == null) { - settings.useOnDownloadStart = true; - } - if ((params.shouldInterceptAjaxRequest != null || - params.onAjaxProgress != null || - params.onAjaxReadyStateChange != null)) { - if (settings.useShouldInterceptAjaxRequest == null) { - settings.useShouldInterceptAjaxRequest = true; - } - if (params.onAjaxReadyStateChange != null && - settings.useOnAjaxReadyStateChange == null) { - settings.useOnAjaxReadyStateChange = true; - } - if (params.onAjaxProgress != null && settings.useOnAjaxProgress == null) { - settings.useOnAjaxProgress = true; - } - } - if (params.shouldInterceptFetchRequest != null && - settings.useShouldInterceptFetchRequest == null) { - settings.useShouldInterceptFetchRequest = true; - } - if (params.shouldInterceptRequest != null && - settings.useShouldInterceptRequest == null) { - settings.useShouldInterceptRequest = true; - } - if (params.onRenderProcessGone != null && - settings.useOnRenderProcessGone == null) { - settings.useOnRenderProcessGone = true; - } - if (params.onNavigationResponse != null && - settings.useOnNavigationResponse == null) { - settings.useOnNavigationResponse = true; - } - } - - @override - void dispose() { - dynamic viewId = _controller?.getViewId(); - debugLog( - className: runtimeType.toString(), - id: viewId?.toString(), - debugLoggingSettings: PlatformInAppWebViewController.debugLoggingSettings, - method: "dispose", - args: [], - ); - final isKeepAlive = params.keepAlive != null; - _controller?.dispose(isKeepAlive: isKeepAlive); - _controller = null; - params.findInteractionController?.dispose(isKeepAlive: isKeepAlive); - } - - @override - T controllerFromPlatform(PlatformInAppWebViewController controller) { - // unused - throw UnimplementedError(); - } -} diff --git a/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview_controller.dart deleted file mode 100644 index aa3549618e..0000000000 --- a/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview_controller.dart +++ /dev/null @@ -1,3097 +0,0 @@ -import 'dart:collection'; -import 'dart:convert'; -import 'dart:core'; -import 'dart:developer' as developer; -import 'dart:io'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../in_app_browser/in_app_browser.dart'; -import '../print_job/main.dart'; -import '../web_message/main.dart'; -import '../web_storage/web_storage.dart'; -import '_static_channel.dart'; -import 'headless_in_app_webview.dart'; - -/// Object specifying creation parameters for creating a [MacOSInAppWebViewController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformInAppWebViewControllerCreationParams] for -/// more information. -@immutable -class MacOSInAppWebViewControllerCreationParams - extends PlatformInAppWebViewControllerCreationParams { - /// Creates a new [MacOSInAppWebViewControllerCreationParams] instance. - const MacOSInAppWebViewControllerCreationParams({ - required super.id, - super.webviewParams, - }); - - /// Creates a [MacOSInAppWebViewControllerCreationParams] instance based on [PlatformInAppWebViewControllerCreationParams]. - factory MacOSInAppWebViewControllerCreationParams.fromPlatformInAppWebViewControllerCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformInAppWebViewControllerCreationParams params, - ) { - return MacOSInAppWebViewControllerCreationParams( - id: params.id, - webviewParams: params.webviewParams, - ); - } -} - -///Controls a WebView, such as an [InAppWebView] widget instance, a [MacOSHeadlessInAppWebView] instance or [MacOSInAppBrowser] WebView instance. -/// -///If you are using the [InAppWebView] widget, an [InAppWebViewController] instance can be obtained by setting the [InAppWebView.onWebViewCreated] -///callback. Instead, if you are using an [MacOSInAppBrowser] instance, you can get it through the [MacOSInAppBrowser.webViewController] attribute. -class MacOSInAppWebViewController extends PlatformInAppWebViewController - with ChannelController { - static final MethodChannel _staticChannel = IN_APP_WEBVIEW_STATIC_CHANNEL; - - // List of properties to be saved and restored for keep alive feature - Map _javaScriptHandlersMap = HashMap(); - Map> _userScripts = { - UserScriptInjectionTime.AT_DOCUMENT_START: [], - UserScriptInjectionTime.AT_DOCUMENT_END: [], - }; - Set _webMessageListenerObjNames = Set(); - Map _injectedScriptsFromURL = {}; - Set _webMessageChannels = Set(); - Set _webMessageListeners = Set(); - - // static map that contains the properties to be saved and restored for keep alive feature - static final Map - _keepAliveMap = {}; - - MacOSInAppBrowser? _inAppBrowser; - - PlatformInAppBrowserEvents? get _inAppBrowserEventHandler => - _inAppBrowser?.eventHandler; - - dynamic _controllerFromPlatform; - - @override - late MacOSWebStorage webStorage; - - MacOSInAppWebViewController( - PlatformInAppWebViewControllerCreationParams params, - ) : super.implementation( - params is MacOSInAppWebViewControllerCreationParams - ? params - : MacOSInAppWebViewControllerCreationParams.fromPlatformInAppWebViewControllerCreationParams( - params, - ), - ) { - channel = MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id'); - handler = handleMethod; - initMethodCallHandler(); - - final initialUserScripts = webviewParams?.initialUserScripts; - if (initialUserScripts != null) { - for (final userScript in initialUserScripts) { - if (userScript.injectionTime == - UserScriptInjectionTime.AT_DOCUMENT_START) { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.add( - userScript, - ); - } else { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.add( - userScript, - ); - } - } - } - - this._init(params); - } - - static final MacOSInAppWebViewController _staticValue = - MacOSInAppWebViewController( - MacOSInAppWebViewControllerCreationParams(id: null), - ); - - factory MacOSInAppWebViewController.static() { - return _staticValue; - } - - MacOSInAppWebViewController.fromInAppBrowser( - PlatformInAppWebViewControllerCreationParams params, - MethodChannel channel, - MacOSInAppBrowser inAppBrowser, - UnmodifiableListView? initialUserScripts, - ) : super.implementation( - params is MacOSInAppWebViewControllerCreationParams - ? params - : MacOSInAppWebViewControllerCreationParams.fromPlatformInAppWebViewControllerCreationParams( - params, - ), - ) { - this.channel = channel; - this._inAppBrowser = inAppBrowser; - - if (initialUserScripts != null) { - for (final userScript in initialUserScripts) { - if (userScript.injectionTime == - UserScriptInjectionTime.AT_DOCUMENT_START) { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.add( - userScript, - ); - } else { - this._userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.add( - userScript, - ); - } - } - } - this._init(params); - } - - void _init(PlatformInAppWebViewControllerCreationParams params) { - _controllerFromPlatform = - params.webviewParams?.controllerFromPlatform?.call(this) ?? this; - - webStorage = MacOSWebStorage( - MacOSWebStorageCreationParams( - localStorage: MacOSLocalStorage.defaultStorage(controller: this), - sessionStorage: MacOSSessionStorage.defaultStorage(controller: this), - ), - ); - - if (params.webviewParams is PlatformInAppWebViewWidgetCreationParams) { - final keepAlive = - (params.webviewParams as PlatformInAppWebViewWidgetCreationParams) - .keepAlive; - if (keepAlive != null) { - InAppWebViewControllerKeepAliveProps? props = _keepAliveMap[keepAlive]; - if (props == null) { - // save controller properties to restore it later - _keepAliveMap[keepAlive] = InAppWebViewControllerKeepAliveProps( - injectedScriptsFromURL: _injectedScriptsFromURL, - javaScriptHandlersMap: _javaScriptHandlersMap, - userScripts: _userScripts, - webMessageListenerObjNames: _webMessageListenerObjNames, - webMessageChannels: _webMessageChannels, - webMessageListeners: _webMessageListeners, - ); - } else { - // restore controller properties - _injectedScriptsFromURL = props.injectedScriptsFromURL; - _javaScriptHandlersMap = props.javaScriptHandlersMap; - _userScripts = props.userScripts; - _webMessageListenerObjNames = props.webMessageListenerObjNames; - _webMessageChannels = - props.webMessageChannels as Set; - _webMessageListeners = - props.webMessageListeners as Set; - } - } - } - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - name: _inAppBrowser == null - ? "WebView" - : _inAppBrowser.runtimeType.toString(), - id: (getViewId() ?? _inAppBrowser?.id).toString(), - debugLoggingSettings: PlatformInAppWebViewController.debugLoggingSettings, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - if (call.method == "_onMouseDown") { - // Workaround for https://github.com/pichillilorenzo/flutter_inappwebview/issues/2380 - // TODO: remove when Flutter fixes this - FocusManager.instance.primaryFocus?.unfocus(); - return; - } - - if (PlatformInAppWebViewController.debugLoggingSettings.enabled && - call.method != "onCallJsHandler") { - _debugLog(call.method, call.arguments); - } - - switch (call.method) { - case "onLoadStart": - _injectedScriptsFromURL.clear(); - if ((webviewParams != null && webviewParams!.onLoadStart != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - if (webviewParams != null && webviewParams!.onLoadStart != null) - webviewParams!.onLoadStart!(_controllerFromPlatform, uri); - else - _inAppBrowserEventHandler!.onLoadStart(uri); - } - break; - case "onLoadStop": - if ((webviewParams != null && webviewParams!.onLoadStop != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - if (webviewParams != null && webviewParams!.onLoadStop != null) - webviewParams!.onLoadStop!(_controllerFromPlatform, uri); - else - _inAppBrowserEventHandler!.onLoadStop(uri); - } - break; - case "onReceivedError": - if ((webviewParams != null && - (webviewParams!.onReceivedError != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadError != null)) || - _inAppBrowserEventHandler != null) { - WebResourceRequest request = WebResourceRequest.fromMap( - call.arguments["request"].cast(), - )!; - WebResourceError error = WebResourceError.fromMap( - call.arguments["error"].cast(), - )!; - var isForMainFrame = request.isForMainFrame ?? false; - - if (webviewParams != null) { - if (webviewParams!.onReceivedError != null) - webviewParams!.onReceivedError!( - _controllerFromPlatform, - request, - error, - ); - else if (isForMainFrame) { - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadError!( - _controllerFromPlatform, - request.url, - error.type.toNativeValue() ?? -1, - error.description, - ); - } - } else { - if (isForMainFrame) { - _inAppBrowserEventHandler!.onLoadError( - request.url, - error.type.toNativeValue() ?? -1, - error.description, - ); - } - _inAppBrowserEventHandler!.onReceivedError(request, error); - } - } - break; - case "onReceivedHttpError": - if ((webviewParams != null && - (webviewParams!.onReceivedHttpError != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadHttpError != null)) || - _inAppBrowserEventHandler != null) { - WebResourceRequest request = WebResourceRequest.fromMap( - call.arguments["request"].cast(), - )!; - WebResourceResponse errorResponse = WebResourceResponse.fromMap( - call.arguments["errorResponse"].cast(), - )!; - var isForMainFrame = request.isForMainFrame ?? false; - - if (webviewParams != null) { - if (webviewParams!.onReceivedHttpError != null) - webviewParams!.onReceivedHttpError!( - _controllerFromPlatform, - request, - errorResponse, - ); - else if (isForMainFrame) { - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadHttpError!( - _controllerFromPlatform, - request.url, - errorResponse.statusCode ?? -1, - errorResponse.reasonPhrase ?? '', - ); - } - } else { - if (isForMainFrame) { - _inAppBrowserEventHandler!.onLoadHttpError( - request.url, - errorResponse.statusCode ?? -1, - errorResponse.reasonPhrase ?? '', - ); - } - _inAppBrowserEventHandler!.onReceivedHttpError( - request, - errorResponse, - ); - } - } - break; - case "onProgressChanged": - if ((webviewParams != null && - webviewParams!.onProgressChanged != null) || - _inAppBrowserEventHandler != null) { - int progress = call.arguments["progress"]; - if (webviewParams != null && webviewParams!.onProgressChanged != null) - webviewParams!.onProgressChanged!( - _controllerFromPlatform, - progress, - ); - else - _inAppBrowserEventHandler!.onProgressChanged(progress); - } - break; - case "shouldOverrideUrlLoading": - if ((webviewParams != null && - webviewParams!.shouldOverrideUrlLoading != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - NavigationAction navigationAction = NavigationAction.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.shouldOverrideUrlLoading != null) - return (await webviewParams!.shouldOverrideUrlLoading!( - _controllerFromPlatform, - navigationAction, - ))?.toNativeValue(); - return (await _inAppBrowserEventHandler!.shouldOverrideUrlLoading( - navigationAction, - ))?.toNativeValue(); - } - break; - case "onConsoleMessage": - if ((webviewParams != null && - webviewParams!.onConsoleMessage != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - ConsoleMessage consoleMessage = ConsoleMessage.fromMap(arguments)!; - if (webviewParams != null && webviewParams!.onConsoleMessage != null) - webviewParams!.onConsoleMessage!( - _controllerFromPlatform, - consoleMessage, - ); - else - _inAppBrowserEventHandler!.onConsoleMessage(consoleMessage); - } - break; - case "onScrollChanged": - if ((webviewParams != null && webviewParams!.onScrollChanged != null) || - _inAppBrowserEventHandler != null) { - int x = call.arguments["x"]; - int y = call.arguments["y"]; - if (webviewParams != null && webviewParams!.onScrollChanged != null) - webviewParams!.onScrollChanged!(_controllerFromPlatform, x, y); - else - _inAppBrowserEventHandler!.onScrollChanged(x, y); - } - break; - case "onDownloadStarting": - if ((webviewParams != null && - (webviewParams!.onDownloadStart != null || - webviewParams!.onDownloadStartRequest != null || - webviewParams!.onDownloadStarting != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - DownloadStartRequest downloadStartRequest = - DownloadStartRequest.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.onDownloadStarting != null) - return (await webviewParams!.onDownloadStarting!( - _controllerFromPlatform, - downloadStartRequest, - ))?.toMap(); - else if (webviewParams!.onDownloadStartRequest != null) - webviewParams!.onDownloadStartRequest!( - _controllerFromPlatform, - downloadStartRequest, - ); - else { - webviewParams!.onDownloadStart!( - _controllerFromPlatform, - downloadStartRequest.url, - ); - } - } else { - _inAppBrowserEventHandler!.onDownloadStart( - downloadStartRequest.url, - ); - _inAppBrowserEventHandler!.onDownloadStartRequest( - downloadStartRequest, - ); - return (await _inAppBrowserEventHandler!.onDownloadStarting( - downloadStartRequest, - ))?.toMap(); - } - } - break; - case "onLoadResourceWithCustomScheme": - if ((webviewParams != null && - (webviewParams!.onLoadResourceWithCustomScheme != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onLoadResourceCustomScheme != null)) || - _inAppBrowserEventHandler != null) { - Map requestMap = call.arguments["request"] - .cast(); - WebResourceRequest request = WebResourceRequest.fromMap(requestMap)!; - - if (webviewParams != null) { - if (webviewParams!.onLoadResourceWithCustomScheme != null) - return (await webviewParams!.onLoadResourceWithCustomScheme!( - _controllerFromPlatform, - request, - ))?.toMap(); - else { - return (await params - .webviewParams! - // ignore: deprecated_member_use_from_same_package - .onLoadResourceCustomScheme!( - _controllerFromPlatform, - request.url, - )) - ?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler! - .onLoadResourceWithCustomScheme(request)) ?? - (await _inAppBrowserEventHandler! - .onLoadResourceCustomScheme(request.url))) - ?.toMap(); - } - } - break; - case "onCreateWindow": - if ((webviewParams != null && webviewParams!.onCreateWindow != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - CreateWindowAction createWindowAction = CreateWindowAction.fromMap( - arguments, - )!; - - if (webviewParams != null && webviewParams!.onCreateWindow != null) - return await webviewParams!.onCreateWindow!( - _controllerFromPlatform, - createWindowAction, - ); - else - return await _inAppBrowserEventHandler!.onCreateWindow( - createWindowAction, - ); - } - break; - case "onCloseWindow": - if (webviewParams != null && webviewParams!.onCloseWindow != null) - webviewParams!.onCloseWindow!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onCloseWindow(); - break; - case "onTitleChanged": - if ((webviewParams != null && webviewParams!.onTitleChanged != null) || - _inAppBrowserEventHandler != null) { - String? title = call.arguments["title"]; - if (webviewParams != null && webviewParams!.onTitleChanged != null) - webviewParams!.onTitleChanged!(_controllerFromPlatform, title); - else - _inAppBrowserEventHandler!.onTitleChanged(title); - } - break; - case "onGeolocationPermissionsShowPrompt": - if ((webviewParams != null && - (webviewParams!.onGeolocationPermissionsShowPrompt != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnGeolocationPermissionsShowPrompt != - null)) || - _inAppBrowserEventHandler != null) { - String origin = call.arguments["origin"]; - - if (webviewParams != null) { - if (webviewParams!.onGeolocationPermissionsShowPrompt != null) - return (await webviewParams!.onGeolocationPermissionsShowPrompt!( - _controllerFromPlatform, - origin, - ))?.toMap(); - else { - return (await params - .webviewParams! - // ignore: deprecated_member_use_from_same_package - .androidOnGeolocationPermissionsShowPrompt!( - _controllerFromPlatform, - origin, - )) - ?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler! - .onGeolocationPermissionsShowPrompt(origin)) ?? - (await _inAppBrowserEventHandler! - .androidOnGeolocationPermissionsShowPrompt(origin))) - ?.toMap(); - } - } - break; - case "onGeolocationPermissionsHidePrompt": - if (webviewParams != null && - (webviewParams!.onGeolocationPermissionsHidePrompt != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnGeolocationPermissionsHidePrompt != - null)) { - if (webviewParams!.onGeolocationPermissionsHidePrompt != null) - webviewParams!.onGeolocationPermissionsHidePrompt!( - _controllerFromPlatform, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnGeolocationPermissionsHidePrompt!( - _controllerFromPlatform, - ); - } - } else if (_inAppBrowserEventHandler != null) { - _inAppBrowserEventHandler!.onGeolocationPermissionsHidePrompt(); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler! - .androidOnGeolocationPermissionsHidePrompt(); - } - break; - case "shouldInterceptRequest": - if ((webviewParams != null && - (webviewParams!.shouldInterceptRequest != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidShouldInterceptRequest != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - WebResourceRequest request = WebResourceRequest.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.shouldInterceptRequest != null) - return (await webviewParams!.shouldInterceptRequest!( - _controllerFromPlatform, - request, - ))?.toMap(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidShouldInterceptRequest!( - _controllerFromPlatform, - request, - ))?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler!.shouldInterceptRequest( - request, - )) ?? - (await _inAppBrowserEventHandler! - .androidShouldInterceptRequest(request))) - ?.toMap(); - } - } - break; - case "onRenderProcessUnresponsive": - if ((webviewParams != null && - (webviewParams!.onRenderProcessUnresponsive != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnRenderProcessUnresponsive != - null)) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - - if (webviewParams != null) { - if (webviewParams!.onRenderProcessUnresponsive != null) - return (await webviewParams!.onRenderProcessUnresponsive!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidOnRenderProcessUnresponsive!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - } - } else { - return ((await _inAppBrowserEventHandler! - .onRenderProcessUnresponsive(uri)) ?? - (await _inAppBrowserEventHandler! - .androidOnRenderProcessUnresponsive(uri))) - ?.toNativeValue(); - } - } - break; - case "onRenderProcessResponsive": - if ((webviewParams != null && - (webviewParams!.onRenderProcessResponsive != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnRenderProcessResponsive != null)) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - - if (webviewParams != null) { - if (webviewParams!.onRenderProcessResponsive != null) - return (await webviewParams!.onRenderProcessResponsive!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidOnRenderProcessResponsive!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - } - } else { - return ((await _inAppBrowserEventHandler!.onRenderProcessResponsive( - uri, - )) ?? - (await _inAppBrowserEventHandler! - .androidOnRenderProcessResponsive(uri))) - ?.toNativeValue(); - } - } - break; - case "onRenderProcessGone": - if ((webviewParams != null && - (webviewParams!.onRenderProcessGone != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnRenderProcessGone != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - RenderProcessGoneDetail detail = RenderProcessGoneDetail.fromMap( - arguments, - )!; - - if (webviewParams != null) { - if (webviewParams!.onRenderProcessGone != null) - webviewParams!.onRenderProcessGone!( - _controllerFromPlatform, - detail, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnRenderProcessGone!( - _controllerFromPlatform, - detail, - ); - } - } else if (_inAppBrowserEventHandler != null) { - _inAppBrowserEventHandler!.onRenderProcessGone(detail); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.androidOnRenderProcessGone(detail); - } - } - break; - case "onFormResubmission": - if ((webviewParams != null && - (webviewParams!.onFormResubmission != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnFormResubmission != null)) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - - if (webviewParams != null) { - if (webviewParams!.onFormResubmission != null) - return (await webviewParams!.onFormResubmission!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidOnFormResubmission!( - _controllerFromPlatform, - uri, - ))?.toNativeValue(); - } - } else { - return ((await _inAppBrowserEventHandler!.onFormResubmission( - uri, - )) ?? - // ignore: deprecated_member_use_from_same_package - (await _inAppBrowserEventHandler!.androidOnFormResubmission( - uri, - ))) - ?.toNativeValue(); - } - } - break; - case "onZoomScaleChanged": - if ((webviewParams != null && - // ignore: deprecated_member_use_from_same_package - (webviewParams!.androidOnScaleChanged != null || - webviewParams!.onZoomScaleChanged != null)) || - _inAppBrowserEventHandler != null) { - double oldScale = call.arguments["oldScale"]; - double newScale = call.arguments["newScale"]; - - if (webviewParams != null) { - if (webviewParams!.onZoomScaleChanged != null) - webviewParams!.onZoomScaleChanged!( - _controllerFromPlatform, - oldScale, - newScale, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnScaleChanged!( - _controllerFromPlatform, - oldScale, - newScale, - ); - } - } else { - _inAppBrowserEventHandler!.onZoomScaleChanged(oldScale, newScale); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.androidOnScaleChanged( - oldScale, - newScale, - ); - } - } - break; - case "onReceivedIcon": - if ((webviewParams != null && - (webviewParams!.onReceivedIcon != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedIcon != null)) || - _inAppBrowserEventHandler != null) { - Uint8List icon = Uint8List.fromList( - call.arguments["icon"].cast(), - ); - - if (webviewParams != null) { - if (webviewParams!.onReceivedIcon != null) - webviewParams!.onReceivedIcon!(_controllerFromPlatform, icon); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedIcon!( - _controllerFromPlatform, - icon, - ); - } - } else { - _inAppBrowserEventHandler!.onReceivedIcon(icon); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.androidOnReceivedIcon(icon); - } - } - break; - case "onReceivedTouchIconUrl": - if ((webviewParams != null && - (webviewParams!.onReceivedTouchIconUrl != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedTouchIconUrl != null)) || - _inAppBrowserEventHandler != null) { - String url = call.arguments["url"]; - bool precomposed = call.arguments["precomposed"]; - WebUri uri = WebUri(url); - - if (webviewParams != null) { - if (webviewParams!.onReceivedTouchIconUrl != null) - webviewParams!.onReceivedTouchIconUrl!( - _controllerFromPlatform, - uri, - precomposed, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedTouchIconUrl!( - _controllerFromPlatform, - uri, - precomposed, - ); - } - } else { - _inAppBrowserEventHandler!.onReceivedTouchIconUrl(uri, precomposed); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.androidOnReceivedTouchIconUrl( - uri, - precomposed, - ); - } - } - break; - case "onJsAlert": - if ((webviewParams != null && webviewParams!.onJsAlert != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsAlertRequest jsAlertRequest = JsAlertRequest.fromMap(arguments)!; - - if (webviewParams != null && webviewParams!.onJsAlert != null) - return (await webviewParams!.onJsAlert!( - _controllerFromPlatform, - jsAlertRequest, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onJsAlert( - jsAlertRequest, - ))?.toMap(); - } - break; - case "onJsConfirm": - if ((webviewParams != null && webviewParams!.onJsConfirm != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsConfirmRequest jsConfirmRequest = JsConfirmRequest.fromMap( - arguments, - )!; - - if (webviewParams != null && webviewParams!.onJsConfirm != null) - return (await webviewParams!.onJsConfirm!( - _controllerFromPlatform, - jsConfirmRequest, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onJsConfirm( - jsConfirmRequest, - ))?.toMap(); - } - break; - case "onJsPrompt": - if ((webviewParams != null && webviewParams!.onJsPrompt != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsPromptRequest jsPromptRequest = JsPromptRequest.fromMap(arguments)!; - - if (webviewParams != null && webviewParams!.onJsPrompt != null) - return (await webviewParams!.onJsPrompt!( - _controllerFromPlatform, - jsPromptRequest, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onJsPrompt( - jsPromptRequest, - ))?.toMap(); - } - break; - case "onJsBeforeUnload": - if ((webviewParams != null && - (webviewParams!.onJsBeforeUnload != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnJsBeforeUnload != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - JsBeforeUnloadRequest jsBeforeUnloadRequest = - JsBeforeUnloadRequest.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.onJsBeforeUnload != null) - return (await webviewParams!.onJsBeforeUnload!( - _controllerFromPlatform, - jsBeforeUnloadRequest, - ))?.toMap(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidOnJsBeforeUnload!( - _controllerFromPlatform, - jsBeforeUnloadRequest, - ))?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler!.onJsBeforeUnload( - jsBeforeUnloadRequest, - )) ?? - (await _inAppBrowserEventHandler!.androidOnJsBeforeUnload( - jsBeforeUnloadRequest, - ))) - ?.toMap(); - } - } - break; - case "onSafeBrowsingHit": - if ((webviewParams != null && - (webviewParams!.onSafeBrowsingHit != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnSafeBrowsingHit != null)) || - _inAppBrowserEventHandler != null) { - String url = call.arguments["url"]; - SafeBrowsingThreat? threatType = SafeBrowsingThreat.fromNativeValue( - call.arguments["threatType"], - ); - WebUri uri = WebUri(url); - - if (webviewParams != null) { - if (webviewParams!.onSafeBrowsingHit != null) - return (await webviewParams!.onSafeBrowsingHit!( - _controllerFromPlatform, - uri, - threatType, - ))?.toMap(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.androidOnSafeBrowsingHit!( - _controllerFromPlatform, - uri, - threatType, - ))?.toMap(); - } - } else { - return ((await _inAppBrowserEventHandler!.onSafeBrowsingHit( - uri, - threatType, - )) ?? - (await _inAppBrowserEventHandler!.androidOnSafeBrowsingHit( - uri, - threatType, - ))) - ?.toMap(); - } - } - break; - case "onReceivedLoginRequest": - if ((webviewParams != null && - (webviewParams!.onReceivedLoginRequest != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedLoginRequest != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - LoginRequest loginRequest = LoginRequest.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.onReceivedLoginRequest != null) - webviewParams!.onReceivedLoginRequest!( - _controllerFromPlatform, - loginRequest, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnReceivedLoginRequest!( - _controllerFromPlatform, - loginRequest, - ); - } - } else { - _inAppBrowserEventHandler!.onReceivedLoginRequest(loginRequest); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.androidOnReceivedLoginRequest( - loginRequest, - ); - } - } - break; - case "onPermissionRequestCanceled": - if ((webviewParams != null && - webviewParams!.onPermissionRequestCanceled != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - PermissionRequest permissionRequest = PermissionRequest.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.onPermissionRequestCanceled != null) - webviewParams!.onPermissionRequestCanceled!( - _controllerFromPlatform, - permissionRequest, - ); - else - _inAppBrowserEventHandler!.onPermissionRequestCanceled( - permissionRequest, - ); - } - break; - case "onRequestFocus": - if ((webviewParams != null && webviewParams!.onRequestFocus != null) || - _inAppBrowserEventHandler != null) { - if (webviewParams != null && webviewParams!.onRequestFocus != null) - webviewParams!.onRequestFocus!(_controllerFromPlatform); - else - _inAppBrowserEventHandler!.onRequestFocus(); - } - break; - case "onReceivedHttpAuthRequest": - if ((webviewParams != null && - webviewParams!.onReceivedHttpAuthRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - HttpAuthenticationChallenge challenge = - HttpAuthenticationChallenge.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onReceivedHttpAuthRequest != null) - return (await webviewParams!.onReceivedHttpAuthRequest!( - _controllerFromPlatform, - challenge, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler!.onReceivedHttpAuthRequest( - challenge, - ))?.toMap(); - } - break; - case "onReceivedServerTrustAuthRequest": - if ((webviewParams != null && - webviewParams!.onReceivedServerTrustAuthRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - ServerTrustChallenge challenge = ServerTrustChallenge.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.onReceivedServerTrustAuthRequest != null) - return (await webviewParams!.onReceivedServerTrustAuthRequest!( - _controllerFromPlatform, - challenge, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler! - .onReceivedServerTrustAuthRequest(challenge)) - ?.toMap(); - } - break; - case "onReceivedClientCertRequest": - if ((webviewParams != null && - webviewParams!.onReceivedClientCertRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - ClientCertChallenge challenge = ClientCertChallenge.fromMap( - arguments, - )!; - - if (webviewParams != null && - webviewParams!.onReceivedClientCertRequest != null) - return (await webviewParams!.onReceivedClientCertRequest!( - _controllerFromPlatform, - challenge, - ))?.toMap(); - else - return (await _inAppBrowserEventHandler! - .onReceivedClientCertRequest(challenge)) - ?.toMap(); - } - break; - case "onFindResultReceived": - if ((webviewParams != null && - (webviewParams!.onFindResultReceived != null || - (webviewParams!.findInteractionController != null && - webviewParams! - .findInteractionController! - .params - .onFindResultReceived != - null))) || - _inAppBrowserEventHandler != null) { - int activeMatchOrdinal = call.arguments["activeMatchOrdinal"]; - int numberOfMatches = call.arguments["numberOfMatches"]; - bool isDoneCounting = call.arguments["isDoneCounting"]; - if (webviewParams != null) { - if (webviewParams!.findInteractionController != null && - webviewParams! - .findInteractionController! - .params - .onFindResultReceived != - null) - webviewParams! - .findInteractionController! - .params - .onFindResultReceived!( - webviewParams!.findInteractionController!, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - else - webviewParams!.onFindResultReceived!( - _controllerFromPlatform, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - } else { - if (_inAppBrowser!.findInteractionController != null && - _inAppBrowser! - .findInteractionController! - .onFindResultReceived != - null) - _inAppBrowser!.findInteractionController!.onFindResultReceived!( - webviewParams!.findInteractionController!, - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - else - _inAppBrowserEventHandler!.onFindResultReceived( - activeMatchOrdinal, - numberOfMatches, - isDoneCounting, - ); - } - } - break; - case "onPermissionRequest": - if ((webviewParams != null && - (webviewParams!.onPermissionRequest != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.androidOnPermissionRequest != null)) || - _inAppBrowserEventHandler != null) { - String origin = call.arguments["origin"]; - List resources = call.arguments["resources"].cast(); - - Map arguments = call.arguments - .cast(); - PermissionRequest permissionRequest = PermissionRequest.fromMap( - arguments, - )!; - - if (webviewParams != null) { - if (webviewParams!.onPermissionRequest != null) - return (await webviewParams!.onPermissionRequest!( - _controllerFromPlatform, - permissionRequest, - ))?.toMap(); - else { - return (await webviewParams!.androidOnPermissionRequest!( - _controllerFromPlatform, - origin, - resources, - ))?.toMap(); - } - } else { - return (await _inAppBrowserEventHandler!.onPermissionRequest( - permissionRequest, - ))?.toMap() ?? - (await _inAppBrowserEventHandler!.androidOnPermissionRequest( - origin, - resources, - ))?.toMap(); - } - } - break; - case "onUpdateVisitedHistory": - if ((webviewParams != null && - webviewParams!.onUpdateVisitedHistory != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - bool? isReload = call.arguments["isReload"]; - WebUri? uri = url != null ? WebUri(url) : null; - if (webviewParams != null && - webviewParams!.onUpdateVisitedHistory != null) - webviewParams!.onUpdateVisitedHistory!( - _controllerFromPlatform, - uri, - isReload, - ); - else - _inAppBrowserEventHandler!.onUpdateVisitedHistory(uri, isReload); - } - break; - case "onWebContentProcessDidTerminate": - if (webviewParams != null && - (webviewParams!.onWebContentProcessDidTerminate != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.iosOnWebContentProcessDidTerminate != null)) { - if (webviewParams!.onWebContentProcessDidTerminate != null) - webviewParams!.onWebContentProcessDidTerminate!( - _controllerFromPlatform, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.iosOnWebContentProcessDidTerminate!( - _controllerFromPlatform, - ); - } - } else if (_inAppBrowserEventHandler != null) { - _inAppBrowserEventHandler!.onWebContentProcessDidTerminate(); - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.iosOnWebContentProcessDidTerminate(); - } - break; - case "onPageCommitVisible": - if ((webviewParams != null && - webviewParams!.onPageCommitVisible != null) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - if (webviewParams != null && - webviewParams!.onPageCommitVisible != null) - webviewParams!.onPageCommitVisible!(_controllerFromPlatform, uri); - else - _inAppBrowserEventHandler!.onPageCommitVisible(uri); - } - break; - case "onDidReceiveServerRedirectForProvisionalNavigation": - if (webviewParams != null && - (webviewParams! - .onDidReceiveServerRedirectForProvisionalNavigation != - null || - params - .webviewParams! - // ignore: deprecated_member_use_from_same_package - .iosOnDidReceiveServerRedirectForProvisionalNavigation != - null)) { - if (webviewParams! - .onDidReceiveServerRedirectForProvisionalNavigation != - null) - webviewParams!.onDidReceiveServerRedirectForProvisionalNavigation!( - _controllerFromPlatform, - ); - else { - params - .webviewParams! - // ignore: deprecated_member_use_from_same_package - .iosOnDidReceiveServerRedirectForProvisionalNavigation!( - _controllerFromPlatform, - ); - } - } else if (_inAppBrowserEventHandler != null) { - _inAppBrowserEventHandler! - .onDidReceiveServerRedirectForProvisionalNavigation(); - _inAppBrowserEventHandler! - .iosOnDidReceiveServerRedirectForProvisionalNavigation(); - } - break; - case "onNavigationResponse": - if ((webviewParams != null && - (webviewParams!.onNavigationResponse != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.iosOnNavigationResponse != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - // ignore: deprecated_member_use_from_same_package - IOSWKNavigationResponse iosOnNavigationResponse = - // ignore: deprecated_member_use_from_same_package - IOSWKNavigationResponse.fromMap(arguments)!; - - NavigationResponse navigationResponse = NavigationResponse.fromMap( - arguments, - )!; - - if (webviewParams != null) { - if (webviewParams!.onNavigationResponse != null) - return (await webviewParams!.onNavigationResponse!( - _controllerFromPlatform, - navigationResponse, - ))?.toNativeValue(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.iosOnNavigationResponse!( - _controllerFromPlatform, - iosOnNavigationResponse, - ))?.toNativeValue(); - } - } else { - return (await _inAppBrowserEventHandler!.onNavigationResponse( - navigationResponse, - ))?.toNativeValue() ?? - (await _inAppBrowserEventHandler!.iosOnNavigationResponse( - iosOnNavigationResponse, - ))?.toNativeValue(); - } - } - break; - case "shouldAllowDeprecatedTLS": - if ((webviewParams != null && - (webviewParams!.shouldAllowDeprecatedTLS != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.iosShouldAllowDeprecatedTLS != null)) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - URLAuthenticationChallenge challenge = - URLAuthenticationChallenge.fromMap(arguments)!; - - if (webviewParams != null) { - if (webviewParams!.shouldAllowDeprecatedTLS != null) - return (await webviewParams!.shouldAllowDeprecatedTLS!( - _controllerFromPlatform, - challenge, - ))?.toNativeValue(); - else { - // ignore: deprecated_member_use_from_same_package - return (await webviewParams!.iosShouldAllowDeprecatedTLS!( - _controllerFromPlatform, - challenge, - ))?.toNativeValue(); - } - } else { - return (await _inAppBrowserEventHandler!.shouldAllowDeprecatedTLS( - challenge, - ))?.toNativeValue() ?? - // ignore: deprecated_member_use_from_same_package - (await _inAppBrowserEventHandler!.iosShouldAllowDeprecatedTLS( - challenge, - ))?.toNativeValue(); - } - } - break; - case "onLongPressHitTestResult": - if ((webviewParams != null && - webviewParams!.onLongPressHitTestResult != null) || - _inAppBrowserEventHandler != null) { - Map arguments = call.arguments - .cast(); - InAppWebViewHitTestResult hitTestResult = - InAppWebViewHitTestResult.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onLongPressHitTestResult != null) - webviewParams!.onLongPressHitTestResult!( - _controllerFromPlatform, - hitTestResult, - ); - else - _inAppBrowserEventHandler!.onLongPressHitTestResult(hitTestResult); - } - break; - case "onCreateContextMenu": - ContextMenu? contextMenu; - if (webviewParams != null && webviewParams!.contextMenu != null) { - contextMenu = webviewParams!.contextMenu; - } else if (_inAppBrowserEventHandler != null && - _inAppBrowser!.contextMenu != null) { - contextMenu = _inAppBrowser!.contextMenu; - } - - if (contextMenu != null && contextMenu.onCreateContextMenu != null) { - Map arguments = call.arguments - .cast(); - InAppWebViewHitTestResult hitTestResult = - InAppWebViewHitTestResult.fromMap(arguments)!; - - contextMenu.onCreateContextMenu!(hitTestResult); - } - break; - case "onHideContextMenu": - ContextMenu? contextMenu; - if (webviewParams != null && webviewParams!.contextMenu != null) { - contextMenu = webviewParams!.contextMenu; - } else if (_inAppBrowserEventHandler != null && - _inAppBrowser!.contextMenu != null) { - contextMenu = _inAppBrowser!.contextMenu; - } - - if (contextMenu != null && contextMenu.onHideContextMenu != null) { - contextMenu.onHideContextMenu!(); - } - break; - case "onContextMenuActionItemClicked": - ContextMenu? contextMenu; - if (webviewParams != null && webviewParams!.contextMenu != null) { - contextMenu = webviewParams!.contextMenu; - } else if (_inAppBrowserEventHandler != null && - _inAppBrowser!.contextMenu != null) { - contextMenu = _inAppBrowser!.contextMenu; - } - - if (contextMenu != null) { - int? androidId = call.arguments["androidId"]; - String? iosId = call.arguments["iosId"]; - dynamic id = call.arguments["id"]; - String title = call.arguments["title"]; - - ContextMenuItem menuItemClicked = ContextMenuItem( - id: id, - // ignore: deprecated_member_use_from_same_package - androidId: androidId, - // ignore: deprecated_member_use_from_same_package - iosId: iosId, - title: title, - action: null, - ); - - for (var menuItem in contextMenu.menuItems) { - if (menuItem.id == id) { - menuItemClicked = menuItem; - if (menuItem.action != null) { - menuItem.action!(); - } - break; - } - } - - if (contextMenu.onContextMenuActionItemClicked != null) { - contextMenu.onContextMenuActionItemClicked!(menuItemClicked); - } - } - break; - case "onEnterFullscreen": - if (webviewParams != null && webviewParams!.onEnterFullscreen != null) - webviewParams!.onEnterFullscreen!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onEnterFullscreen(); - break; - case "onExitFullscreen": - if (webviewParams != null && webviewParams!.onExitFullscreen != null) - webviewParams!.onExitFullscreen!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onExitFullscreen(); - break; - case "onOverScrolled": - if ((webviewParams != null && webviewParams!.onOverScrolled != null) || - _inAppBrowserEventHandler != null) { - int x = call.arguments["x"]; - int y = call.arguments["y"]; - bool clampedX = call.arguments["clampedX"]; - bool clampedY = call.arguments["clampedY"]; - - if (webviewParams != null && webviewParams!.onOverScrolled != null) - webviewParams!.onOverScrolled!( - _controllerFromPlatform, - x, - y, - clampedX, - clampedY, - ); - else - _inAppBrowserEventHandler!.onOverScrolled(x, y, clampedX, clampedY); - } - break; - case "onWindowFocus": - if (webviewParams != null && webviewParams!.onWindowFocus != null) - webviewParams!.onWindowFocus!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onWindowFocus(); - break; - case "onWindowBlur": - if (webviewParams != null && webviewParams!.onWindowBlur != null) - webviewParams!.onWindowBlur!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onWindowBlur(); - break; - case "onPrintRequest": - if ((webviewParams != null && - (webviewParams!.onPrintRequest != null || - // ignore: deprecated_member_use_from_same_package - webviewParams!.onPrint != null)) || - _inAppBrowserEventHandler != null) { - String? url = call.arguments["url"]; - String? printJobId = call.arguments["printJobId"]; - WebUri? uri = url != null ? WebUri(url) : null; - MacOSPrintJobController? printJob = printJobId != null - ? MacOSPrintJobController( - MacOSPrintJobControllerCreationParams(id: printJobId), - ) - : null; - - if (webviewParams != null) { - if (webviewParams!.onPrintRequest != null) - return await webviewParams!.onPrintRequest!( - _controllerFromPlatform, - uri, - printJob, - ); - else { - // ignore: deprecated_member_use_from_same_package - webviewParams!.onPrint!(_controllerFromPlatform, uri); - return false; - } - } else { - // ignore: deprecated_member_use_from_same_package - _inAppBrowserEventHandler!.onPrint(uri); - return await _inAppBrowserEventHandler!.onPrintRequest( - uri, - printJob, - ); - } - } - break; - case "onInjectedScriptLoaded": - String id = call.arguments[0]; - var onLoadCallback = _injectedScriptsFromURL[id]?.onLoad; - if ((webviewParams != null || _inAppBrowserEventHandler != null) && - onLoadCallback != null) { - onLoadCallback(); - } - break; - case "onInjectedScriptError": - String id = call.arguments[0]; - var onErrorCallback = _injectedScriptsFromURL[id]?.onError; - if ((webviewParams != null || _inAppBrowserEventHandler != null) && - onErrorCallback != null) { - onErrorCallback(); - } - break; - case "onCameraCaptureStateChanged": - if ((webviewParams != null && - webviewParams!.onCameraCaptureStateChanged != null) || - _inAppBrowserEventHandler != null) { - var oldState = MediaCaptureState.fromNativeValue( - call.arguments["oldState"], - ); - var newState = MediaCaptureState.fromNativeValue( - call.arguments["newState"], - ); - - if (webviewParams != null && - webviewParams!.onCameraCaptureStateChanged != null) - webviewParams!.onCameraCaptureStateChanged!( - _controllerFromPlatform, - oldState, - newState, - ); - else - _inAppBrowserEventHandler!.onCameraCaptureStateChanged( - oldState, - newState, - ); - } - break; - case "onMicrophoneCaptureStateChanged": - if ((webviewParams != null && - webviewParams!.onMicrophoneCaptureStateChanged != null) || - _inAppBrowserEventHandler != null) { - var oldState = MediaCaptureState.fromNativeValue( - call.arguments["oldState"], - ); - var newState = MediaCaptureState.fromNativeValue( - call.arguments["newState"], - ); - - if (webviewParams != null && - webviewParams!.onMicrophoneCaptureStateChanged != null) - webviewParams!.onMicrophoneCaptureStateChanged!( - _controllerFromPlatform, - oldState, - newState, - ); - else - _inAppBrowserEventHandler!.onMicrophoneCaptureStateChanged( - oldState, - newState, - ); - } - break; - case "onContentSizeChanged": - if ((webviewParams != null && - webviewParams!.onContentSizeChanged != null) || - _inAppBrowserEventHandler != null) { - var oldContentSize = MapSize.fromMap( - call.arguments["oldContentSize"]?.cast(), - )!; - var newContentSize = MapSize.fromMap( - call.arguments["newContentSize"]?.cast(), - )!; - - if (webviewParams != null && - webviewParams!.onContentSizeChanged != null) - webviewParams!.onContentSizeChanged!( - _controllerFromPlatform, - oldContentSize, - newContentSize, - ); - else - _inAppBrowserEventHandler!.onContentSizeChanged( - oldContentSize, - newContentSize, - ); - } - break; - case "onCallJsHandler": - String handlerName = call.arguments["handlerName"]; - Map handlerDataMap = call.arguments["data"] - .cast(); - // decode args to json - handlerDataMap["args"] = jsonDecode(handlerDataMap["args"]); - final handlerData = JavaScriptHandlerFunctionData.fromMap( - handlerDataMap, - )!; - - _debugLog(handlerName, handlerData); - - switch (handlerName) { - case "onLoadResource": - if ((webviewParams != null && - webviewParams!.onLoadResource != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - arguments["startTime"] = arguments["startTime"] is int - ? arguments["startTime"].toDouble() - : arguments["startTime"]; - arguments["duration"] = arguments["duration"] is int - ? arguments["duration"].toDouble() - : arguments["duration"]; - - var response = LoadedResource.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onLoadResource != null) - webviewParams!.onLoadResource!( - _controllerFromPlatform, - response, - ); - else - _inAppBrowserEventHandler!.onLoadResource(response); - } - return null; - case "shouldInterceptAjaxRequest": - if ((webviewParams != null && - webviewParams!.shouldInterceptAjaxRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - AjaxRequest request = AjaxRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.shouldInterceptAjaxRequest != null) - return jsonEncode( - await params.webviewParams!.shouldInterceptAjaxRequest!( - _controllerFromPlatform, - request, - ), - ); - else - return jsonEncode( - await _inAppBrowserEventHandler!.shouldInterceptAjaxRequest( - request, - ), - ); - } - return null; - case "onAjaxReadyStateChange": - if ((webviewParams != null && - webviewParams!.onAjaxReadyStateChange != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - AjaxRequest request = AjaxRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onAjaxReadyStateChange != null) - return jsonEncode( - (await webviewParams!.onAjaxReadyStateChange!( - _controllerFromPlatform, - request, - ))?.toNativeValue(), - ); - else - return jsonEncode( - (await _inAppBrowserEventHandler!.onAjaxReadyStateChange( - request, - ))?.toNativeValue(), - ); - } - return null; - case "onAjaxProgress": - if ((webviewParams != null && - webviewParams!.onAjaxProgress != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - AjaxRequest request = AjaxRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.onAjaxProgress != null) - return jsonEncode( - (await webviewParams!.onAjaxProgress!( - _controllerFromPlatform, - request, - ))?.toNativeValue(), - ); - else - return jsonEncode( - (await _inAppBrowserEventHandler!.onAjaxProgress( - request, - ))?.toNativeValue(), - ); - } - return null; - case "shouldInterceptFetchRequest": - if ((webviewParams != null && - webviewParams!.shouldInterceptFetchRequest != null) || - _inAppBrowserEventHandler != null) { - Map arguments = handlerData.args[0] - .cast(); - FetchRequest request = FetchRequest.fromMap(arguments)!; - - if (webviewParams != null && - webviewParams!.shouldInterceptFetchRequest != null) - return jsonEncode( - await webviewParams!.shouldInterceptFetchRequest!( - _controllerFromPlatform, - request, - ), - ); - else - return jsonEncode( - await _inAppBrowserEventHandler!.shouldInterceptFetchRequest( - request, - ), - ); - } - return null; - case "onWindowFocus": - if (webviewParams != null && webviewParams!.onWindowFocus != null) - webviewParams!.onWindowFocus!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onWindowFocus(); - return null; - case "onWindowBlur": - if (webviewParams != null && webviewParams!.onWindowBlur != null) - webviewParams!.onWindowBlur!(_controllerFromPlatform); - else if (_inAppBrowserEventHandler != null) - _inAppBrowserEventHandler!.onWindowBlur(); - return null; - case "onInjectedScriptLoaded": - String id = handlerData.args[0]; - var onLoadCallback = _injectedScriptsFromURL[id]?.onLoad; - if ((webviewParams != null || _inAppBrowserEventHandler != null) && - onLoadCallback != null) { - onLoadCallback(); - } - return null; - case "onInjectedScriptError": - String id = handlerData.args[0]; - var onErrorCallback = _injectedScriptsFromURL[id]?.onError; - if ((webviewParams != null || _inAppBrowserEventHandler != null) && - onErrorCallback != null) { - onErrorCallback(); - } - return null; - } - - if (_javaScriptHandlersMap.containsKey(handlerName)) { - // convert result to json - try { - var jsHandlerResult = null; - if (_javaScriptHandlersMap[handlerName] - is JavaScriptHandlerCallback) { - jsHandlerResult = - await (_javaScriptHandlersMap[handlerName] - as JavaScriptHandlerCallback)(handlerData.args); - } else if (_javaScriptHandlersMap[handlerName] - is JavaScriptHandlerFunction) { - jsHandlerResult = - await (_javaScriptHandlersMap[handlerName] - as JavaScriptHandlerFunction)(handlerData); - } else { - jsHandlerResult = await _javaScriptHandlersMap[handlerName]!(); - } - return jsonEncode(jsHandlerResult); - } catch (error, stacktrace) { - developer.log( - error.toString() + '\n' + stacktrace.toString(), - name: 'JavaScript Handler "$handlerName"', - ); - throw Exception(error.toString().replaceFirst('Exception: ', '')); - } - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - Future getUrl() async { - Map args = {}; - String? url = await channel?.invokeMethod('getUrl', args); - return url != null ? WebUri(url) : null; - } - - @override - Future getTitle() async { - Map args = {}; - return await channel?.invokeMethod('getTitle', args); - } - - @override - Future getProgress() async { - Map args = {}; - return await channel?.invokeMethod('getProgress', args); - } - - @override - Future getHtml() async { - String? html; - - InAppWebViewSettings? settings = await getSettings(); - if (settings != null && settings.javaScriptEnabled == true) { - html = await evaluateJavascript( - source: "window.document.getElementsByTagName('html')[0].outerHTML;", - ); - if (html != null && html.isNotEmpty) return html; - } - - var webviewUrl = await getUrl(); - if (webviewUrl == null) { - return html; - } - - if (webviewUrl.isScheme("file")) { - var assetPathSplit = webviewUrl.toString().split("/flutter_assets/"); - var assetPath = assetPathSplit[assetPathSplit.length - 1]; - try { - var bytes = await rootBundle.load(assetPath); - html = utf8.decode(bytes.buffer.asUint8List()); - } catch (e) {} - } else { - try { - HttpClient client = HttpClient(); - var htmlRequest = await client.getUrl(webviewUrl); - html = await (await htmlRequest.close()) - .transform(Utf8Decoder()) - .join(); - } catch (e) { - developer.log(e.toString(), name: this.runtimeType.toString()); - } - } - - return html; - } - - @override - Future> getFavicons() async { - List favicons = []; - - var webviewUrl = await getUrl(); - - if (webviewUrl == null) { - return favicons; - } - - String? manifestUrl; - - var html = await getHtml(); - if (html == null || html.isEmpty) { - return favicons; - } - var assetPathBase; - - if (webviewUrl.isScheme("file")) { - var assetPathSplit = webviewUrl.toString().split("/flutter_assets/"); - assetPathBase = assetPathSplit[0] + "/flutter_assets/"; - } - - InAppWebViewSettings? settings = await getSettings(); - if (settings != null && settings.javaScriptEnabled == true) { - List> links = - (await evaluateJavascript( - source: """ -(function() { - var linkNodes = document.head.getElementsByTagName("link"); - var links = []; - for (var i = 0; i < linkNodes.length; i++) { - var linkNode = linkNodes[i]; - if (linkNode.rel === 'manifest') { - links.push( - { - rel: linkNode.rel, - href: linkNode.href, - sizes: null - } - ); - } else if (linkNode.rel != null && linkNode.rel.indexOf('icon') >= 0) { - links.push( - { - rel: linkNode.rel, - href: linkNode.href, - sizes: linkNode.sizes != null && linkNode.sizes.value != "" ? linkNode.sizes.value : null - } - ); - } - } - return links; -})(); -""", - ))?.cast>() ?? - []; - for (var link in links) { - if (link["rel"] == "manifest") { - manifestUrl = link["href"]; - if (!_isUrlAbsolute(manifestUrl!)) { - if (manifestUrl.startsWith("/")) { - manifestUrl = manifestUrl.substring(1); - } - manifestUrl = - ((assetPathBase == null) - ? webviewUrl.scheme + "://" + webviewUrl.host + "/" - : assetPathBase) + - manifestUrl; - } - continue; - } - favicons.addAll( - _createFavicons( - webviewUrl, - assetPathBase, - link["href"], - link["rel"], - link["sizes"], - false, - ), - ); - } - } - - // try to get /favicon.ico - try { - HttpClient client = HttpClient(); - var faviconUrl = - webviewUrl.scheme + "://" + webviewUrl.host + "/favicon.ico"; - var faviconUri = WebUri(faviconUrl); - var headRequest = await client.headUrl(faviconUri); - var headResponse = await headRequest.close(); - if (headResponse.statusCode == 200) { - favicons.add(Favicon(url: faviconUri, rel: "shortcut icon")); - } - } catch (e) { - developer.log( - "/favicon.ico file not found: " + e.toString(), - name: runtimeType.toString(), - ); - } - - // try to get the manifest file - HttpClientRequest? manifestRequest; - HttpClientResponse? manifestResponse; - bool manifestFound = false; - if (manifestUrl == null) { - manifestUrl = - webviewUrl.scheme + "://" + webviewUrl.host + "/manifest.json"; - } - try { - HttpClient client = HttpClient(); - manifestRequest = await client.getUrl(Uri.parse(manifestUrl)); - manifestResponse = await manifestRequest.close(); - manifestFound = - manifestResponse.statusCode == 200 && - manifestResponse.headers.contentType?.mimeType == "application/json"; - } catch (e) { - developer.log( - "Manifest file not found: " + e.toString(), - name: this.runtimeType.toString(), - ); - } - - if (manifestFound) { - try { - Map manifest = json.decode( - await manifestResponse!.transform(Utf8Decoder()).join(), - ); - if (manifest.containsKey("icons")) { - for (Map icon in manifest["icons"]) { - favicons.addAll( - _createFavicons( - webviewUrl, - assetPathBase, - icon["src"], - icon["rel"], - icon["sizes"], - true, - ), - ); - } - } - } catch (e) { - developer.log( - "Cannot get favicons from Manifest file. It might not have a valid format: " + - e.toString(), - error: e, - name: runtimeType.toString(), - ); - } - } - - return favicons; - } - - bool _isUrlAbsolute(String url) { - return url.startsWith("http://") || url.startsWith("https://"); - } - - List _createFavicons( - WebUri url, - String? assetPathBase, - String urlIcon, - String? rel, - String? sizes, - bool isManifest, - ) { - List favicons = []; - - List urlSplit = urlIcon.split("/"); - if (!_isUrlAbsolute(urlIcon)) { - if (urlIcon.startsWith("/")) { - urlIcon = urlIcon.substring(1); - } - urlIcon = - ((assetPathBase == null) - ? url.scheme + "://" + url.host + "/" - : assetPathBase) + - urlIcon; - } - if (isManifest) { - rel = (sizes != null) - ? urlSplit[urlSplit.length - 1] - .replaceFirst("-" + sizes, "") - .split(" ")[0] - .split(".")[0] - : null; - } - if (sizes != null && sizes.isNotEmpty && sizes != "any") { - List sizesSplit = sizes.split(" "); - for (String size in sizesSplit) { - int width = int.parse(size.split("x")[0]); - int height = int.parse(size.split("x")[1]); - favicons.add( - Favicon(url: WebUri(urlIcon), rel: rel, width: width, height: height), - ); - } - } else { - favicons.add( - Favicon(url: WebUri(urlIcon), rel: rel, width: null, height: null), - ); - } - - return favicons; - } - - @override - Future loadUrl({ - required URLRequest urlRequest, - @Deprecated('Use allowingReadAccessTo instead') - Uri? iosAllowingReadAccessTo, - WebUri? allowingReadAccessTo, - }) async { - assert(urlRequest.url != null && urlRequest.url.toString().isNotEmpty); - assert( - allowingReadAccessTo == null || allowingReadAccessTo.isScheme("file"), - ); - assert( - iosAllowingReadAccessTo == null || - iosAllowingReadAccessTo.isScheme("file"), - ); - - Map args = {}; - args.putIfAbsent('urlRequest', () => urlRequest.toMap()); - args.putIfAbsent( - 'allowingReadAccessTo', - () => - allowingReadAccessTo?.toString() ?? - iosAllowingReadAccessTo?.toString(), - ); - await channel?.invokeMethod('loadUrl', args); - } - - @override - Future postUrl({ - required WebUri url, - required Uint8List postData, - }) async { - assert(url.toString().isNotEmpty); - Map args = {}; - args.putIfAbsent('url', () => url.toString()); - args.putIfAbsent('postData', () => postData); - await channel?.invokeMethod('postUrl', args); - } - - @override - Future loadData({ - required String data, - String mimeType = "text/html", - String encoding = "utf8", - WebUri? baseUrl, - @Deprecated('Use historyUrl instead') Uri? androidHistoryUrl, - WebUri? historyUrl, - @Deprecated('Use allowingReadAccessTo instead') - Uri? iosAllowingReadAccessTo, - WebUri? allowingReadAccessTo, - }) async { - assert( - allowingReadAccessTo == null || allowingReadAccessTo.isScheme("file"), - ); - assert( - iosAllowingReadAccessTo == null || - iosAllowingReadAccessTo.isScheme("file"), - ); - - Map args = {}; - args.putIfAbsent('data', () => data); - args.putIfAbsent('mimeType', () => mimeType); - args.putIfAbsent('encoding', () => encoding); - args.putIfAbsent('baseUrl', () => baseUrl?.toString() ?? "about:blank"); - args.putIfAbsent( - 'historyUrl', - () => - historyUrl?.toString() ?? - androidHistoryUrl?.toString() ?? - "about:blank", - ); - args.putIfAbsent( - 'allowingReadAccessTo', - () => - allowingReadAccessTo?.toString() ?? - iosAllowingReadAccessTo?.toString(), - ); - await channel?.invokeMethod('loadData', args); - } - - @override - Future loadFile({required String assetFilePath}) async { - assert(assetFilePath.isNotEmpty); - Map args = {}; - args.putIfAbsent('assetFilePath', () => assetFilePath); - await channel?.invokeMethod('loadFile', args); - } - - @override - Future reload() async { - Map args = {}; - await channel?.invokeMethod('reload', args); - } - - @override - Future goBack() async { - Map args = {}; - await channel?.invokeMethod('goBack', args); - } - - @override - Future canGoBack() async { - Map args = {}; - return await channel?.invokeMethod('canGoBack', args) ?? false; - } - - @override - Future goForward() async { - Map args = {}; - await channel?.invokeMethod('goForward', args); - } - - @override - Future canGoForward() async { - Map args = {}; - return await channel?.invokeMethod('canGoForward', args) ?? false; - } - - @override - Future goBackOrForward({required int steps}) async { - Map args = {}; - args.putIfAbsent('steps', () => steps); - await channel?.invokeMethod('goBackOrForward', args); - } - - @override - Future canGoBackOrForward({required int steps}) async { - Map args = {}; - args.putIfAbsent('steps', () => steps); - return await channel?.invokeMethod('canGoBackOrForward', args) ?? - false; - } - - @override - Future goTo({required WebHistoryItem historyItem}) async { - var steps = historyItem.offset; - if (steps != null) { - await goBackOrForward(steps: steps); - } - } - - @override - Future isLoading() async { - Map args = {}; - return await channel?.invokeMethod('isLoading', args) ?? false; - } - - @override - Future stopLoading() async { - Map args = {}; - await channel?.invokeMethod('stopLoading', args); - } - - @override - Future evaluateJavascript({ - required String source, - ContentWorld? contentWorld, - }) async { - Map args = {}; - args.putIfAbsent('source', () => source); - args.putIfAbsent('contentWorld', () => contentWorld?.toMap()); - var data = await channel?.invokeMethod('evaluateJavascript', args); - return data; - } - - @override - Future injectJavascriptFileFromUrl({ - required WebUri urlFile, - ScriptHtmlTagAttributes? scriptHtmlTagAttributes, - }) async { - assert(urlFile.toString().isNotEmpty); - var id = scriptHtmlTagAttributes?.id; - if (scriptHtmlTagAttributes != null && id != null) { - _injectedScriptsFromURL[id] = scriptHtmlTagAttributes; - } - Map args = {}; - args.putIfAbsent('urlFile', () => urlFile.toString()); - args.putIfAbsent( - 'scriptHtmlTagAttributes', - () => scriptHtmlTagAttributes?.toMap(), - ); - await channel?.invokeMethod('injectJavascriptFileFromUrl', args); - } - - @override - Future injectJavascriptFileFromAsset({ - required String assetFilePath, - }) async { - String source = await rootBundle.loadString(assetFilePath); - return await evaluateJavascript(source: source); - } - - @override - Future injectCSSCode({required String source}) async { - Map args = {}; - args.putIfAbsent('source', () => source); - await channel?.invokeMethod('injectCSSCode', args); - } - - @override - Future injectCSSFileFromUrl({ - required WebUri urlFile, - CSSLinkHtmlTagAttributes? cssLinkHtmlTagAttributes, - }) async { - assert(urlFile.toString().isNotEmpty); - Map args = {}; - args.putIfAbsent('urlFile', () => urlFile.toString()); - args.putIfAbsent( - 'cssLinkHtmlTagAttributes', - () => cssLinkHtmlTagAttributes?.toMap(), - ); - await channel?.invokeMethod('injectCSSFileFromUrl', args); - } - - @override - Future injectCSSFileFromAsset({required String assetFilePath}) async { - String source = await rootBundle.loadString(assetFilePath); - await injectCSSCode(source: source); - } - - @override - void addJavaScriptHandler({ - required String handlerName, - required Function callback, - }) { - assert( - !kJavaScriptHandlerForbiddenNames.contains(handlerName), - '"$handlerName" is a forbidden name!', - ); - this._javaScriptHandlersMap[handlerName] = (callback); - } - - @override - Function? removeJavaScriptHandler({required String handlerName}) { - return this._javaScriptHandlersMap.remove(handlerName); - } - - @override - bool hasJavaScriptHandler({required String handlerName}) { - return this._javaScriptHandlersMap.containsKey(handlerName); - } - - @override - Future takeScreenshot({ - ScreenshotConfiguration? screenshotConfiguration, - }) async { - Map args = {}; - args.putIfAbsent( - 'screenshotConfiguration', - () => screenshotConfiguration?.toMap(), - ); - return await channel?.invokeMethod('takeScreenshot', args); - } - - @override - @Deprecated('Use setSettings instead') - Future setOptions({required InAppWebViewGroupOptions options}) async { - InAppWebViewSettings settings = - InAppWebViewSettings.fromMap(options.toMap()) ?? InAppWebViewSettings(); - await setSettings(settings: settings); - } - - @override - @Deprecated('Use getSettings instead') - Future getOptions() async { - InAppWebViewSettings? settings = await getSettings(); - - Map? options = settings?.toMap(); - if (options != null) { - options = options.cast(); - return InAppWebViewGroupOptions.fromMap(options as Map); - } - - return null; - } - - @override - Future setSettings({required InAppWebViewSettings settings}) async { - Map args = {}; - - args.putIfAbsent('settings', () => settings.toMap()); - await channel?.invokeMethod('setSettings', args); - } - - @override - Future getSettings() async { - Map args = {}; - - Map? settings = await channel?.invokeMethod( - 'getSettings', - args, - ); - if (settings != null) { - settings = settings.cast(); - return InAppWebViewSettings.fromMap(settings as Map); - } - - return null; - } - - @override - Future getCopyBackForwardList() async { - Map args = {}; - Map? result = (await channel?.invokeMethod( - 'getCopyBackForwardList', - args, - ))?.cast(); - return WebHistory.fromMap(result); - } - - @override - @Deprecated("Use InAppWebViewController.clearAllCache instead") - Future clearCache() async { - Map args = {}; - await channel?.invokeMethod('clearCache', args); - } - - @override - @Deprecated("Use FindInteractionController.findAll instead") - Future findAllAsync({required String find}) async { - Map args = {}; - args.putIfAbsent('find', () => find); - await channel?.invokeMethod('findAll', args); - } - - @override - @Deprecated("Use FindInteractionController.findNext instead") - Future findNext({required bool forward}) async { - Map args = {}; - args.putIfAbsent('forward', () => forward); - await channel?.invokeMethod('findNext', args); - } - - @override - @Deprecated("Use FindInteractionController.clearMatches instead") - Future clearMatches() async { - Map args = {}; - await channel?.invokeMethod('clearMatches', args); - } - - @override - @Deprecated("Use tRexRunnerHtml instead") - Future getTRexRunnerHtml() async { - return await tRexRunnerHtml; - } - - @override - @Deprecated("Use tRexRunnerCss instead") - Future getTRexRunnerCss() async { - return await tRexRunnerCss; - } - - @override - Future scrollTo({ - required int x, - required int y, - bool animated = false, - }) async { - Map args = {}; - args.putIfAbsent('x', () => x); - args.putIfAbsent('y', () => y); - args.putIfAbsent('animated', () => animated); - await channel?.invokeMethod('scrollTo', args); - } - - @override - Future scrollBy({ - required int x, - required int y, - bool animated = false, - }) async { - Map args = {}; - args.putIfAbsent('x', () => x); - args.putIfAbsent('y', () => y); - args.putIfAbsent('animated', () => animated); - await channel?.invokeMethod('scrollBy', args); - } - - @override - Future pauseTimers() async { - Map args = {}; - await channel?.invokeMethod('pauseTimers', args); - } - - @override - Future resumeTimers() async { - Map args = {}; - await channel?.invokeMethod('resumeTimers', args); - } - - @override - Future printCurrentPage({ - PrintJobSettings? settings, - }) async { - Map args = {}; - args.putIfAbsent("settings", () => settings?.toMap()); - String? jobId = await channel?.invokeMethod( - 'printCurrentPage', - args, - ); - if (jobId != null) { - return MacOSPrintJobController( - PlatformPrintJobControllerCreationParams(id: jobId), - ); - } - return null; - } - - @override - Future getContentHeight() async { - Map args = {}; - var height = await channel?.invokeMethod('getContentHeight', args); - if (height == null || height == 0) { - // try to use javascript - var scrollHeight = await evaluateJavascript( - source: "document.documentElement.scrollHeight;", - ); - if (scrollHeight != null && scrollHeight is num) { - height = scrollHeight.toInt(); - } - } - return height; - } - - @override - Future getContentWidth() async { - Map args = {}; - var height = await channel?.invokeMethod('getContentWidth', args); - if (height == null || height == 0) { - // try to use javascript - var scrollHeight = await evaluateJavascript( - source: "document.documentElement.scrollWidth;", - ); - if (scrollHeight != null && scrollHeight is num) { - height = scrollHeight.toInt(); - } - } - return height; - } - - @override - Future zoomBy({ - required double zoomFactor, - @Deprecated('Use animated instead') bool? iosAnimated, - bool animated = false, - }) async { - Map args = {}; - args.putIfAbsent('zoomFactor', () => zoomFactor); - args.putIfAbsent('animated', () => iosAnimated ?? animated); - return await channel?.invokeMethod('zoomBy', args); - } - - @override - Future getOriginalUrl() async { - Map args = {}; - String? url = await channel?.invokeMethod('getOriginalUrl', args); - return url != null ? WebUri(url) : null; - } - - @override - @Deprecated('Use getZoomScale instead') - Future getScale() async { - return await getZoomScale(); - } - - @override - Future getSelectedText() async { - Map args = {}; - return await channel?.invokeMethod('getSelectedText', args); - } - - @override - Future requestFocus({ - FocusDirection? direction, - InAppWebViewRect? previouslyFocusedRect, - }) async { - Map args = {}; - args.putIfAbsent("direction", () => direction?.toNativeValue()); - args.putIfAbsent( - "previouslyFocusedRect", - () => previouslyFocusedRect?.toMap(), - ); - return await channel?.invokeMethod('requestFocus', args); - } - - @override - Future clearFocus() async { - Map args = {}; - return await channel?.invokeMethod('clearFocus', args); - } - - @override - Future> getMetaTags() async { - List metaTags = []; - - List>? metaTagList = (await evaluateJavascript( - source: """ -(function() { - var metaTags = []; - var metaTagNodes = document.head.getElementsByTagName('meta'); - for (var i = 0; i < metaTagNodes.length; i++) { - var metaTagNode = metaTagNodes[i]; - - var otherAttributes = metaTagNode.getAttributeNames(); - var nameIndex = otherAttributes.indexOf("name"); - if (nameIndex !== -1) otherAttributes.splice(nameIndex, 1); - var contentIndex = otherAttributes.indexOf("content"); - if (contentIndex !== -1) otherAttributes.splice(contentIndex, 1); - - var attrs = []; - for (var j = 0; j < otherAttributes.length; j++) { - var otherAttribute = otherAttributes[j]; - attrs.push( - { - name: otherAttribute, - value: metaTagNode.getAttribute(otherAttribute) - } - ); - } - - metaTags.push( - { - name: metaTagNode.name, - content: metaTagNode.content, - attrs: attrs - } - ); - } - return metaTags; -})(); - """, - ))?.cast>(); - - if (metaTagList == null) { - return metaTags; - } - - for (var metaTag in metaTagList) { - var attrs = []; - - for (var metaTagAttr in metaTag["attrs"]) { - attrs.add( - MetaTagAttribute( - name: metaTagAttr["name"], - value: metaTagAttr["value"], - ), - ); - } - - metaTags.add( - MetaTag( - name: metaTag["name"], - content: metaTag["content"], - attrs: attrs, - ), - ); - } - - return metaTags; - } - - @override - Future getMetaThemeColor() async { - Color? themeColor; - - try { - Map args = {}; - themeColor = UtilColor.fromStringRepresentation( - await channel?.invokeMethod('getMetaThemeColor', args), - ); - return themeColor; - } catch (e) { - // not implemented - } - - // try using javascript - var metaTags = await getMetaTags(); - MetaTag? metaTagThemeColor; - - for (var metaTag in metaTags) { - if (metaTag.name == "theme-color") { - metaTagThemeColor = metaTag; - break; - } - } - - if (metaTagThemeColor == null) { - return null; - } - - var colorValue = metaTagThemeColor.content; - - themeColor = colorValue != null - ? UtilColor.fromStringRepresentation(colorValue) - : null; - - return themeColor; - } - - @override - Future getScrollX() async { - Map args = {}; - return await channel?.invokeMethod('getScrollX', args); - } - - @override - Future getScrollY() async { - Map args = {}; - return await channel?.invokeMethod('getScrollY', args); - } - - @override - Future getCertificate() async { - Map args = {}; - Map? sslCertificateMap = (await channel?.invokeMethod( - 'getCertificate', - args, - ))?.cast(); - return SslCertificate.fromMap(sslCertificateMap); - } - - @override - Future addUserScript({required UserScript userScript}) async { - assert(webviewParams?.windowId == null); - - Map args = {}; - args.putIfAbsent('userScript', () => userScript.toMap()); - if (!(_userScripts[userScript.injectionTime]?.contains(userScript) ?? - false)) { - _userScripts[userScript.injectionTime]?.add(userScript); - await channel?.invokeMethod('addUserScript', args); - } - } - - @override - Future addUserScripts({required List userScripts}) async { - assert(webviewParams?.windowId == null); - - for (var i = 0; i < userScripts.length; i++) { - await addUserScript(userScript: userScripts[i]); - } - } - - @override - Future removeUserScript({required UserScript userScript}) async { - assert(webviewParams?.windowId == null); - - var index = _userScripts[userScript.injectionTime]?.indexOf(userScript); - if (index == null || index == -1) { - return false; - } - - _userScripts[userScript.injectionTime]?.remove(userScript); - Map args = {}; - args.putIfAbsent('userScript', () => userScript.toMap()); - args.putIfAbsent('index', () => index); - await channel?.invokeMethod('removeUserScript', args); - - return true; - } - - @override - Future removeUserScriptsByGroupName({required String groupName}) async { - assert(webviewParams?.windowId == null); - - final List userScriptsAtDocumentStart = List.from( - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_START] ?? [], - ); - for (final userScript in userScriptsAtDocumentStart) { - if (userScript.groupName == groupName) { - _userScripts[userScript.injectionTime]?.remove(userScript); - } - } - - final List userScriptsAtDocumentEnd = List.from( - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_END] ?? [], - ); - for (final userScript in userScriptsAtDocumentEnd) { - if (userScript.groupName == groupName) { - _userScripts[userScript.injectionTime]?.remove(userScript); - } - } - - Map args = {}; - args.putIfAbsent('groupName', () => groupName); - await channel?.invokeMethod('removeUserScriptsByGroupName', args); - } - - @override - Future removeUserScripts({ - required List userScripts, - }) async { - assert(webviewParams?.windowId == null); - - for (final userScript in userScripts) { - await removeUserScript(userScript: userScript); - } - } - - @override - Future removeAllUserScripts() async { - assert(webviewParams?.windowId == null); - - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.clear(); - _userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.clear(); - - Map args = {}; - await channel?.invokeMethod('removeAllUserScripts', args); - } - - @override - bool hasUserScript({required UserScript userScript}) { - return _userScripts[userScript.injectionTime]?.contains(userScript) ?? - false; - } - - @override - Future callAsyncJavaScript({ - required String functionBody, - Map arguments = const {}, - ContentWorld? contentWorld, - }) async { - Map args = {}; - args.putIfAbsent('functionBody', () => functionBody); - args.putIfAbsent('arguments', () => arguments); - args.putIfAbsent('contentWorld', () => contentWorld?.toMap()); - var data = await channel?.invokeMethod('callAsyncJavaScript', args); - if (data == null) { - return null; - } - return CallAsyncJavaScriptResult( - value: data["value"], - error: data["error"], - ); - } - - @override - Future saveWebArchive({ - required String filePath, - bool autoname = false, - }) async { - if (!autoname) { - assert( - WebArchiveFormat.WEBARCHIVE.isSupported() && - filePath.endsWith( - "." + WebArchiveFormat.WEBARCHIVE.toNativeValue()!, - ), - ); - } - - Map args = {}; - args.putIfAbsent("filePath", () => filePath); - args.putIfAbsent("autoname", () => autoname); - return await channel?.invokeMethod('saveWebArchive', args); - } - - @override - Future isSecureContext() async { - Map args = {}; - return await channel?.invokeMethod('isSecureContext', args) ?? false; - } - - @override - Future createWebMessageChannel() async { - Map args = {}; - Map? result = (await channel?.invokeMethod( - 'createWebMessageChannel', - args, - ))?.cast(); - final webMessageChannel = MacOSWebMessageChannel.static().fromMap(result); - if (webMessageChannel != null) { - _webMessageChannels.add(webMessageChannel); - } - return webMessageChannel; - } - - @override - Future postWebMessage({ - required WebMessage message, - WebUri? targetOrigin, - }) async { - if (targetOrigin == null) { - targetOrigin = WebUri(''); - } - Map args = {}; - args.putIfAbsent('message', () => message.toMap()); - args.putIfAbsent('targetOrigin', () => targetOrigin.toString()); - await channel?.invokeMethod('postWebMessage', args); - } - - @override - Future addWebMessageListener( - PlatformWebMessageListener webMessageListener, - ) async { - assert( - !_webMessageListeners.contains(webMessageListener), - "${webMessageListener} was already added.", - ); - assert( - !_webMessageListenerObjNames.contains( - webMessageListener.params.jsObjectName, - ), - "jsObjectName ${webMessageListener.params.jsObjectName} was already added.", - ); - _webMessageListeners.add(webMessageListener as MacOSWebMessageListener); - _webMessageListenerObjNames.add(webMessageListener.params.jsObjectName); - - Map args = {}; - args.putIfAbsent('webMessageListener', () => webMessageListener.toMap()); - await channel?.invokeMethod('addWebMessageListener', args); - } - - @override - bool hasWebMessageListener(PlatformWebMessageListener webMessageListener) { - return _webMessageListeners.contains(webMessageListener) || - _webMessageListenerObjNames.contains( - webMessageListener.params.jsObjectName, - ); - } - - @override - Future canScrollVertically() async { - Map args = {}; - return await channel?.invokeMethod('canScrollVertically', args) ?? - false; - } - - @override - Future canScrollHorizontally() async { - Map args = {}; - return await channel?.invokeMethod('canScrollHorizontally', args) ?? - false; - } - - @override - Future reloadFromOrigin() async { - Map args = {}; - await channel?.invokeMethod('reloadFromOrigin', args); - } - - @override - Future createPdf({ - @Deprecated("Use pdfConfiguration instead") - // ignore: deprecated_member_use_from_same_package - IOSWKPDFConfiguration? iosWKPdfConfiguration, - PDFConfiguration? pdfConfiguration, - }) async { - Map args = {}; - args.putIfAbsent( - 'pdfConfiguration', - () => pdfConfiguration?.toMap() ?? iosWKPdfConfiguration?.toMap(), - ); - return await channel?.invokeMethod('createPdf', args); - } - - @override - Future createWebArchiveData() async { - Map args = {}; - return await channel?.invokeMethod('createWebArchiveData', args); - } - - @override - Future hasOnlySecureContent() async { - Map args = {}; - return await channel?.invokeMethod('hasOnlySecureContent', args) ?? - false; - } - - @override - Future pauseAllMediaPlayback() async { - Map args = {}; - return await channel?.invokeMethod('pauseAllMediaPlayback', args); - } - - @override - Future setAllMediaPlaybackSuspended({required bool suspended}) async { - Map args = {}; - args.putIfAbsent("suspended", () => suspended); - return await channel?.invokeMethod('setAllMediaPlaybackSuspended', args); - } - - @override - Future closeAllMediaPresentations() async { - Map args = {}; - return await channel?.invokeMethod('closeAllMediaPresentations', args); - } - - @override - Future requestMediaPlaybackState() async { - Map args = {}; - return MediaPlaybackState.fromNativeValue( - await channel?.invokeMethod('requestMediaPlaybackState', args), - ); - } - - @override - Future isInFullscreen() async { - Map args = {}; - return await channel?.invokeMethod('isInFullscreen', args) ?? false; - } - - @override - Future getCameraCaptureState() async { - Map args = {}; - return MediaCaptureState.fromNativeValue( - await channel?.invokeMethod('getCameraCaptureState', args), - ); - } - - @override - Future setCameraCaptureState({required MediaCaptureState state}) async { - Map args = {}; - args.putIfAbsent('state', () => state.toNativeValue()); - await channel?.invokeMethod('setCameraCaptureState', args); - } - - @override - Future getMicrophoneCaptureState() async { - Map args = {}; - return MediaCaptureState.fromNativeValue( - await channel?.invokeMethod('getMicrophoneCaptureState', args), - ); - } - - @override - Future setMicrophoneCaptureState({ - required MediaCaptureState state, - }) async { - Map args = {}; - args.putIfAbsent('state', () => state.toNativeValue()); - await channel?.invokeMethod('setMicrophoneCaptureState', args); - } - - @override - Future loadSimulatedRequest({ - required URLRequest urlRequest, - required Uint8List data, - URLResponse? urlResponse, - }) async { - Map args = {}; - args.putIfAbsent('urlRequest', () => urlRequest.toMap()); - args.putIfAbsent('data', () => data); - args.putIfAbsent('urlResponse', () => urlResponse?.toMap()); - await channel?.invokeMethod('loadSimulatedRequest', args); - } - - @override - Future getDefaultUserAgent() async { - Map args = {}; - return await _staticChannel.invokeMethod( - 'getDefaultUserAgent', - args, - ) ?? - ''; - } - - @override - Future handlesURLScheme(String urlScheme) async { - Map args = {}; - args.putIfAbsent('urlScheme', () => urlScheme); - return await _staticChannel.invokeMethod('handlesURLScheme', args); - } - - @override - Future disposeKeepAlive(InAppWebViewKeepAlive keepAlive) async { - Map args = {}; - args.putIfAbsent('keepAliveId', () => keepAlive.id); - await _staticChannel.invokeMethod('disposeKeepAlive', args); - _keepAliveMap[keepAlive] = null; - } - - @override - Future clearAllCache({bool includeDiskFiles = true}) async { - Map args = {}; - args.putIfAbsent('includeDiskFiles', () => includeDiskFiles); - await _staticChannel.invokeMethod('clearAllCache', args); - } - - @override - Future setJavaScriptBridgeName(String bridgeName) async { - assert( - RegExp(r'^[a-zA-Z_]\w*$').hasMatch(bridgeName), - 'bridgeName must be a non-empty string with only alphanumeric and underscore characters. It can\'t start with a number.', - ); - Map args = {}; - args.putIfAbsent('bridgeName', () => bridgeName); - await _staticChannel.invokeMethod('setJavaScriptBridgeName', args); - } - - @override - Future getJavaScriptBridgeName() async { - Map args = {}; - return await _staticChannel.invokeMethod( - 'getJavaScriptBridgeName', - args, - ) ?? - ''; - } - - @override - Future get tRexRunnerHtml async => await rootBundle.loadString( - 'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html', - ); - - @override - Future get tRexRunnerCss async => await rootBundle.loadString( - 'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.css', - ); - - @override - dynamic getViewId() { - return id; - } - - @override - void dispose({bool isKeepAlive = false}) { - disposeChannel(removeMethodCallHandler: !isKeepAlive); - _inAppBrowser = null; - webStorage.dispose(); - if (!isKeepAlive) { - _controllerFromPlatform = null; - _javaScriptHandlersMap.clear(); - _userScripts.clear(); - _webMessageListenerObjNames.clear(); - _injectedScriptsFromURL.clear(); - for (final webMessageChannel in _webMessageChannels) { - webMessageChannel.dispose(); - } - _webMessageChannels.clear(); - for (final webMessageListener in _webMessageListeners) { - webMessageListener.dispose(); - } - _webMessageListeners.clear(); - } - } -} - -extension InternalInAppWebViewController on MacOSInAppWebViewController { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_macos/lib/src/in_app_webview/main.dart b/flutter_inappwebview_macos/lib/src/in_app_webview/main.dart deleted file mode 100644 index b83b0611e7..0000000000 --- a/flutter_inappwebview_macos/lib/src/in_app_webview/main.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'in_app_webview_controller.dart' hide InternalInAppWebViewController; -export 'in_app_webview.dart'; -export 'headless_in_app_webview.dart' hide InternalHeadlessInAppWebView; diff --git a/flutter_inappwebview_macos/lib/src/inappwebview_platform.dart b/flutter_inappwebview_macos/lib/src/inappwebview_platform.dart deleted file mode 100644 index 4fe102eef8..0000000000 --- a/flutter_inappwebview_macos/lib/src/inappwebview_platform.dart +++ /dev/null @@ -1,714 +0,0 @@ -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import 'cookie_manager.dart'; -import 'find_interaction/main.dart'; -import 'http_auth_credentials_database.dart'; -import 'in_app_browser/in_app_browser.dart'; -import 'in_app_webview/main.dart'; -import 'print_job/main.dart'; -import 'proxy_controller.dart'; -import 'web_authentication_session/main.dart'; -import 'web_message/main.dart'; -import 'web_storage/main.dart'; - -/// Implementation of [InAppWebViewPlatform] using the WebKit API. -class MacOSInAppWebViewPlatform extends InAppWebViewPlatform { - /// Registers this class as the default instance of [InAppWebViewPlatform]. - static void registerWith() { - InAppWebViewPlatform.instance = MacOSInAppWebViewPlatform(); - } - - /// Creates a new [MacOSCookieManager]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [CookieManager] in `flutter_inappwebview` instead. - @override - MacOSCookieManager createPlatformCookieManager( - PlatformCookieManagerCreationParams params, - ) { - return MacOSCookieManager(params); - } - - /// Creates a new empty [MacOSCookieManager] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [CookieManager] in `flutter_inappwebview` instead. - @override - MacOSCookieManager createPlatformCookieManagerStatic() { - return MacOSCookieManager.static(); - } - - /// Creates a new [MacOSInAppWebViewController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebViewController] in `flutter_inappwebview` instead. - @override - MacOSInAppWebViewController createPlatformInAppWebViewController( - PlatformInAppWebViewControllerCreationParams params, - ) { - return MacOSInAppWebViewController(params); - } - - /// Creates a new empty [MacOSInAppWebViewController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebViewController] in `flutter_inappwebview` instead. - @override - MacOSInAppWebViewController createPlatformInAppWebViewControllerStatic() { - return MacOSInAppWebViewController.static(); - } - - /// Creates a new [MacOSInAppWebViewWidget]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebView] in `flutter_inappwebview` instead. - @override - MacOSInAppWebViewWidget createPlatformInAppWebViewWidget( - PlatformInAppWebViewWidgetCreationParams params, - ) { - return MacOSInAppWebViewWidget(params); - } - - /// Creates a new empty [MacOSInAppWebViewWidget] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppWebView] in `flutter_inappwebview` instead. - @override - MacOSInAppWebViewWidget createPlatformInAppWebViewWidgetStatic() { - return MacOSInAppWebViewWidget.static(); - } - - /// Creates a new [MacOSFindInteractionController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [FindInteractionController] in `flutter_inappwebview` instead. - @override - MacOSFindInteractionController createPlatformFindInteractionController( - PlatformFindInteractionControllerCreationParams params, - ) { - return MacOSFindInteractionController(params); - } - - /// Creates a new empty [MacOSFindInteractionController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [FindInteractionController] in `flutter_inappwebview` instead. - @override - MacOSFindInteractionController - createPlatformFindInteractionControllerStatic() { - return MacOSFindInteractionController.static(); - } - - /// Creates a new [MacOSPrintJobController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [PrintJobController] in `flutter_inappwebview` instead. - @override - MacOSPrintJobController createPlatformPrintJobController( - PlatformPrintJobControllerCreationParams params, - ) { - return MacOSPrintJobController(params); - } - - /// Creates a new empty [PlatformPrintJobController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [PrintJobController] in `flutter_inappwebview` instead. - @override - MacOSPrintJobController createPlatformPrintJobControllerStatic() { - return MacOSPrintJobController.static(); - } - - /// Creates a new empty [PlatformPullToRefreshController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [PullToRefreshController] in `flutter_inappwebview` instead. - @override - PlatformPullToRefreshController - createPlatformPullToRefreshControllerStatic() { - return _PlatformPullToRefreshController.static(); - } - - /// Creates a new [MacOSWebMessageChannel]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebMessageChannel] in `flutter_inappwebview` instead. - @override - MacOSWebMessageChannel createPlatformWebMessageChannel( - PlatformWebMessageChannelCreationParams params, - ) { - return MacOSWebMessageChannel(params); - } - - /// Creates a new empty [MacOSWebMessageChannel] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebMessageChannel] in `flutter_inappwebview` instead. - @override - MacOSWebMessageChannel createPlatformWebMessageChannelStatic() { - return MacOSWebMessageChannel.static(); - } - - /// Creates a new [MacOSWebMessageListener]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebMessageListener] in `flutter_inappwebview` instead. - @override - MacOSWebMessageListener createPlatformWebMessageListener( - PlatformWebMessageListenerCreationParams params, - ) { - return MacOSWebMessageListener(params); - } - - /// Creates a new empty [MacOSWebMessageListener] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebMessageListener] in `flutter_inappwebview` instead. - @override - MacOSWebMessageListener createPlatformWebMessageListenerStatic() { - return MacOSWebMessageListener.static(); - } - - /// Creates a new [MacOSJavaScriptReplyProxy]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [JavaScriptReplyProxy] in `flutter_inappwebview` instead. - @override - MacOSJavaScriptReplyProxy createPlatformJavaScriptReplyProxy( - PlatformJavaScriptReplyProxyCreationParams params, - ) { - return MacOSJavaScriptReplyProxy(params); - } - - /// Creates a new [MacOSWebMessagePort]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebMessagePort] in `flutter_inappwebview` instead. - @override - MacOSWebMessagePort createPlatformWebMessagePort( - PlatformWebMessagePortCreationParams params, - ) { - return MacOSWebMessagePort(params); - } - - /// Creates a new [MacOSWebStorage]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebStorage] in `flutter_inappwebview` instead. - @override - MacOSWebStorage createPlatformWebStorage( - PlatformWebStorageCreationParams params, - ) { - return MacOSWebStorage(params); - } - - /// Creates a new empty [MacOSWebStorage] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebStorage] in `flutter_inappwebview` instead. - @override - MacOSWebStorage createPlatformWebStorageStatic() { - return MacOSWebStorage( - MacOSWebStorageCreationParams( - localStorage: createPlatformLocalStorageStatic(), - sessionStorage: createPlatformSessionStorageStatic(), - ), - ); - } - - /// Creates a new [MacOSLocalStorage]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [LocalStorage] in `flutter_inappwebview` instead. - @override - MacOSLocalStorage createPlatformLocalStorage( - PlatformLocalStorageCreationParams params, - ) { - return MacOSLocalStorage(params); - } - - /// Creates a new empty [MacOSLocalStorage] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [LocalStorage] in `flutter_inappwebview` instead. - @override - MacOSLocalStorage createPlatformLocalStorageStatic() { - return MacOSLocalStorage.defaultStorage(controller: null); - } - - /// Creates a new [MacOSSessionStorage]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [SessionStorage] in `flutter_inappwebview` instead. - @override - MacOSSessionStorage createPlatformSessionStorage( - PlatformSessionStorageCreationParams params, - ) { - return MacOSSessionStorage(params); - } - - /// Creates a new empty [MacOSSessionStorage] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [SessionStorage] in `flutter_inappwebview` instead. - @override - MacOSSessionStorage createPlatformSessionStorageStatic() { - return MacOSSessionStorage.defaultStorage(controller: null); - } - - /// Creates a new [MacOSHeadlessInAppWebView]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [HeadlessInAppWebView] in `flutter_inappwebview` instead. - @override - MacOSHeadlessInAppWebView createPlatformHeadlessInAppWebView( - PlatformHeadlessInAppWebViewCreationParams params, - ) { - return MacOSHeadlessInAppWebView(params); - } - - /// Creates a new empty [MacOSHeadlessInAppWebView] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [HeadlessInAppWebView] in `flutter_inappwebview` instead. - @override - MacOSHeadlessInAppWebView createPlatformHeadlessInAppWebViewStatic() { - return MacOSHeadlessInAppWebView.static(); - } - - /// Creates a new [MacOSHttpAuthCredentialDatabase]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [HttpAuthCredentialDatabase] in `flutter_inappwebview` instead. - @override - MacOSHttpAuthCredentialDatabase createPlatformHttpAuthCredentialDatabase( - PlatformHttpAuthCredentialDatabaseCreationParams params, - ) { - return MacOSHttpAuthCredentialDatabase(params); - } - - /// Creates a new empty [MacOSHttpAuthCredentialDatabase] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [HttpAuthCredentialDatabase] in `flutter_inappwebview` instead. - @override - MacOSHttpAuthCredentialDatabase - createPlatformHttpAuthCredentialDatabaseStatic() { - return MacOSHttpAuthCredentialDatabase.static(); - } - - /// Creates a new [MacOSInAppBrowser]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppBrowser] in `flutter_inappwebview` instead. - @override - MacOSInAppBrowser createPlatformInAppBrowser( - PlatformInAppBrowserCreationParams params, - ) { - return MacOSInAppBrowser(params); - } - - /// Creates a new empty [MacOSInAppBrowser] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppBrowser] in `flutter_inappwebview` instead. - @override - MacOSInAppBrowser createPlatformInAppBrowserStatic() { - return MacOSInAppBrowser.static(); - } - - /// Creates a new empty [MacOSWebStorageManager] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebStorageManager] in `flutter_inappwebview` instead. - @override - MacOSWebStorageManager createPlatformWebStorageManager( - PlatformWebStorageManagerCreationParams params, - ) { - return MacOSWebStorageManager(params); - } - - /// Creates a new empty [MacOSWebStorageManager] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebStorageManager] in `flutter_inappwebview` instead. - @override - MacOSWebStorageManager createPlatformWebStorageManagerStatic() { - return MacOSWebStorageManager.static(); - } - - /// Creates a new [MacOSWebAuthenticationSession]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebAuthenticationSession] in `flutter_inappwebview` instead. - @override - MacOSWebAuthenticationSession createPlatformWebAuthenticationSession( - PlatformWebAuthenticationSessionCreationParams params, - ) { - return MacOSWebAuthenticationSession(params); - } - - /// Creates a new empty [MacOSWebAuthenticationSession] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebAuthenticationSession] in `flutter_inappwebview` instead. - @override - MacOSWebAuthenticationSession createPlatformWebAuthenticationSessionStatic() { - return MacOSWebAuthenticationSession.static(); - } - - /// Creates a new [MacOSProxyController]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ProxyController] in `flutter_inappwebview` instead. - @override - PlatformProxyController createPlatformProxyController( - PlatformProxyControllerCreationParams params, - ) { - return MacOSProxyController(params); - } - - /// Creates a new empty [MacOSProxyController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ProxyController] in `flutter_inappwebview` instead. - @override - MacOSProxyController createPlatformProxyControllerStatic() { - return MacOSProxyController.static(); - } - - // ************************************************************************ // - // Create static instances of unsupported classes to be able to call // - // isClassSupported, isMethodSupported, isPropertySupported, etc. // - // static methods without throwing a missing platform implementation // - // exception. // - // ************************************************************************ // - - /// Creates a new empty [PlatformWebViewEnvironment] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebViewEnvironment] in `flutter_inappwebview` instead. - @override - PlatformWebViewEnvironment createPlatformWebViewEnvironmentStatic() { - return _PlatformWebViewEnvironment.static(); - } - - /// Creates a new empty [PlatformChromeSafariBrowser] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ChromeSafariBrowser] in `flutter_inappwebview` instead. - PlatformChromeSafariBrowser createPlatformChromeSafariBrowserStatic() { - return _PlatformChromeSafariBrowser.static(); - } - - /// Creates a new empty [PlatformProcessGlobalConfig] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ProcessGlobalConfig] in `flutter_inappwebview` instead. - @override - PlatformProcessGlobalConfig createPlatformProcessGlobalConfigStatic() { - return _PlatformProcessGlobalConfig.static(); - } - - /// Creates a new empty [PlatformServiceWorkerController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ServiceWorkerController] in `flutter_inappwebview` instead. - @override - PlatformServiceWorkerController - createPlatformServiceWorkerControllerStatic() { - return _PlatformServiceWorkerController.static(); - } - - /// Creates a new empty [PlatformTracingController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [TracingController] in `flutter_inappwebview` instead. - @override - PlatformTracingController createPlatformTracingControllerStatic() { - return _PlatformTracingController.static(); - } - - /// Creates a new empty [PlatformWebNotificationController] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebNotificationController] in `flutter_inappwebview` instead. - @override - PlatformWebNotificationController - createPlatformWebNotificationControllerStatic() { - return _PlatformWebNotificationController.static(); - } - - /// Creates a new empty [PlatformAssetsPathHandler] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [AssetsPathHandler] in `flutter_inappwebview` instead. - @override - PlatformAssetsPathHandler createPlatformAssetsPathHandlerStatic() { - return _PlatformAssetsPathHandler.static(); - } - - /// Creates a new empty [PlatformResourcesPathHandler] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [ResourcesPathHandler] in `flutter_inappwebview` instead. - @override - PlatformResourcesPathHandler createPlatformResourcesPathHandlerStatic() { - return _PlatformResourcesPathHandler.static(); - } - - /// Creates a new empty [PlatformInternalStoragePathHandler] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InternalStoragePathHandler] in `flutter_inappwebview` instead. - @override - PlatformInternalStoragePathHandler - createPlatformInternalStoragePathHandlerStatic() { - return _PlatformInternalStoragePathHandler.static(); - } - - /// Creates a new empty [PlatformCustomPathHandler] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [CustomPathHandler] in `flutter_inappwebview` instead. - @override - PlatformCustomPathHandler createPlatformCustomPathHandlerStatic() { - return _PlatformCustomPathHandler.static(); - } - - /// Creates a new [DefaultInAppLocalhostServer]. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppLocalhostServer] in `flutter_inappwebview` instead. - @override - DefaultInAppLocalhostServer createPlatformInAppLocalhostServer( - PlatformInAppLocalhostServerCreationParams params, - ) { - return DefaultInAppLocalhostServer(params); - } - - /// Creates a new empty [DefaultInAppLocalhostServer] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [InAppLocalhostServer] in `flutter_inappwebview` instead. - @override - DefaultInAppLocalhostServer createPlatformInAppLocalhostServerStatic() { - return DefaultInAppLocalhostServer.static(); - } - - /// Creates a new empty [PlatformWebViewFeature] to access static methods. - /// - /// This function should only be called by the app-facing package. - /// Look at using [WebViewFeature] in `flutter_inappwebview` instead - @override - PlatformWebViewFeature createPlatformWebViewFeatureStatic() { - return _PlatformWebViewFeature.static(); - } -} - -class _PlatformChromeSafariBrowser extends PlatformChromeSafariBrowser { - _PlatformChromeSafariBrowser(PlatformChromeSafariBrowserCreationParams params) - : super.implementation(params); - static final _PlatformChromeSafariBrowser _staticValue = - _PlatformChromeSafariBrowser( - const PlatformChromeSafariBrowserCreationParams(), - ); - - factory _PlatformChromeSafariBrowser.static() => _staticValue; -} - -class _PlatformProcessGlobalConfig extends PlatformProcessGlobalConfig { - _PlatformProcessGlobalConfig(PlatformProcessGlobalConfigCreationParams params) - : super.implementation(params); - static final _PlatformProcessGlobalConfig _staticValue = - _PlatformProcessGlobalConfig( - const PlatformProcessGlobalConfigCreationParams(), - ); - - factory _PlatformProcessGlobalConfig.static() => _staticValue; -} - -class _PlatformServiceWorkerController extends PlatformServiceWorkerController { - _PlatformServiceWorkerController( - PlatformServiceWorkerControllerCreationParams params, - ) : super.implementation(params); - static final _PlatformServiceWorkerController _staticValue = - _PlatformServiceWorkerController( - const PlatformServiceWorkerControllerCreationParams(), - ); - - factory _PlatformServiceWorkerController.static() => _staticValue; - - @override - ServiceWorkerClient? get serviceWorkerClient => throw UnimplementedError(); -} - -class _PlatformTracingController extends PlatformTracingController { - _PlatformTracingController(PlatformTracingControllerCreationParams params) - : super.implementation(params); - static final _PlatformTracingController _staticValue = - _PlatformTracingController( - const PlatformTracingControllerCreationParams(), - ); - - factory _PlatformTracingController.static() => _staticValue; -} - -class _PlatformPullToRefreshController extends PlatformPullToRefreshController { - _PlatformPullToRefreshController( - PlatformPullToRefreshControllerCreationParams params, - ) : super.implementation(params); - - static final _PlatformPullToRefreshController _staticValue = - _PlatformPullToRefreshController( - PlatformPullToRefreshControllerCreationParams(), - ); - - factory _PlatformPullToRefreshController.static() => _staticValue; -} - -class _PlatformWebViewEnvironment extends PlatformWebViewEnvironment { - _PlatformWebViewEnvironment(PlatformWebViewEnvironmentCreationParams params) - : super.implementation(params); - static final _PlatformWebViewEnvironment _staticValue = - _PlatformWebViewEnvironment( - const PlatformWebViewEnvironmentCreationParams(), - ); - - factory _PlatformWebViewEnvironment.static() => _staticValue; -} - -class _PlatformWebNotificationController - extends PlatformWebNotificationController { - _PlatformWebNotificationController( - PlatformWebNotificationControllerCreationParams params, - ) : super.implementation(params); - - static final _PlatformWebNotificationController _staticValue = - _PlatformWebNotificationController( - PlatformWebNotificationControllerCreationParams( - id: '', - notification: WebNotification(), - ), - ); - - factory _PlatformWebNotificationController.static() => _staticValue; -} - -class _PlatformWebViewFeature extends PlatformWebViewFeature { - _PlatformWebViewFeature(PlatformWebViewFeatureCreationParams params) - : super.implementation(params); - - static final _PlatformWebViewFeature _staticValue = _PlatformWebViewFeature( - PlatformWebViewFeatureCreationParams(), - ); - factory _PlatformWebViewFeature.static() => _staticValue; -} - -class _PlatformAssetsPathHandler extends PlatformAssetsPathHandler { - _PlatformAssetsPathHandler(PlatformAssetsPathHandlerCreationParams params) - : super.implementation(params); - - static final _PlatformAssetsPathHandler _staticValue = - _PlatformAssetsPathHandler( - PlatformAssetsPathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - ), - ); - - factory _PlatformAssetsPathHandler.static() => _staticValue; - - @override - PlatformPathHandlerEvents? eventHandler; - - @override - Map toMap({EnumMethod? enumMethod}) => { - "path": path, - "type": type, - }; - - @override - Map toJson() => toMap(); -} - -class _PlatformResourcesPathHandler extends PlatformResourcesPathHandler { - _PlatformResourcesPathHandler( - PlatformResourcesPathHandlerCreationParams params, - ) : super.implementation(params); - - static final _PlatformResourcesPathHandler _staticValue = - _PlatformResourcesPathHandler( - PlatformResourcesPathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - ), - ); - - factory _PlatformResourcesPathHandler.static() => _staticValue; - - @override - PlatformPathHandlerEvents? eventHandler; - - @override - Map toMap({EnumMethod? enumMethod}) => { - "path": path, - "type": type, - }; - - @override - Map toJson() => toMap(); -} - -class _PlatformInternalStoragePathHandler - extends PlatformInternalStoragePathHandler { - _PlatformInternalStoragePathHandler( - PlatformInternalStoragePathHandlerCreationParams params, - ) : super.implementation(params); - - static final _PlatformInternalStoragePathHandler _staticValue = - _PlatformInternalStoragePathHandler( - PlatformInternalStoragePathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - directory: '', - ), - ); - - factory _PlatformInternalStoragePathHandler.static() => _staticValue; - - @override - PlatformPathHandlerEvents? eventHandler; - - @override - Map toMap({EnumMethod? enumMethod}) => { - "path": path, - "type": type, - }; - - @override - Map toJson() => toMap(); -} - -class _PlatformCustomPathHandler extends PlatformCustomPathHandler { - _PlatformCustomPathHandler(PlatformCustomPathHandlerCreationParams params) - : super.implementation(params); - - static final _PlatformCustomPathHandler _staticValue = - _PlatformCustomPathHandler( - PlatformCustomPathHandlerCreationParams( - PlatformPathHandlerCreationParams(path: ''), - ), - ); - - factory _PlatformCustomPathHandler.static() => _staticValue; - - @override - PlatformPathHandlerEvents? eventHandler; - - @override - Map toMap({EnumMethod? enumMethod}) => { - "path": path, - "type": type, - }; - - @override - Map toJson() => toMap(); -} diff --git a/flutter_inappwebview_macos/lib/src/main.dart b/flutter_inappwebview_macos/lib/src/main.dart deleted file mode 100644 index e58414ae0d..0000000000 --- a/flutter_inappwebview_macos/lib/src/main.dart +++ /dev/null @@ -1,11 +0,0 @@ -export 'inappwebview_platform.dart'; -export 'in_app_webview/main.dart'; -export 'in_app_browser/main.dart'; -export 'web_storage/main.dart'; -export 'cookie_manager.dart' hide InternalCookieManager; -export 'http_auth_credentials_database.dart' - hide InternalHttpAuthCredentialDatabase; -export 'web_message/main.dart'; -export 'print_job/main.dart'; -export 'find_interaction/main.dart'; -export 'web_authentication_session/main.dart'; diff --git a/flutter_inappwebview_macos/lib/src/platform_util.dart b/flutter_inappwebview_macos/lib/src/platform_util.dart deleted file mode 100644 index e52ccbd8cc..0000000000 --- a/flutter_inappwebview_macos/lib/src/platform_util.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'package:flutter/services.dart'; - -///Platform native utilities -class PlatformUtil { - static PlatformUtil? _instance; - static const MethodChannel _channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_platformutil', - ); - - PlatformUtil._(); - - ///Get [PlatformUtil] instance. - static PlatformUtil instance() { - return (_instance != null) ? _instance! : _init(); - } - - static PlatformUtil _init() { - _channel.setMethodCallHandler((call) async { - try { - return await _handleMethod(call); - } on Error catch (e) { - print(e); - print(e.stackTrace); - } - }); - _instance = PlatformUtil._(); - return _instance!; - } - - static Future _handleMethod(MethodCall call) async {} - - String? _cachedSystemVersion; - - ///Get current platform system version. - Future getSystemVersion() async { - if (_cachedSystemVersion != null) { - return _cachedSystemVersion!; - } - Map args = {}; - _cachedSystemVersion = await _channel.invokeMethod( - 'getSystemVersion', - args, - ); - return _cachedSystemVersion!; - } - - ///Format date. - Future formatDate({ - required DateTime date, - required String format, - String locale = "en_US", - String timezone = "UTC", - }) async { - Map args = {}; - args.putIfAbsent('date', () => date.millisecondsSinceEpoch); - args.putIfAbsent('format', () => format); - args.putIfAbsent('locale', () => locale); - args.putIfAbsent('timezone', () => timezone); - return await _channel.invokeMethod('formatDate', args); - } - - ///Get cookie expiration date used by Web platform. - Future getWebCookieExpirationDate({required DateTime date}) async { - Map args = {}; - args.putIfAbsent('date', () => date.millisecondsSinceEpoch); - return await _channel.invokeMethod('getWebCookieExpirationDate', args); - } -} diff --git a/flutter_inappwebview_macos/lib/src/print_job/main.dart b/flutter_inappwebview_macos/lib/src/print_job/main.dart deleted file mode 100644 index 4e70ad9405..0000000000 --- a/flutter_inappwebview_macos/lib/src/print_job/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'print_job_controller.dart'; diff --git a/flutter_inappwebview_macos/lib/src/print_job/print_job_controller.dart b/flutter_inappwebview_macos/lib/src/print_job/print_job_controller.dart deleted file mode 100644 index b75be2eda9..0000000000 --- a/flutter_inappwebview_macos/lib/src/print_job/print_job_controller.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [MacOSPrintJobController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformPrintJobControllerCreationParams] for -/// more information. -@immutable -class MacOSPrintJobControllerCreationParams - extends PlatformPrintJobControllerCreationParams { - /// Creates a new [MacOSPrintJobControllerCreationParams] instance. - const MacOSPrintJobControllerCreationParams({required super.id}); - - /// Creates a [MacOSPrintJobControllerCreationParams] instance based on [PlatformPrintJobControllerCreationParams]. - factory MacOSPrintJobControllerCreationParams.fromPlatformPrintJobControllerCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformPrintJobControllerCreationParams params, - ) { - return MacOSPrintJobControllerCreationParams(id: params.id); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformPrintJobController} -class MacOSPrintJobController extends PlatformPrintJobController - with ChannelController { - /// Constructs a [MacOSPrintJobController]. - MacOSPrintJobController(PlatformPrintJobControllerCreationParams params) - : super.implementation( - params is MacOSPrintJobControllerCreationParams - ? params - : MacOSPrintJobControllerCreationParams.fromPlatformPrintJobControllerCreationParams( - params, - ), - ) { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_printjobcontroller_${params.id}', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - static final MacOSPrintJobController _staticValue = MacOSPrintJobController( - MacOSPrintJobControllerCreationParams(id: ''), - ); - - /// Provide static access. - factory MacOSPrintJobController.static() { - return _staticValue; - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onComplete": - bool completed = call.arguments["completed"]; - String? error = call.arguments["error"]; - if (onComplete != null) { - onComplete!(completed, error); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - } - - @override - Future getInfo() async { - Map args = {}; - Map? infoMap = (await channel?.invokeMethod( - 'getInfo', - args, - ))?.cast(); - return PrintJobInfo.fromMap(infoMap); - } - - @override - Future dispose() async { - Map args = {}; - await channel?.invokeMethod('dispose', args); - disposeChannel(); - } -} diff --git a/flutter_inappwebview_macos/lib/src/proxy_controller.dart b/flutter_inappwebview_macos/lib/src/proxy_controller.dart deleted file mode 100644 index 8f508ee9e9..0000000000 --- a/flutter_inappwebview_macos/lib/src/proxy_controller.dart +++ /dev/null @@ -1,98 +0,0 @@ -import 'dart:async'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [MacOSProxyController]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformProxyControllerCreationParams] for -/// more information. -@immutable -class MacOSProxyControllerCreationParams - extends PlatformProxyControllerCreationParams { - /// Creates a new [MacOSProxyControllerCreationParams] instance. - const MacOSProxyControllerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformProxyControllerCreationParams params, - ) : super(); - - /// Creates a [MacOSProxyControllerCreationParams] instance based on [PlatformProxyControllerCreationParams]. - factory MacOSProxyControllerCreationParams.fromPlatformProxyControllerCreationParams( - PlatformProxyControllerCreationParams params, - ) { - return MacOSProxyControllerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformProxyController} -class MacOSProxyController extends PlatformProxyController - with ChannelController { - /// Creates a new [MacOSProxyController]. - MacOSProxyController(PlatformProxyControllerCreationParams params) - : super.implementation( - params is MacOSProxyControllerCreationParams - ? params - : MacOSProxyControllerCreationParams.fromPlatformProxyControllerCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_proxycontroller', - ); - handler = handleMethod; - initMethodCallHandler(); - } - - static MacOSProxyController? _instance; - - ///Gets the [MacOSProxyController] shared instance. - static MacOSProxyController instance() { - return (_instance != null) ? _instance! : _init(); - } - - static MacOSProxyController _init() { - _instance = MacOSProxyController( - MacOSProxyControllerCreationParams( - const PlatformProxyControllerCreationParams(), - ), - ); - return _instance!; - } - - static final MacOSProxyController _staticValue = MacOSProxyController( - MacOSProxyControllerCreationParams( - const PlatformProxyControllerCreationParams(), - ), - ); - - /// Provide static access. - factory MacOSProxyController.static() { - return _staticValue; - } - - Future _handleMethod(MethodCall call) async {} - - @override - Future setProxyOverride({required ProxySettings settings}) async { - Map args = {}; - args.putIfAbsent("settings", () => settings.toMap()); - await channel?.invokeMethod('setProxyOverride', args); - } - - @override - Future clearProxyOverride() async { - Map args = {}; - await channel?.invokeMethod('clearProxyOverride', args); - } - - @override - void dispose() { - // empty - } -} - -extension InternalProxyController on MacOSProxyController { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_macos/lib/src/web_authentication_session/main.dart b/flutter_inappwebview_macos/lib/src/web_authentication_session/main.dart deleted file mode 100644 index 37ca0c240c..0000000000 --- a/flutter_inappwebview_macos/lib/src/web_authentication_session/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'web_authenticate_session.dart'; diff --git a/flutter_inappwebview_macos/lib/src/web_authentication_session/web_authenticate_session.dart b/flutter_inappwebview_macos/lib/src/web_authentication_session/web_authenticate_session.dart deleted file mode 100755 index 19c669b09b..0000000000 --- a/flutter_inappwebview_macos/lib/src/web_authentication_session/web_authenticate_session.dart +++ /dev/null @@ -1,175 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [MacOSWebAuthenticationSession]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebAuthenticationSessionCreationParams] for -/// more information. -class MacOSWebAuthenticationSessionCreationParams - extends PlatformWebAuthenticationSessionCreationParams { - /// Creates a new [MacOSWebAuthenticationSessionCreationParams] instance. - const MacOSWebAuthenticationSessionCreationParams(); - - /// Creates a [MacOSWebAuthenticationSessionCreationParams] instance based on [PlatformWebAuthenticationSessionCreationParams]. - factory MacOSWebAuthenticationSessionCreationParams.fromPlatformWebAuthenticationSessionCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebAuthenticationSessionCreationParams params, - ) { - return MacOSWebAuthenticationSessionCreationParams(); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession} -class MacOSWebAuthenticationSession extends PlatformWebAuthenticationSession - with ChannelController { - /// Constructs a [MacOSWebAuthenticationSession]. - MacOSWebAuthenticationSession( - PlatformWebAuthenticationSessionCreationParams params, - ) : super.implementation( - params is MacOSWebAuthenticationSessionCreationParams - ? params - : MacOSWebAuthenticationSessionCreationParams.fromPlatformWebAuthenticationSessionCreationParams( - params, - ), - ); - - static final MacOSWebAuthenticationSession _staticValue = - MacOSWebAuthenticationSession( - MacOSWebAuthenticationSessionCreationParams(), - ); - - /// Provide static access. - factory MacOSWebAuthenticationSession.static() { - return _staticValue; - } - - @override - final String id = IdGenerator.generate(); - - @override - late final WebUri url; - - @override - late final String? callbackURLScheme; - - @override - late final WebAuthenticationSessionSettings? initialSettings; - - @override - late final WebAuthenticationSessionCompletionHandler onComplete; - - static const MethodChannel _staticChannel = const MethodChannel( - 'com.pichillilorenzo/flutter_webauthenticationsession', - ); - - @override - Future create({ - required WebUri url, - String? callbackURLScheme, - WebAuthenticationSessionCompletionHandler onComplete, - WebAuthenticationSessionSettings? initialSettings, - }) async { - var session = MacOSWebAuthenticationSession._create( - url: url, - callbackURLScheme: callbackURLScheme, - onComplete: onComplete, - initialSettings: initialSettings, - ); - initialSettings = - session.initialSettings ?? WebAuthenticationSessionSettings(); - Map args = {}; - args.putIfAbsent("id", () => session.id); - args.putIfAbsent("url", () => session.url.toString()); - args.putIfAbsent("callbackURLScheme", () => session.callbackURLScheme); - args.putIfAbsent("initialSettings", () => initialSettings?.toMap()); - await _staticChannel.invokeMethod('create', args); - return session; - } - - MacOSWebAuthenticationSession._create({ - required this.url, - this.callbackURLScheme, - this.onComplete, - WebAuthenticationSessionSettings? initialSettings, - }) : super.implementation(MacOSWebAuthenticationSessionCreationParams()) { - assert(url.toString().isNotEmpty); - assert( - ['http', 'https'].contains(url.scheme), - 'The specified URL has an unsupported scheme. Only HTTP and HTTPS URLs are supported on iOS.', - ); - - this.initialSettings = - initialSettings ?? WebAuthenticationSessionSettings(); - channel = MethodChannel( - 'com.pichillilorenzo/flutter_webauthenticationsession_$id', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - _debugLog(String method, dynamic args) { - debugLog( - className: this.runtimeType.toString(), - debugLoggingSettings: - PlatformWebAuthenticationSession.debugLoggingSettings, - id: id, - method: method, - args: args, - ); - } - - Future _handleMethod(MethodCall call) async { - _debugLog(call.method, call.arguments); - - switch (call.method) { - case "onComplete": - String? url = call.arguments["url"]; - WebUri? uri = url != null ? WebUri(url) : null; - var error = WebAuthenticationSessionError.fromNativeValue( - call.arguments["errorCode"], - ); - if (onComplete != null) { - onComplete!(uri, error); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - } - - @override - Future canStart() async { - Map args = {}; - return await channel?.invokeMethod('canStart', args) ?? false; - } - - @override - Future start() async { - Map args = {}; - return await channel?.invokeMethod('start', args) ?? false; - } - - @override - Future cancel() async { - Map args = {}; - await channel?.invokeMethod("cancel", args); - } - - @override - Future dispose() async { - Map args = {}; - await channel?.invokeMethod("dispose", args); - disposeChannel(); - } - - @override - Future isAvailable() async { - Map args = {}; - return await _staticChannel.invokeMethod("isAvailable", args) ?? - false; - } -} diff --git a/flutter_inappwebview_macos/lib/src/web_message/main.dart b/flutter_inappwebview_macos/lib/src/web_message/main.dart deleted file mode 100644 index d41e30c755..0000000000 --- a/flutter_inappwebview_macos/lib/src/web_message/main.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'web_message_port.dart' hide InternalWebMessagePort; -export 'web_message_channel.dart' hide InternalWebMessageChannel; -export 'web_message_listener.dart'; diff --git a/flutter_inappwebview_macos/lib/src/web_message/web_message_channel.dart b/flutter_inappwebview_macos/lib/src/web_message/web_message_channel.dart deleted file mode 100644 index abcf106a12..0000000000 --- a/flutter_inappwebview_macos/lib/src/web_message/web_message_channel.dart +++ /dev/null @@ -1,130 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import 'web_message_port.dart'; - -/// Object specifying creation parameters for creating a [MacOSWebMessageChannel]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebMessageChannelCreationParams] for -/// more information. -@immutable -class MacOSWebMessageChannelCreationParams - extends PlatformWebMessageChannelCreationParams { - /// Creates a new [MacOSWebMessageChannelCreationParams] instance. - const MacOSWebMessageChannelCreationParams({ - required super.id, - required super.port1, - required super.port2, - }); - - /// Creates a [MacOSWebMessageChannelCreationParams] instance based on [PlatformWebMessageChannelCreationParams]. - factory MacOSWebMessageChannelCreationParams.fromPlatformWebMessageChannelCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebMessageChannelCreationParams params, - ) { - return MacOSWebMessageChannelCreationParams( - id: params.id, - port1: params.port1, - port2: params.port2, - ); - } - - @override - String toString() { - return 'MacOSWebMessageChannelCreationParams{id: $id, port1: $port1, port2: $port2}'; - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel} -class MacOSWebMessageChannel extends PlatformWebMessageChannel - with ChannelController { - /// Constructs a [MacOSWebMessageChannel]. - MacOSWebMessageChannel(PlatformWebMessageChannelCreationParams params) - : super.implementation( - params is MacOSWebMessageChannelCreationParams - ? params - : MacOSWebMessageChannelCreationParams.fromPlatformWebMessageChannelCreationParams( - params, - ), - ) { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_web_message_channel_${params.id}', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - static final MacOSWebMessageChannel _staticValue = MacOSWebMessageChannel( - MacOSWebMessageChannelCreationParams( - id: '', - port1: MacOSWebMessagePort(MacOSWebMessagePortCreationParams(index: 0)), - port2: MacOSWebMessagePort(MacOSWebMessagePortCreationParams(index: 1)), - ), - ); - - /// Provide static access. - factory MacOSWebMessageChannel.static() { - return _staticValue; - } - - MacOSWebMessagePort get _macosPort1 => port1 as MacOSWebMessagePort; - - MacOSWebMessagePort get _macosPort2 => port2 as MacOSWebMessagePort; - - static MacOSWebMessageChannel? _fromMap(Map? map) { - if (map == null) { - return null; - } - var webMessageChannel = MacOSWebMessageChannel( - MacOSWebMessageChannelCreationParams( - id: map["id"], - port1: MacOSWebMessagePort(MacOSWebMessagePortCreationParams(index: 0)), - port2: MacOSWebMessagePort(MacOSWebMessagePortCreationParams(index: 1)), - ), - ); - webMessageChannel._macosPort1.webMessageChannel = webMessageChannel; - webMessageChannel._macosPort2.webMessageChannel = webMessageChannel; - return webMessageChannel; - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onMessage": - int index = call.arguments["index"]; - var port = index == 0 ? _macosPort1 : _macosPort2; - if (port.onMessage != null) { - WebMessage? message = call.arguments["message"] != null - ? WebMessage.fromMap( - call.arguments["message"].cast(), - ) - : null; - port.onMessage!(message); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - MacOSWebMessageChannel? fromMap(Map? map) { - return _fromMap(map); - } - - @override - void dispose() { - disposeChannel(); - } - - @override - String toString() { - return 'MacOSWebMessageChannel{id: $id, port1: $port1, port2: $port2}'; - } -} - -extension InternalWebMessageChannel on MacOSWebMessageChannel { - MethodChannel? get internalChannel => channel; -} diff --git a/flutter_inappwebview_macos/lib/src/web_message/web_message_listener.dart b/flutter_inappwebview_macos/lib/src/web_message/web_message_listener.dart deleted file mode 100644 index d3518fdef4..0000000000 --- a/flutter_inappwebview_macos/lib/src/web_message/web_message_listener.dart +++ /dev/null @@ -1,190 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [MacOSWebMessageListener]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebMessageListenerCreationParams] for -/// more information. -@immutable -class MacOSWebMessageListenerCreationParams - extends PlatformWebMessageListenerCreationParams { - /// Creates a new [MacOSWebMessageListenerCreationParams] instance. - const MacOSWebMessageListenerCreationParams({ - required this.allowedOriginRules, - required super.jsObjectName, - super.onPostMessage, - }); - - /// Creates a [MacOSWebMessageListenerCreationParams] instance based on [PlatformWebMessageListenerCreationParams]. - factory MacOSWebMessageListenerCreationParams.fromPlatformWebMessageListenerCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebMessageListenerCreationParams params, - ) { - return MacOSWebMessageListenerCreationParams( - allowedOriginRules: params.allowedOriginRules ?? Set.from(["*"]), - jsObjectName: params.jsObjectName, - onPostMessage: params.onPostMessage, - ); - } - - @override - final Set allowedOriginRules; - - @override - String toString() { - return 'MacOSWebMessageListenerCreationParams{jsObjectName: $jsObjectName, allowedOriginRules: $allowedOriginRules, onPostMessage: $onPostMessage}'; - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener} -class MacOSWebMessageListener extends PlatformWebMessageListener - with ChannelController { - /// Constructs a [MacOSWebMessageListener]. - MacOSWebMessageListener(PlatformWebMessageListenerCreationParams params) - : super.implementation( - params is MacOSWebMessageListenerCreationParams - ? params - : MacOSWebMessageListenerCreationParams.fromPlatformWebMessageListenerCreationParams( - params, - ), - ) { - assert( - !this._macosParams.allowedOriginRules.contains(""), - "allowedOriginRules cannot contain empty strings", - ); - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_web_message_listener_${_id}_${params.jsObjectName}', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - static final MacOSWebMessageListener _staticValue = MacOSWebMessageListener( - MacOSWebMessageListenerCreationParams( - jsObjectName: '', - allowedOriginRules: Set.from(["*"]), - ), - ); - - /// Provide static access. - factory MacOSWebMessageListener.static() { - return _staticValue; - } - - ///Message Listener ID used internally. - final String _id = IdGenerator.generate(); - - MacOSJavaScriptReplyProxy? _replyProxy; - - MacOSWebMessageListenerCreationParams get _macosParams => - params as MacOSWebMessageListenerCreationParams; - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onPostMessage": - if (_replyProxy == null) { - _replyProxy = MacOSJavaScriptReplyProxy( - PlatformJavaScriptReplyProxyCreationParams( - webMessageListener: this, - ), - ); - } - if (onPostMessage != null) { - WebMessage? message = call.arguments["message"] != null - ? WebMessage.fromMap( - call.arguments["message"].cast(), - ) - : null; - WebUri? sourceOrigin = call.arguments["sourceOrigin"] != null - ? WebUri(call.arguments["sourceOrigin"]) - : null; - bool isMainFrame = call.arguments["isMainFrame"]; - onPostMessage!(message, sourceOrigin, isMainFrame, _replyProxy!); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - void dispose() { - disposeChannel(); - } - - @override - Map toMap() { - return { - "id": _id, - "jsObjectName": params.jsObjectName, - "allowedOriginRules": _macosParams.allowedOriginRules.toList(), - }; - } - - @override - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return 'MacOSWebMessageListener{id: ${_id}, jsObjectName: ${params.jsObjectName}, allowedOriginRules: ${params.allowedOriginRules}, replyProxy: $_replyProxy}'; - } -} - -/// Object specifying creation parameters for creating a [MacOSJavaScriptReplyProxy]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformJavaScriptReplyProxyCreationParams] for -/// more information. -@immutable -class MacOSJavaScriptReplyProxyCreationParams - extends PlatformJavaScriptReplyProxyCreationParams { - /// Creates a new [MacOSJavaScriptReplyProxyCreationParams] instance. - const MacOSJavaScriptReplyProxyCreationParams({ - required super.webMessageListener, - }); - - /// Creates a [MacOSJavaScriptReplyProxyCreationParams] instance based on [PlatformJavaScriptReplyProxyCreationParams]. - factory MacOSJavaScriptReplyProxyCreationParams.fromPlatformJavaScriptReplyProxyCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformJavaScriptReplyProxyCreationParams params, - ) { - return MacOSJavaScriptReplyProxyCreationParams( - webMessageListener: params.webMessageListener, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.JavaScriptReplyProxy} -class MacOSJavaScriptReplyProxy extends PlatformJavaScriptReplyProxy { - /// Constructs a [MacOSWebMessageListener]. - MacOSJavaScriptReplyProxy(PlatformJavaScriptReplyProxyCreationParams params) - : super.implementation( - params is MacOSJavaScriptReplyProxyCreationParams - ? params - : MacOSJavaScriptReplyProxyCreationParams.fromPlatformJavaScriptReplyProxyCreationParams( - params, - ), - ); - - MacOSWebMessageListener get _macosWebMessageListener => - params.webMessageListener as MacOSWebMessageListener; - - @override - Future postMessage(WebMessage message) async { - Map args = {}; - args.putIfAbsent('message', () => message.toMap()); - await _macosWebMessageListener.channel?.invokeMethod('postMessage', args); - } - - @override - String toString() { - return 'MacOSJavaScriptReplyProxy{}'; - } -} diff --git a/flutter_inappwebview_macos/lib/src/web_message/web_message_port.dart b/flutter_inappwebview_macos/lib/src/web_message/web_message_port.dart deleted file mode 100644 index 3942193c13..0000000000 --- a/flutter_inappwebview_macos/lib/src/web_message/web_message_port.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import 'web_message_channel.dart'; - -/// Object specifying creation parameters for creating a [MacOSWebMessagePort]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebMessagePortCreationParams] for -/// more information. -@immutable -class MacOSWebMessagePortCreationParams - extends PlatformWebMessagePortCreationParams { - /// Creates a new [MacOSWebMessagePortCreationParams] instance. - const MacOSWebMessagePortCreationParams({required super.index}); - - /// Creates a [MacOSWebMessagePortCreationParams] instance based on [PlatformWebMessagePortCreationParams]. - factory MacOSWebMessagePortCreationParams.fromPlatformWebMessagePortCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebMessagePortCreationParams params, - ) { - return MacOSWebMessagePortCreationParams(index: params.index); - } - - @override - String toString() { - return 'MacOSWebMessagePortCreationParams{index: $index}'; - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessagePort} -class MacOSWebMessagePort extends PlatformWebMessagePort { - WebMessageCallback? _onMessage; - late MacOSWebMessageChannel _webMessageChannel; - - /// Constructs a [MacOSWebMessagePort]. - MacOSWebMessagePort(PlatformWebMessagePortCreationParams params) - : super.implementation( - params is MacOSWebMessagePortCreationParams - ? params - : MacOSWebMessagePortCreationParams.fromPlatformWebMessagePortCreationParams( - params, - ), - ); - - @override - Future setWebMessageCallback(WebMessageCallback? onMessage) async { - Map args = {}; - args.putIfAbsent('index', () => params.index); - await _webMessageChannel.internalChannel?.invokeMethod( - 'setWebMessageCallback', - args, - ); - this._onMessage = onMessage; - } - - @override - Future postMessage(WebMessage message) async { - Map args = {}; - args.putIfAbsent('index', () => params.index); - args.putIfAbsent('message', () => message.toMap()); - await _webMessageChannel.internalChannel?.invokeMethod('postMessage', args); - } - - @override - Future close() async { - Map args = {}; - args.putIfAbsent('index', () => params.index); - await _webMessageChannel.internalChannel?.invokeMethod('close', args); - } - - @override - Map toMap({EnumMethod? enumMethod}) { - return { - "index": params.index, - "webMessageChannelId": this._webMessageChannel.params.id, - }; - } - - @override - Map toJson() { - return toMap(); - } - - @override - String toString() { - return 'MacOSWebMessagePort{index: ${params.index}}'; - } -} - -extension InternalWebMessagePort on MacOSWebMessagePort { - WebMessageCallback? get onMessage => _onMessage; - void set onMessage(WebMessageCallback? value) => _onMessage = value; - - MacOSWebMessageChannel get webMessageChannel => _webMessageChannel; - void set webMessageChannel(MacOSWebMessageChannel value) => - _webMessageChannel = value; -} diff --git a/flutter_inappwebview_macos/lib/src/web_storage/main.dart b/flutter_inappwebview_macos/lib/src/web_storage/main.dart deleted file mode 100644 index dab327ba6d..0000000000 --- a/flutter_inappwebview_macos/lib/src/web_storage/main.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'web_storage.dart'; -export 'web_storage_manager.dart'; diff --git a/flutter_inappwebview_macos/lib/src/web_storage/web_storage.dart b/flutter_inappwebview_macos/lib/src/web_storage/web_storage.dart deleted file mode 100644 index f77882369a..0000000000 --- a/flutter_inappwebview_macos/lib/src/web_storage/web_storage.dart +++ /dev/null @@ -1,306 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import '../in_app_webview/in_app_webview_controller.dart'; - -/// Object specifying creation parameters for creating a [MacOSWebStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebStorageCreationParams] for -/// more information. -class MacOSWebStorageCreationParams extends PlatformWebStorageCreationParams { - /// Creates a new [MacOSWebStorageCreationParams] instance. - MacOSWebStorageCreationParams({ - required super.localStorage, - required super.sessionStorage, - }); - - /// Creates a [MacOSWebStorageCreationParams] instance based on [PlatformWebStorageCreationParams]. - factory MacOSWebStorageCreationParams.fromPlatformWebStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebStorageCreationParams params, - ) { - return MacOSWebStorageCreationParams( - localStorage: params.localStorage, - sessionStorage: params.sessionStorage, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage} -class MacOSWebStorage extends PlatformWebStorage { - /// Constructs a [MacOSWebStorage]. - MacOSWebStorage(PlatformWebStorageCreationParams params) - : super.implementation( - params is MacOSWebStorageCreationParams - ? params - : MacOSWebStorageCreationParams.fromPlatformWebStorageCreationParams( - params, - ), - ); - - @override - PlatformLocalStorage get localStorage => params.localStorage; - - @override - PlatformSessionStorage get sessionStorage => params.sessionStorage; - - @override - void dispose() { - localStorage.dispose(); - sessionStorage.dispose(); - } -} - -/// Object specifying creation parameters for creating a [MacOSStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformStorageCreationParams] for -/// more information. -class MacOSStorageCreationParams extends PlatformStorageCreationParams { - /// Creates a new [MacOSStorageCreationParams] instance. - MacOSStorageCreationParams({ - required super.controller, - required super.webStorageType, - }); - - /// Creates a [MacOSStorageCreationParams] instance based on [PlatformStorageCreationParams]. - factory MacOSStorageCreationParams.fromPlatformStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformStorageCreationParams params, - ) { - return MacOSStorageCreationParams( - controller: params.controller, - webStorageType: params.webStorageType, - ); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformStorage} -abstract mixin class MacOSStorage implements PlatformStorage { - @override - MacOSInAppWebViewController? controller; - - @override - Future length() async { - var result = await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.length; - """, - ); - return result != null ? int.parse(json.decode(result)) : null; - } - - @override - Future setItem({required String key, required dynamic value}) async { - var encodedValue = json.encode(value); - await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.setItem("$key", ${value is String ? encodedValue : "JSON.stringify($encodedValue)"}); - """, - ); - } - - @override - Future getItem({required String key}) async { - var itemValue = await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.getItem("$key"); - """, - ); - - if (itemValue == null) { - return null; - } - - try { - return json.decode(itemValue); - } catch (e) {} - - return itemValue; - } - - @override - Future removeItem({required String key}) async { - await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.removeItem("$key"); - """, - ); - } - - @override - Future> getItems() async { - var webStorageItems = []; - - List>? items = (await controller?.evaluateJavascript( - source: - """ -(function() { - var webStorageItems = []; - for(var i = 0; i < window.$webStorageType.length; i++){ - var key = window.$webStorageType.key(i); - webStorageItems.push( - { - key: key, - value: window.$webStorageType.getItem(key) - } - ); - } - return webStorageItems; -})(); - """, - ))?.cast>(); - - if (items == null) { - return webStorageItems; - } - - for (var item in items) { - webStorageItems.add( - WebStorageItem(key: item["key"], value: item["value"]), - ); - } - - return webStorageItems; - } - - @override - Future clear() async { - await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.clear(); - """, - ); - } - - @override - Future key({required int index}) async { - var result = await controller?.evaluateJavascript( - source: - """ - window.$webStorageType.key($index); - """, - ); - return result != null ? json.decode(result) : null; - } - - @override - void dispose() { - controller = null; - } -} - -/// Object specifying creation parameters for creating a [MacOSLocalStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformLocalStorageCreationParams] for -/// more information. -class MacOSLocalStorageCreationParams - extends PlatformLocalStorageCreationParams { - /// Creates a new [MacOSLocalStorageCreationParams] instance. - MacOSLocalStorageCreationParams(super.params); - - /// Creates a [MacOSLocalStorageCreationParams] instance based on [PlatformLocalStorageCreationParams]. - factory MacOSLocalStorageCreationParams.fromPlatformLocalStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformLocalStorageCreationParams params, - ) { - return MacOSLocalStorageCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformLocalStorage} -class MacOSLocalStorage extends PlatformLocalStorage with MacOSStorage { - /// Constructs a [MacOSLocalStorage]. - MacOSLocalStorage(PlatformLocalStorageCreationParams params) - : super.implementation( - params is MacOSLocalStorageCreationParams - ? params - : MacOSLocalStorageCreationParams.fromPlatformLocalStorageCreationParams( - params, - ), - ); - - /// Default storage - factory MacOSLocalStorage.defaultStorage({ - required PlatformInAppWebViewController? controller, - }) { - return MacOSLocalStorage( - MacOSLocalStorageCreationParams( - PlatformLocalStorageCreationParams( - PlatformStorageCreationParams( - controller: controller, - webStorageType: WebStorageType.LOCAL_STORAGE, - ), - ), - ), - ); - } - - @override - MacOSInAppWebViewController? get controller => - params.controller as MacOSInAppWebViewController?; -} - -/// Object specifying creation parameters for creating a [MacOSSessionStorage]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformSessionStorageCreationParams] for -/// more information. -class MacOSSessionStorageCreationParams - extends PlatformSessionStorageCreationParams { - /// Creates a new [MacOSSessionStorageCreationParams] instance. - MacOSSessionStorageCreationParams(super.params); - - /// Creates a [MacOSSessionStorageCreationParams] instance based on [PlatformSessionStorageCreationParams]. - factory MacOSSessionStorageCreationParams.fromPlatformSessionStorageCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformSessionStorageCreationParams params, - ) { - return MacOSSessionStorageCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformSessionStorage} -class MacOSSessionStorage extends PlatformSessionStorage with MacOSStorage { - /// Constructs a [MacOSSessionStorage]. - MacOSSessionStorage(PlatformSessionStorageCreationParams params) - : super.implementation( - params is MacOSSessionStorageCreationParams - ? params - : MacOSSessionStorageCreationParams.fromPlatformSessionStorageCreationParams( - params, - ), - ); - - /// Default storage - factory MacOSSessionStorage.defaultStorage({ - required PlatformInAppWebViewController? controller, - }) { - return MacOSSessionStorage( - MacOSSessionStorageCreationParams( - PlatformSessionStorageCreationParams( - PlatformStorageCreationParams( - controller: controller, - webStorageType: WebStorageType.SESSION_STORAGE, - ), - ), - ), - ); - } - - @override - MacOSInAppWebViewController? get controller => - params.controller as MacOSInAppWebViewController?; -} diff --git a/flutter_inappwebview_macos/lib/src/web_storage/web_storage_manager.dart b/flutter_inappwebview_macos/lib/src/web_storage/web_storage_manager.dart deleted file mode 100755 index d7457ef986..0000000000 --- a/flutter_inappwebview_macos/lib/src/web_storage/web_storage_manager.dart +++ /dev/null @@ -1,164 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [MacOSWebStorageManager]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebStorageManagerCreationParams] for -/// more information. -@immutable -class MacOSWebStorageManagerCreationParams - extends PlatformWebStorageManagerCreationParams { - /// Creates a new [MacOSWebStorageManagerCreationParams] instance. - const MacOSWebStorageManagerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformWebStorageManagerCreationParams params, - ) : super(); - - /// Creates a [MacOSWebStorageManagerCreationParams] instance based on [PlatformWebStorageManagerCreationParams]. - factory MacOSWebStorageManagerCreationParams.fromPlatformWebStorageManagerCreationParams( - PlatformWebStorageManagerCreationParams params, - ) { - return MacOSWebStorageManagerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager} -class MacOSWebStorageManager extends PlatformWebStorageManager - with ChannelController { - /// Creates a new [MacOSWebStorageManager]. - MacOSWebStorageManager(PlatformWebStorageManagerCreationParams params) - : super.implementation( - params is MacOSWebStorageManagerCreationParams - ? params - : MacOSWebStorageManagerCreationParams.fromPlatformWebStorageManagerCreationParams( - params, - ), - ) { - channel = const MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_webstoragemanager', - ); - handler = _handleMethod; - initMethodCallHandler(); - } - - static MacOSWebStorageManager? _instance; - - ///Gets the WebStorage manager shared instance. - static MacOSWebStorageManager instance() { - return (_instance != null) ? _instance! : _init(); - } - - static MacOSWebStorageManager _init() { - _instance = MacOSWebStorageManager( - MacOSWebStorageManagerCreationParams( - const PlatformWebStorageManagerCreationParams(), - ), - ); - return _instance!; - } - - static MacOSWebStorageManager? _static; - - /// Provide static access. - factory MacOSWebStorageManager.static() { - _static ??= MacOSWebStorageManager( - MacOSWebStorageManagerCreationParams( - const PlatformWebStorageManagerCreationParams(), - ), - ); - return _static!; - } - - Future _handleMethod(MethodCall call) async {} - - @override - Future> fetchDataRecords({ - required Set dataTypes, - }) async { - List recordList = []; - List dataTypesList = []; - for (var dataType in dataTypes) { - if (dataType.isSupported()) { - dataTypesList.add(dataType.toNativeValue()!); - } - } - Map args = {}; - args.putIfAbsent("dataTypes", () => dataTypesList); - List> records = - (await channel?.invokeMethod( - 'fetchDataRecords', - args, - ))?.cast>() ?? - []; - for (var record in records) { - List dataTypesString = record["dataTypes"].cast(); - Set dataTypes = Set(); - for (var dataTypeValue in dataTypesString) { - var dataType = WebsiteDataType.fromNativeValue(dataTypeValue); - if (dataType != null) { - dataTypes.add(dataType); - } - } - recordList.add( - WebsiteDataRecord( - displayName: record["displayName"], - dataTypes: dataTypes, - ), - ); - } - return recordList; - } - - @override - Future removeDataFor({ - required Set dataTypes, - required List dataRecords, - }) async { - List dataTypesList = []; - for (var dataType in dataTypes) { - if (dataType.isSupported()) { - dataTypesList.add(dataType.toNativeValue()!); - } - } - - List> recordList = []; - for (var record in dataRecords) { - recordList.add(record.toMap()); - } - - Map args = {}; - args.putIfAbsent("dataTypes", () => dataTypesList); - args.putIfAbsent("recordList", () => recordList); - await channel?.invokeMethod('removeDataFor', args); - } - - @override - Future removeDataModifiedSince({ - required Set dataTypes, - required DateTime date, - }) async { - List dataTypesList = []; - for (var dataType in dataTypes) { - if (dataType.isSupported()) { - dataTypesList.add(dataType.toNativeValue()!); - } - } - - var timestamp = date.millisecondsSinceEpoch; - - Map args = {}; - args.putIfAbsent("dataTypes", () => dataTypesList); - args.putIfAbsent("timestamp", () => timestamp); - await channel?.invokeMethod('removeDataModifiedSince', args); - } - - @override - void dispose() { - // empty - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos.podspec b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos.podspec deleted file mode 100644 index 0ab1163421..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos.podspec +++ /dev/null @@ -1,32 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint flutter_inappwebview_macos.podspec` to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'flutter_inappwebview_macos' - s.version = '0.0.1' - s.summary = 'A new Flutter plugin project.' - s.description = <<-DESC -A new Flutter plugin project. - DESC - s.homepage = 'http://example.com' - s.license = { :file => '../LICENSE' } - s.author = { 'Your Company' => 'email@example.com' } - - s.source = { :path => '.' } - s.source_files = 'flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/**/*.swift' - s.dependency 'FlutterMacOS' - s.resource_bundles = {'flutter_inappwebview_macos_privacy' => ['flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Resources/PrivacyInfo.xcprivacy']} - - # swift-collections podspec doesn't declare macOS support, so we must use OrderedSet library - # s.dependency 'swift-collections', '~>1.1.1' - s.dependency 'OrderedSet', '~>6.0.3' - - s.platform = :osx, '10.14' - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } - s.xcconfig = { - 'LIBRARY_SEARCH_PATHS' => '$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)/ $(SDKROOT)/usr/lib/swift', - 'LD_RUNPATH_SEARCH_PATHS' => '/usr/lib/swift', - } - s.swift_version = '5.0' -end diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Package.resolved b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Package.resolved deleted file mode 100644 index eb9351a474..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Package.resolved +++ /dev/null @@ -1,14 +0,0 @@ -{ - "pins" : [ - { - "identity" : "swift-collections", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-collections.git", - "state" : { - "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", - "version" : "1.3.0" - } - } - ], - "version" : 2 -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Package.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Package.swift deleted file mode 100644 index d1095c0cd0..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Package.swift +++ /dev/null @@ -1,28 +0,0 @@ -// swift-tools-version: 5.9 -// The swift-tools-version declares the minimum version of Swift required to build this package. - -import PackageDescription - -let package = Package( - name: "flutter_inappwebview_macos", - platforms: [ - .macOS("10.14"), - ], - products: [ - .library(name: "flutter-inappwebview-macos", targets: ["flutter_inappwebview_macos"]) - ], - dependencies: [ - .package(url: "https://github.com/apple/swift-collections.git", from: "1.2.1") - ], - targets: [ - .target( - name: "flutter_inappwebview_macos", - dependencies: [ - .product(name: "Collections", package: "swift-collections") - ], - resources: [ - .process("Resources") - ] - ) - ] -) diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/CredentialDatabase.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/CredentialDatabase.swift deleted file mode 100755 index 4a7a45df7f..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/CredentialDatabase.swift +++ /dev/null @@ -1,172 +0,0 @@ -// -// CredentialDatabase.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 29/10/2019. -// - -import Foundation -import FlutterMacOS - -public class CredentialDatabase: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_credential_database" - var plugin: InAppWebViewFlutterPlugin? - static var credentialStore = URLCredentialStorage.shared - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: CredentialDatabase.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger)) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - switch call.method { - case "getAllAuthCredentials": - var allCredentials: [[String: Any?]] = [] - - for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { - var crendentials: [[String: Any?]] = [] - for c in credentials { - let credential: [String: Any?] = c.value.toMap() - crendentials.append(credential) - } - if crendentials.count > 0 { - let dict: [String : Any] = [ - "protectionSpace": protectionSpace.toMap(), - "credentials": crendentials - ] - allCredentials.append(dict) - } - } - result(allCredentials) - break - case "getHttpAuthCredentials": - var crendentials: [[String: Any?]] = [] - - let host = arguments!["host"] as! String - let urlProtocol = arguments!["protocol"] as? String - let urlPort = arguments!["port"] as? Int ?? 0 - var realm = arguments!["realm"] as? String; - if let r = realm, r.isEmpty { - realm = nil - } - - for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { - if protectionSpace.host == host && protectionSpace.realm == realm && - protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort { - for c in credentials { - crendentials.append(c.value.toMap()) - } - break - } - } - result(crendentials) - break - case "setHttpAuthCredential": - let host = arguments!["host"] as! String - let urlProtocol = arguments!["protocol"] as? String - let urlPort = arguments!["port"] as? Int ?? 0 - var realm = arguments!["realm"] as? String; - if let r = realm, r.isEmpty { - realm = nil - } - let username = arguments!["username"] as! String - let password = arguments!["password"] as! String - let credential = URLCredential(user: username, password: password, persistence: .permanent) - CredentialDatabase.credentialStore.set(credential, - for: URLProtectionSpace(host: host, port: urlPort, protocol: urlProtocol, - realm: realm, authenticationMethod: NSURLAuthenticationMethodHTTPBasic)) - result(true) - break - case "removeHttpAuthCredential": - let host = arguments!["host"] as! String - let urlProtocol = arguments!["protocol"] as? String - let urlPort = arguments!["port"] as? Int ?? 0 - var realm = arguments!["realm"] as? String; - if let r = realm, r.isEmpty { - realm = nil - } - let username = arguments!["username"] as! String - let password = arguments!["password"] as! String - - var credential: URLCredential? = nil; - var protectionSpaceCredential: URLProtectionSpace? = nil - - for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { - if protectionSpace.host == host && protectionSpace.realm == realm && - protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort { - for c in credentials { - if c.value.user == username, c.value.password == password { - credential = c.value - protectionSpaceCredential = protectionSpace - break - } - } - } - if credential != nil { - break - } - } - - if let c = credential, let protectionSpace = protectionSpaceCredential { - CredentialDatabase.credentialStore.remove(c, for: protectionSpace) - } - - result(true) - break - case "removeHttpAuthCredentials": - let host = arguments!["host"] as! String - let urlProtocol = arguments!["protocol"] as? String - let urlPort = arguments!["port"] as? Int ?? 0 - var realm = arguments!["realm"] as? String; - if let r = realm, r.isEmpty { - realm = nil - } - - var credentialsToRemove: [URLCredential] = []; - var protectionSpaceCredential: URLProtectionSpace? = nil - - for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { - if protectionSpace.host == host && protectionSpace.realm == realm && - protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort { - protectionSpaceCredential = protectionSpace - for c in credentials { - if let _ = c.value.user, let _ = c.value.password { - credentialsToRemove.append(c.value) - } - } - break - } - } - - if let protectionSpace = protectionSpaceCredential { - for credential in credentialsToRemove { - CredentialDatabase.credentialStore.remove(credential, for: protectionSpace) - } - } - - result(true) - break - case "clearAllAuthCredentials": - for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { - for credential in credentials { - CredentialDatabase.credentialStore.remove(credential.value, for: protectionSpace) - } - } - result(true) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public override func dispose() { - super.dispose() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/FindInteraction/FindInteractionChannelDelegate.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/FindInteraction/FindInteractionChannelDelegate.swift deleted file mode 100644 index e471d28673..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/FindInteraction/FindInteractionChannelDelegate.swift +++ /dev/null @@ -1,112 +0,0 @@ -// -// FindInteractionChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/10/22. -// - -import Foundation -import FlutterMacOS - -public class FindInteractionChannelDelegate: ChannelDelegate { - private weak var findInteractionController: FindInteractionController? - - public init(findInteractionController: FindInteractionController, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.findInteractionController = findInteractionController - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "findAll": - if let findInteractionController = findInteractionController { - let find = arguments!["find"] as! String - findInteractionController.findAll(find: find, completionHandler: {(value, error) in - if error != nil { - result(FlutterError(code: "FindInteractionChannelDelegate", message: error?.localizedDescription, details: nil)) - return - } - result(true) - }) - } else { - result(false) - } - break - case "findNext": - if let findInteractionController = findInteractionController { - let forward = arguments!["forward"] as! Bool - findInteractionController.findNext(forward: forward, completionHandler: {(value, error) in - if error != nil { - result(FlutterError(code: "FindInteractionChannelDelegate", message: error?.localizedDescription, details: nil)) - return - } - result(true) - }) - } else { - result(false) - } - break - case "clearMatches": - if let findInteractionController = findInteractionController { - findInteractionController.clearMatches(completionHandler: {(value, error) in - if error != nil { - result(FlutterError(code: "FindInteractionChannelDelegate", message: error?.localizedDescription, details: nil)) - return - } - result(true) - }) - } else { - result(false) - } - break - case "setSearchText": - if let findInteractionController = findInteractionController { - let searchText = arguments!["searchText"] as? String - findInteractionController.searchText = searchText - result(true) - } else { - result(false) - } - break - case "getSearchText": - result(findInteractionController?.searchText) - break - case "getActiveFindSession": - if let findInteractionController = findInteractionController { - result(findInteractionController.activeFindSession?.toMap()) - } else { - result(nil) - } - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func onFindResultReceived(activeMatchOrdinal: Int, numberOfMatches: Int, isDoneCounting: Bool) { - if isDoneCounting, let findInteractionController = findInteractionController { - findInteractionController.activeFindSession = FindSession(resultCount: numberOfMatches, - highlightedResultIndex: activeMatchOrdinal, - searchResultDisplayStyle: 2) // matches UIFindSession.SearchResultDisplayStyle.none - } - - let arguments: [String : Any?] = [ - "activeMatchOrdinal": activeMatchOrdinal, - "numberOfMatches": numberOfMatches, - "isDoneCounting": isDoneCounting - ] - channel?.invokeMethod("onFindResultReceived", arguments: arguments) - } - - public override func dispose() { - super.dispose() - findInteractionController = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/FindInteraction/FindInteractionController.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/FindInteraction/FindInteractionController.swift deleted file mode 100644 index f6e5492a89..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/FindInteraction/FindInteractionController.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// FindInteractionController.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/10/22. -// - -import Foundation -import FlutterMacOS - -public class FindInteractionController: NSObject, Disposable { - - static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_find_interaction_"; - var plugin: InAppWebViewFlutterPlugin? - var webView: InAppWebView? - var channelDelegate: FindInteractionChannelDelegate? - var settings: FindInteractionSettings? - var shouldCallOnRefresh = false - var searchText: String? - var activeFindSession: FindSession? - - public init(plugin: InAppWebViewFlutterPlugin, id: Any, webView: InAppWebView, settings: FindInteractionSettings?) { - super.init() - self.plugin = plugin - self.webView = webView - self.settings = settings - let channel = FlutterMethodChannel(name: FindInteractionController.METHOD_CHANNEL_NAME_PREFIX + String(describing: id), - binaryMessenger: plugin.registrar.messenger) - self.channelDelegate = FindInteractionChannelDelegate(findInteractionController: self, channel: channel) - } - - public func prepare() { -// if let settings = settings { -// -// } - } - - public func findAll(find: String?, completionHandler: ((Any?, Error?) -> Void)?) { - guard let webView else { - if let completionHandler = completionHandler { - completionHandler(nil, nil) - } - return - } - - var find = find - if find == nil { - find = searchText - } else { - // updated searchText - searchText = find - } - - guard let find else { - if let completionHandler = completionHandler { - completionHandler(nil, nil) - } - return - } - - if find != "" { - let startSearch = "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findAllAsync('\(find)');" - webView.evaluateJavaScript(startSearch, completionHandler: completionHandler) - } - } - - public func findNext(forward: Bool, completionHandler: ((Any?, Error?) -> Void)?) { - guard let webView else { - if let completionHandler = completionHandler { - completionHandler(nil, nil) - } - return - } - webView.evaluateJavaScript("window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findNext(\(forward ? "true" : "false"));", completionHandler: completionHandler) - } - - public func clearMatches(completionHandler: ((Any?, Error?) -> Void)?) { - guard let webView else { - if let completionHandler = completionHandler { - completionHandler(nil, nil) - } - return - } - webView.evaluateJavaScript("window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._clearMatches();", completionHandler: completionHandler) - } - - public func dispose() { - channelDelegate?.dispose() - channelDelegate = nil - webView = nil - activeFindSession = nil - plugin = nil - } - - deinit { - debugPrint("FindInteractionControl - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/FindInteraction/FindInteractionSettings.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/FindInteraction/FindInteractionSettings.swift deleted file mode 100644 index 3c4ecb14a2..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/FindInteraction/FindInteractionSettings.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// FindInteractionSettings.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/10/22. -// - -import Foundation - -public class FindInteractionSettings: ISettings { - - override init(){ - super.init() - } - - override func parse(settings: [String: Any?]) -> FindInteractionSettings { - let _ = super.parse(settings: settings) - return self - } - - override func getRealSettings(obj: FindInteractionController?) -> [String: Any?] { - let realSettings: [String: Any?] = toMap() - return realSettings - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/HeadlessInAppWebView/HeadlessInAppWebView.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/HeadlessInAppWebView/HeadlessInAppWebView.swift deleted file mode 100644 index 9f5b9524fa..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/HeadlessInAppWebView/HeadlessInAppWebView.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// HeadlessInAppWebView.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 26/03/21. -// - -import Foundation -import FlutterMacOS - -public class HeadlessInAppWebView: Disposable { - static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_headless_inappwebview_" - var id: String - var channelDelegate: HeadlessWebViewChannelDelegate? - var flutterWebView: FlutterWebViewController? - var plugin: InAppWebViewFlutterPlugin? - - public init(plugin: InAppWebViewFlutterPlugin, id: String, flutterWebView: FlutterWebViewController) { - self.id = id - self.flutterWebView = flutterWebView - self.plugin = plugin - let channel = FlutterMethodChannel(name: HeadlessInAppWebView.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: plugin.registrar.messenger) - self.channelDelegate = HeadlessWebViewChannelDelegate(headlessWebView: self, channel: channel) - } - - public func onWebViewCreated() { - channelDelegate?.onWebViewCreated(); - } - - public func prepare(params: NSDictionary) { - if let view = flutterWebView?.view() { - view.alphaValue = 0.01 - let initialSize = params["initialSize"] as? [String: Any?] - if let size = Size2D.fromMap(map: initialSize) { - setSize(size: size) - } else { - view.frame = CGRect(x: 0.0, y: 0.0, width: NSApplication.shared.mainWindow?.contentView?.bounds.width ?? 0.0, - height: NSApplication.shared.mainWindow?.contentView?.bounds.height ?? 0.0) - } - /// Note: The WKWebView behaves very unreliable when rendering offscreen - /// on a device. This is especially true with JavaScript, which simply - /// won't be executed sometimes. - /// So, add the headless WKWebView to the view hierarchy. - /// This way is also possible to take screenshots. - let wrapperView = NSView() // wrapper view with frame zero - wrapperView.addSubview(view, positioned: .below, relativeTo: nil) - NSApplication.shared.mainWindow?.contentView?.addSubview(wrapperView, positioned: .below, relativeTo: nil) - } - } - - public func setSize(size: Size2D) { - if let view = flutterWebView?.view() { - let width = size.width == -1.0 ? NSApplication.shared.mainWindow?.contentView?.bounds.width ?? 0.0 : CGFloat(size.width) - let height = size.height == -1.0 ? NSApplication.shared.mainWindow?.contentView?.bounds.height ?? 0.0 : CGFloat(size.height) - view.frame = CGRect(x: 0.0, y: 0.0, width: width, height: height) - } - } - - public func getSize() -> Size2D? { - if let view = flutterWebView?.view() { - return Size2D(width: Double(view.frame.width), height: Double(view.frame.height)) - } - return nil - } - - public func disposeAndGetFlutterWebView(withFrame frame: CGRect) -> FlutterWebViewController? { - let newFlutterWebView = flutterWebView - if let view = flutterWebView?.view() { - // restore WebView frame and alpha - view.frame = frame - view.alphaValue = 1.0 - // remove from parent - view.removeFromSuperview() - dispose(disposeWebView: false) - } - return newFlutterWebView - } - - - public func dispose(disposeWebView: Bool) { - channelDelegate?.dispose() - channelDelegate = nil - plugin?.headlessInAppWebViewManager?.webViews[id] = nil - if disposeWebView { - flutterWebView?.dispose(removeFromSuperview: true) - } - flutterWebView = nil - plugin = nil - } - - public func dispose() { - dispose(disposeWebView: true) - } - - deinit { - debugPrint("HeadlessInAppWebView - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift deleted file mode 100644 index 4dcd1b5364..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// HeadlessInAppWebViewManager.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/05/2020. -// - -import Foundation - -import FlutterMacOS -import AppKit -import WebKit -import Foundation -import AVFoundation - -public class HeadlessInAppWebViewManager: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_headless_inappwebview" - var plugin: InAppWebViewFlutterPlugin? - var webViews: [String: HeadlessInAppWebView?] = [:] - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: HeadlessInAppWebViewManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger)) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - let id: String = arguments!["id"] as! String - - switch call.method { - case "run": - let params = arguments!["params"] as! [String: Any?] - run(id: id, params: params) - result(true) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func run(id: String, params: [String: Any?]) { - guard let plugin = plugin else { - return - } - let flutterWebView = FlutterWebViewController(plugin: plugin, - withFrame: CGRect.zero, - viewIdentifier: id, - params: params as NSDictionary) - let headlessInAppWebView = HeadlessInAppWebView(plugin: plugin, id: id, flutterWebView: flutterWebView) - webViews[id] = headlessInAppWebView - - headlessInAppWebView.prepare(params: params as NSDictionary) - headlessInAppWebView.onWebViewCreated() - flutterWebView.makeInitialLoad(params: params as NSDictionary) - } - - public override func dispose() { - super.dispose() - let headlessWebViews = webViews.values - headlessWebViews.forEach { (headlessWebView: HeadlessInAppWebView?) in - headlessWebView?.dispose() - } - webViews.removeAll() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/HeadlessInAppWebView/HeadlessWebViewChannelDelegate.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/HeadlessInAppWebView/HeadlessWebViewChannelDelegate.swift deleted file mode 100644 index 9b4ee63efe..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/HeadlessInAppWebView/HeadlessWebViewChannelDelegate.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// HeadlessWebViewChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 05/05/22. -// - -import Foundation -import FlutterMacOS - -public class HeadlessWebViewChannelDelegate: ChannelDelegate { - private weak var headlessWebView: HeadlessInAppWebView? - - public init(headlessWebView: HeadlessInAppWebView, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.headlessWebView = headlessWebView - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "dispose": - if let headlessWebView = headlessWebView { - headlessWebView.dispose() - result(true) - } else { - result(false) - } - break - case "setSize": - if let headlessWebView = headlessWebView { - let sizeMap = arguments!["size"] as? [String: Any?] - if let size = Size2D.fromMap(map: sizeMap) { - headlessWebView.setSize(size: size) - } - result(true) - } else { - result(false) - } - break - case "getSize": - result(headlessWebView?.getSize()?.toMap()) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func onWebViewCreated() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onWebViewCreated", arguments: arguments) - } - - public override func dispose() { - super.dispose() - headlessWebView = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/ISettings.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/ISettings.swift deleted file mode 100755 index 1e21d4e855..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/ISettings.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// Options.swift -// flutter_inappwebview -// -// Created by Lorenzo on 26/09/18. -// - -import Foundation - -@objcMembers -public class ISettings: NSObject { - - override init(){ - super.init() - } - - func parse(settings: [String: Any?]) -> ISettings { - for (key, value) in settings { - if !(value is NSNull), value != nil { - if self.responds(to: Selector(key)) { - self.setValue(value, forKey: key) - } else if self.responds(to: Selector("_" + key)) { - self.setValue(value, forKey: "_" + key) - } - } - } - return self - } - - func toMap() -> [String: Any?] { - var settings: [String: Any?] = [:] - let mirrored_object = Mirror(reflecting: self) - for (_, attr) in mirrored_object.children.enumerated() { - if let property_name = attr.label as String? { - settings[property_name] = attr.value - } - } - return settings - } - - func getRealSettings(obj: T?) -> [String: Any?] { - let realSettings: [String: Any?] = toMap() - return realSettings - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserChannelDelegate.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserChannelDelegate.swift deleted file mode 100644 index 19dc499f91..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserChannelDelegate.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// InAppBrowserChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 05/05/22. -// - -import Foundation -import FlutterMacOS - -public class InAppBrowserChannelDelegate: ChannelDelegate { - public override init(channel: FlutterMethodChannel) { - super.init(channel: channel) - } - - public func onBrowserCreated() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onBrowserCreated", arguments: arguments) - } - - public func onMenuItemClicked(menuItem: InAppBrowserMenuItem) { - let arguments: [String: Any?] = [ - "id": menuItem.id - ] - channel?.invokeMethod("onMenuItemClicked", arguments: arguments) - } - - public func onMainWindowWillClose() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onMainWindowWillClose", arguments: arguments) - } - - public func onExit() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onExit", arguments: arguments) - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserDelegate.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserDelegate.swift deleted file mode 100644 index ba013c58e9..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserDelegate.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// InAppBrowserDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 14/02/21. -// - -import Foundation - -public protocol InAppBrowserDelegate { - func didChangeTitle(title: String?) - func didStartNavigation(url: URL?) - func didUpdateVisitedHistory(url: URL?) - func didFinishNavigation(url: URL?) - func didFailNavigation(url: URL?, error: Error) - func didChangeProgress(progress: Double) -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserManager.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserManager.swift deleted file mode 100755 index 68745e2079..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserManager.swift +++ /dev/null @@ -1,122 +0,0 @@ -// -// InAppBrowserManager.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 18/12/2019. -// - -import FlutterMacOS -import AppKit -import WebKit -import Foundation -import AVFoundation - -public class InAppBrowserManager: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappbrowser" - static let WEBVIEW_STORYBOARD = "WebView" - static let WEBVIEW_STORYBOARD_CONTROLLER_ID = "viewController" - static let NAV_STORYBOARD_CONTROLLER_ID = "navController" - var plugin: InAppWebViewFlutterPlugin? - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: InAppBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger)) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "open": - open(arguments: arguments!) - result(true) - break - case "openWithSystemBrowser": - let url = arguments!["url"] as! String - openWithSystemBrowser(url: url, result: result) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func open(arguments: NSDictionary) { - let id = arguments["id"] as! String - let urlRequest = arguments["urlRequest"] as? [String:Any?] - let assetFilePath = arguments["assetFilePath"] as? String - let data = arguments["data"] as? String - let mimeType = arguments["mimeType"] as? String - let encoding = arguments["encoding"] as? String - let baseUrl = arguments["baseUrl"] as? String - let settings = arguments["settings"] as! [String: Any?] - let windowId = arguments["windowId"] as? Int64 - let initialUserScripts = arguments["initialUserScripts"] as? [[String: Any]] - let menuItems = arguments["menuItems"] as! [[String: Any?]] - - let browserSettings = InAppBrowserSettings() - let _ = browserSettings.parse(settings: settings) - - let webViewSettings = InAppWebViewSettings() - let _ = webViewSettings.parse(settings: settings) - - let webViewController = InAppBrowserWebViewController() - webViewController.plugin = plugin - webViewController.browserSettings = browserSettings - webViewController.webViewSettings = webViewSettings - - webViewController.id = id - webViewController.initialUrlRequest = urlRequest != nil ? URLRequest.init(fromPluginMap: urlRequest!) : nil - webViewController.initialFile = assetFilePath - webViewController.initialData = data - webViewController.initialMimeType = mimeType - webViewController.initialEncoding = encoding - webViewController.initialBaseUrl = baseUrl - webViewController.windowId = windowId - webViewController.initialUserScripts = initialUserScripts ?? [] - webViewController.isHidden = browserSettings.hidden - - let window = InAppBrowserWindow(contentViewController: webViewController) - window.browserSettings = browserSettings - window.contentViewController = webViewController - for menuItem in menuItems { - window.menuItems.append(InAppBrowserMenuItem.fromMap(map: menuItem)!) - } - window.prepare() - - if #available(macOS 10.12, *), browserSettings.windowType == .tabbed { - NSApplication.shared.mainWindow?.addTabbedWindow(window, ordered: .above) - } else if browserSettings.windowType == .child { - NSApplication.shared.mainWindow?.addChildWindow(window, ordered: .above) - } else { - window.windowController?.showWindow(self) - } - - window.makeKeyAndOrderFront(self) - if browserSettings.hidden { - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1939 - // without calling first window.makeKeyAndOrderFront(self) - // window.hide() would deallocate and dispose the InAppBrowserWindow - window.hide() - NSApplication.shared.mainWindow?.makeKeyAndOrderFront(self) - } - } - - public func openWithSystemBrowser(url: String, result: @escaping FlutterResult) { - let absoluteUrl = URL(string: url)!.absoluteURL - if !NSWorkspace.shared.open(absoluteUrl) { - result(FlutterError(code: "InAppBrowserManager", message: url + " cannot be opened!", details: nil)) - return - } - result(true) - } - - public override func dispose() { - super.dispose() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserSettings.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserSettings.swift deleted file mode 100755 index 26670f0296..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserSettings.swift +++ /dev/null @@ -1,92 +0,0 @@ -// -// InAppBrowserOptions.swift -// flutter_inappwebview -// -// Created by Lorenzo on 17/09/18. -// - -import Foundation -import AppKit - -@objcMembers -public class InAppBrowserSettings: ISettings { - - var hidden = false - var hideToolbarTop = true - var toolbarTopBackgroundColor: String? - var hideUrlBar = false - var hideProgressBar = false - var toolbarTopFixedTitle: String? - var windowType = InAppBrowserWindowType.window - var windowAlphaValue = 1.0 - var _windowStyleMask: NSNumber? - var windowStyleMask: NSWindow.StyleMask? { - get { - return _windowStyleMask != nil ? - NSWindow.StyleMask.init(rawValue: _windowStyleMask!.uintValue) : - nil - } - set { - if let newValue = newValue { - _windowStyleMask = NSNumber.init(value: newValue.rawValue) - } else { - _windowStyleMask = nil - } - } - } - var _windowTitlebarSeparatorStyle: NSNumber? - @available(macOS 11.0, *) - var windowTitlebarSeparatorStyle: NSTitlebarSeparatorStyle? { - get { - return _windowTitlebarSeparatorStyle != nil ? - NSTitlebarSeparatorStyle.init(rawValue: _windowTitlebarSeparatorStyle!.intValue) : - nil - } - set { - if let newValue = newValue { - _windowTitlebarSeparatorStyle = NSNumber.init(value: newValue.rawValue) - } else { - _windowTitlebarSeparatorStyle = nil - } - } - } - var windowFrame: NSRect? - var hideDefaultMenuItems = false - - override init(){ - super.init() - } - - override func parse(settings: [String: Any?]) -> InAppBrowserSettings { - let _ = super.parse(settings: settings) - if let windowType = settings["windowType"] as? String { - self.windowType = InAppBrowserWindowType.init(rawValue: windowType) ?? InAppBrowserWindowType.child - } - if let windowFrame = settings["windowFrame"] as? [String:Double] { - self.windowFrame = NSRect(x: windowFrame["x"]!, - y: windowFrame["y"]!, - width: windowFrame["width"]!, - height: windowFrame["height"]!) - } - return self - } - - override func getRealSettings(obj: InAppBrowserWebViewController?) -> [String: Any?] { - var realOptions: [String: Any?] = toMap() - realOptions["windowType"] = windowType.rawValue - if let inAppBrowserWebViewController = obj { - realOptions["hidden"] = inAppBrowserWebViewController.isHidden - realOptions["hideUrlBar"] = inAppBrowserWebViewController.window?.searchBar?.isHidden - realOptions["hideProgressBar"] = inAppBrowserWebViewController.progressBar.isHidden - realOptions["hideToolbarTop"] = !(inAppBrowserWebViewController.window?.toolbar?.isVisible ?? true) - realOptions["toolbarTopBackgroundColor"] = inAppBrowserWebViewController.window?.backgroundColor.hexString - realOptions["windowAlphaValue"] = inAppBrowserWebViewController.window?.alphaValue - realOptions["windowStyleMask"] = inAppBrowserWebViewController.window?.styleMask.rawValue - if #available(macOS 11.0, *) { - realOptions["windowTitlebarSeparatorStyle"] = inAppBrowserWebViewController.window?.titlebarSeparatorStyle.rawValue - } - realOptions["windowFrame"] = inAppBrowserWebViewController.window?.frame.toMap() - } - return realOptions - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserWebViewController.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserWebViewController.swift deleted file mode 100755 index 890f154e3d..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserWebViewController.swift +++ /dev/null @@ -1,339 +0,0 @@ -// -// InAppBrowserWebViewController.swift -// flutter_inappwebview -// -// Created by Lorenzo on 17/09/18. -// - -import FlutterMacOS -import AppKit -import WebKit -import Foundation - -public class InAppBrowserWebViewController: NSViewController, InAppBrowserDelegate, Disposable { - static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappbrowser_"; - - var progressBar: NSProgressIndicator! - - var window: InAppBrowserWindow? - var id: String = "" - var plugin: InAppWebViewFlutterPlugin? - var windowId: Int64? - var webView: InAppWebView? - var channelDelegate: InAppBrowserChannelDelegate? - var initialUrlRequest: URLRequest? - var initialFile: String? - var browserSettings: InAppBrowserSettings? - var webViewSettings: InAppWebViewSettings? - var initialData: String? - var initialMimeType: String? - var initialEncoding: String? - var initialBaseUrl: String? - var initialUserScripts: [[String: Any]] = [] - var isHidden = false - - public override func loadView() { - guard let plugin = plugin else { - return - } - - let channel = FlutterMethodChannel(name: InAppBrowserWebViewController.METHOD_CHANNEL_NAME_PREFIX + id, binaryMessenger: plugin.registrar.messenger) - channelDelegate = InAppBrowserChannelDelegate(channel: channel) - - var userScripts: [UserScript] = [] - for initialUserScript in initialUserScripts { - userScripts.append(UserScript.fromMap(map: initialUserScript, windowId: windowId)!) - } - - let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(settings: webViewSettings) - if let wId = windowId, let webViewTransport = plugin.inAppWebViewManager?.windowWebViews[wId] { - webView = webViewTransport.webView - webView!.initialUserScripts = userScripts - } else { - webView = InAppWebView(id: nil, - plugin: nil, - frame: .zero, - configuration: preWebviewConfiguration, - userScripts: userScripts) - } - - guard let webView = webView else { - return - } - - webView.inAppBrowserDelegate = self - webView.id = id - webView.plugin = plugin - webView.channelDelegate = WebViewChannelDelegate(webView: webView, channel: channel) - - let findInteractionController = FindInteractionController( - plugin: plugin, - id: id, webView: webView, settings: nil) - webView.findInteractionController = findInteractionController - findInteractionController.prepare() - - prepareWebView() - webView.windowCreated = true - - progressBar = NSProgressIndicator() - progressBar.style = .bar - progressBar.isIndeterminate = false - progressBar.startAnimation(self) - - view = NSView(frame: NSApplication.shared.mainWindow?.frame ?? .zero) - view.addSubview(webView) - view.addSubview(progressBar, positioned: .above, relativeTo: webView) - } - - public override func viewDidLoad() { - super.viewDidLoad() - - webView?.translatesAutoresizingMaskIntoConstraints = false - progressBar.translatesAutoresizingMaskIntoConstraints = false - - webView?.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0.0).isActive = true - webView?.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0.0).isActive = true - webView?.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0.0).isActive = true - webView?.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0.0).isActive = true - - progressBar.topAnchor.constraint(equalTo: self.view.topAnchor, constant: -6.0).isActive = true - progressBar.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0.0).isActive = true - progressBar.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0.0).isActive = true - - if let wId = windowId { - channelDelegate?.onBrowserCreated() - webView?.runWindowBeforeCreatedCallbacks() - } else { - if #available(macOS 10.13, *) { - if let contentBlockers = webView?.settings?.contentBlockers, contentBlockers.count > 0 { - do { - let jsonData = try JSONSerialization.data(withJSONObject: contentBlockers, options: []) - let blockRules = String(data: jsonData, encoding: .utf8) - WKContentRuleListStore.default().compileContentRuleList( - forIdentifier: "ContentBlockingRules", - encodedContentRuleList: blockRules) { (contentRuleList, error) in - - if let error = error { - print(error.localizedDescription) - return - } - - let configuration = self.webView!.configuration - configuration.userContentController.add(contentRuleList!) - - self.initLoad() - } - return - } catch { - print(error.localizedDescription) - } - } - } - - initLoad() - } - } - - public override func viewDidAppear() { - super.viewDidAppear() - window = view.window as? InAppBrowserWindow - } - - public func initLoad() { - if let initialFile = initialFile { - do { - try webView?.loadFile(assetFilePath: initialFile) - } - catch let error as NSError { - dump(error) - } - } - else if let initialData = initialData { - let baseUrl = URL(string: initialBaseUrl ?? "about:blank")! - var allowingReadAccessToURL: URL? = nil - if let allowingReadAccessTo = webView?.settings?.allowingReadAccessTo, baseUrl.scheme == "file" { - allowingReadAccessToURL = URL(string: allowingReadAccessTo) - if allowingReadAccessToURL?.scheme != "file" { - allowingReadAccessToURL = nil - } - } - webView?.loadData(data: initialData, mimeType: initialMimeType!, encoding: initialEncoding!, baseUrl: baseUrl, allowingReadAccessTo: allowingReadAccessToURL) - } - else if let initialUrlRequest = initialUrlRequest { - var allowingReadAccessToURL: URL? = nil - if let allowingReadAccessTo = webView?.settings?.allowingReadAccessTo, let url = initialUrlRequest.url, url.scheme == "file" { - allowingReadAccessToURL = URL(string: allowingReadAccessTo) - if allowingReadAccessToURL?.scheme != "file" { - allowingReadAccessToURL = nil - } - } - webView?.loadUrl(urlRequest: initialUrlRequest, allowingReadAccessTo: allowingReadAccessToURL) - } - - channelDelegate?.onBrowserCreated() - } - - public func prepareWebView() { - webView?.settings = webViewSettings - webView?.prepare() - - if let browserSettings = browserSettings { - if browserSettings.hideProgressBar { - progressBar.isHidden = true - } - } - } - - public func didChangeTitle(title: String?) { - guard let title = title else { - return - } - if let browserSettings = browserSettings, - let toolbarTopFixedTitle = browserSettings.toolbarTopFixedTitle { - window?.title = toolbarTopFixedTitle - } else { - window?.title = title - } - window?.update() - } - - public func didStartNavigation(url: URL?) { - window?.forwardButton?.isEnabled = webView?.canGoForward ?? false - window?.backButton?.isEnabled = webView?.canGoBack ?? false - progressBar.doubleValue = 0.0 - progressBar.isHidden = false - guard let url = url else { - return - } - window?.searchBar?.stringValue = url.absoluteString - } - - public func didUpdateVisitedHistory(url: URL?) { - window?.forwardButton?.isEnabled = webView?.canGoForward ?? false - window?.backButton?.isEnabled = webView?.canGoBack ?? false - guard let url = url else { - return - } - window?.searchBar?.stringValue = url.absoluteString - } - - public func didFinishNavigation(url: URL?) { - window?.forwardButton?.isEnabled = webView?.canGoForward ?? false - window?.backButton?.isEnabled = webView?.canGoBack ?? false - progressBar.doubleValue = 0.0 - progressBar.isHidden = true - guard let url = url else { - return - } - window?.searchBar?.stringValue = url.absoluteString - } - - public func didFailNavigation(url: URL?, error: Error) { - window?.forwardButton?.isEnabled = webView?.canGoForward ?? false - window?.backButton?.isEnabled = webView?.canGoBack ?? false - progressBar.doubleValue = 0.0 - progressBar.isHidden = true - } - - public func didChangeProgress(progress: Double) { - progressBar.isHidden = false - progressBar.doubleValue = progress * 100 - if progress == 100.0 { - progressBar.isHidden = true - } - } - - @objc public func reload() { - webView?.reload() - didUpdateVisitedHistory(url: webView?.url) - } - - @objc public func goBack() { - if let webView = webView, webView.canGoBack { - webView.goBack() - } - } - - @objc public func goForward() { - if let webView = webView, webView.canGoForward { - webView.goForward() - } - } - - @objc public func goBackOrForward(steps: Int) { - webView?.goBackOrForward(steps: steps) - } - - @objc public func onMenuItemClicked(sender: Any?) { - var identifier: String? - if let sender = sender as? NSMenuItem { - identifier = sender.identifier?.rawValue - } - if identifier == nil, let sender = sender as? NSButton { - identifier = sender.identifier?.rawValue - } - if let identifier = identifier, let window = window { - let menuItem = window.menuItems.first { item in - return item.id == Int64(identifier) - } - if let menuItem = menuItem { - channelDelegate?.onMenuItemClicked(menuItem: menuItem) - } - } - } - - public func setSettings(newSettings: InAppBrowserSettings, newSettingsMap: [String: Any]) { - window?.setSettings(newSettings: newSettings, newSettingsMap: newSettingsMap) - - let newInAppWebViewSettings = InAppWebViewSettings() - let _ = newInAppWebViewSettings.parse(settings: newSettingsMap) - webView?.setSettings(newSettings: newInAppWebViewSettings, newSettingsMap: newSettingsMap) - - if newSettingsMap["hideProgressBar"] != nil, browserSettings?.hideProgressBar != newSettings.hideProgressBar { - progressBar.isHidden = newSettings.hideProgressBar - } - - browserSettings = newSettings - webViewSettings = newInAppWebViewSettings - } - - public func getSettings() -> [String: Any?]? { - let webViewSettingsMap = webView?.getSettings() - if (self.browserSettings == nil || webViewSettingsMap == nil) { - return nil - } - var settingsMap = self.browserSettings!.getRealSettings(obj: self) - settingsMap.merge(webViewSettingsMap!, uniquingKeysWith: { (current, _) in current }) - return settingsMap - } - - public func hide() { - isHidden = true - window?.hide() - } - - public func show() { - isHidden = false - window?.show() - } - - public func close() { - window?.close() - } - - public func dispose() { - channelDelegate?.onExit() - channelDelegate?.dispose() - channelDelegate = nil - webView?.dispose() - webView?.removeFromSuperview() - webView = nil - window = nil - plugin = nil - } - - deinit { - debugPrint("InAppBrowserWebViewController - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserWindow.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserWindow.swift deleted file mode 100644 index cf6957a4b5..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppBrowser/InAppBrowserWindow.swift +++ /dev/null @@ -1,388 +0,0 @@ -// -// InAppBrowserNavigationController.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 14/02/21. -// - -import Foundation -import AppKit - -struct ToolbarIdentifiers { - static let searchBar = NSToolbarItem.Identifier(rawValue: "SearchBar") - static let backButton = NSToolbarItem.Identifier(rawValue: "BackButton") - static let forwardButton = NSToolbarItem.Identifier(rawValue: "ForwardButton") - static let reloadButton = NSToolbarItem.Identifier(rawValue: "ReloadButton") - static let menuButton = NSToolbarItem.Identifier(rawValue: "MenuButton") -} - -public class InAppBrowserWindow: NSWindow, NSWindowDelegate, NSToolbarDelegate, NSSearchFieldDelegate { - var searchItem: NSToolbarItem? - var backItem: NSToolbarItem? - var forwardItem: NSToolbarItem? - var reloadItem: NSToolbarItem? - var menuItem: NSToolbarItem? - var actionItems: [NSToolbarItem] = [] - - var reloadButton: NSButton? { - get { - return reloadItem?.view as? NSButton - } - } - var backButton: NSButton? { - get { - return backItem?.view as? NSButton - } - } - var forwardButton: NSButton? { - get { - return forwardItem?.view as? NSButton - } - } - var searchBar: NSSearchField? { - get { - if #available(macOS 11.0, *), let searchItem = searchItem as? NSSearchToolbarItem { - return searchItem.searchField - } else { - return searchItem?.view as? NSSearchField - } - } - } - var menuButton: NSPopUpButton? { - get { - return menuItem?.view as? NSPopUpButton - } - } - - var browserSettings: InAppBrowserSettings? - var menuItems: [InAppBrowserMenuItem] = [] - - public func prepare() { - title = "" - collectionBehavior = .fullScreenPrimary - delegate = self - - NotificationCenter.default.addObserver(self, - selector: #selector(onMainWindowWillClose(_:)), - name: NSWindow.willCloseNotification, - object: NSApplication.shared.mainWindow) - - if #available(macOS 10.13, *) { - let windowToolbar = NSToolbar() - windowToolbar.delegate = self - if #available(macOS 11.0, *) { - searchItem = NSSearchToolbarItem(itemIdentifier: ToolbarIdentifiers.searchBar) - (searchItem as! NSSearchToolbarItem).searchField.delegate = self - toolbarStyle = .expanded - } else { - searchItem = NSToolbarItem(itemIdentifier: ToolbarIdentifiers.searchBar) - let textField = NSSearchField() - textField.usesSingleLineMode = true - textField.delegate = self - searchItem?.view = textField - } - searchItem?.label = "" - windowToolbar.displayMode = .default - - backItem = NSToolbarItem(itemIdentifier: ToolbarIdentifiers.backButton) - backItem?.label = "" - if let webViewController = contentViewController as? InAppBrowserWebViewController { - if #available(macOS 11.0, *) { - backItem?.view = NSButton(image: NSImage(systemSymbolName: "chevron.left", - accessibilityDescription: "Go Back")!, - target: webViewController, - action: #selector(InAppBrowserWebViewController.goBack)) - } else { - backItem?.view = NSButton(title: "\u{2039}", - target: webViewController, - action: #selector(InAppBrowserWebViewController.goBack)) - } - } - - forwardItem = NSToolbarItem(itemIdentifier: ToolbarIdentifiers.forwardButton) - forwardItem?.label = "" - if let webViewController = contentViewController as? InAppBrowserWebViewController { - if #available(macOS 11.0, *) { - forwardItem?.view = NSButton(image: NSImage(systemSymbolName: "chevron.right", - accessibilityDescription: "Go Forward")!, - target: webViewController, - action: #selector(InAppBrowserWebViewController.goForward)) - } else { - forwardItem?.view = NSButton(title: "\u{203A}", - target: webViewController, - action: #selector(InAppBrowserWebViewController.goForward)) - } - } - - reloadItem = NSToolbarItem(itemIdentifier: ToolbarIdentifiers.reloadButton) - reloadItem?.label = "" - if let webViewController = contentViewController as? InAppBrowserWebViewController { - if #available(macOS 11.0, *) { - reloadItem?.view = NSButton(image: NSImage(systemSymbolName: "arrow.counterclockwise", - accessibilityDescription: "Reload")!, - target: webViewController, - action: #selector(InAppBrowserWebViewController.reload)) - } else { - reloadItem?.view = NSButton(title: "Reload", - target: webViewController, - action: #selector(InAppBrowserWebViewController.reload)) - } - } - - if #available(macOS 10.15, *), !menuItems.isEmpty { - menuItem = NSMenuToolbarItem(itemIdentifier: ToolbarIdentifiers.menuButton) - if let menuItem = menuItem as? NSMenuToolbarItem { - menuItem.label = "" - if #available(macOS 11.0, *) { - menuItem.image = NSImage(systemSymbolName: "ellipsis.circle", - accessibilityDescription: "Options") - menuItem.showsIndicator = true - menuItem.isBordered = true - } else { - menuItem.title = "Options" - } - let menu = NSMenu() - menuItems = menuItems.sorted(by: {$0.order ?? 0 < $1.order ?? 0}) - for item in menuItems { - if !item.showAsAction { - let nsItem = NSMenuItem(title: item.title, action: #selector(InAppBrowserWebViewController.onMenuItemClicked), keyEquivalent: "") - nsItem.identifier = NSUserInterfaceItemIdentifier.init(String(item.id)) - nsItem.image = item.icon - menu.addItem(nsItem) - } else { - let actionItem = NSMenuToolbarItem(itemIdentifier: NSToolbarItem.Identifier(rawValue: String(item.id))) - actionItem.label = "" - if let webViewController = contentViewController as? InAppBrowserWebViewController { - let actionButton = NSButton(title: item.title, - target: webViewController, - action: #selector(InAppBrowserWebViewController.onMenuItemClicked)) - actionButton.identifier = NSUserInterfaceItemIdentifier.init(String(item.id)) - actionButton.image = item.icon - actionItem.view = actionButton - } - actionItems.append(actionItem) - } - } - menuItem.menu = menu - } - } - - - if #available(macOS 10.14, *) { - windowToolbar.centeredItemIdentifier = ToolbarIdentifiers.searchBar - } - toolbar = windowToolbar - } - - forwardButton?.isEnabled = false - backButton?.isEnabled = false - - if let browserSettings = browserSettings { - if let toolbarTopFixedTitle = browserSettings.toolbarTopFixedTitle { - title = toolbarTopFixedTitle - } - if !browserSettings.hideToolbarTop { - toolbar?.isVisible = true - if browserSettings.hideUrlBar { - if #available(macOS 11.0, *) { - (searchItem as! NSSearchToolbarItem).searchField.isHidden = true - } else { - searchItem?.view?.isHidden = true - } - } - if let bgColor = browserSettings.toolbarTopBackgroundColor, !bgColor.isEmpty { - backgroundColor = NSColor(hexString: bgColor) - } - } - else { - toolbar?.isVisible = false - } - if #available(macOS 11.0, *), let windowTitlebarSeparatorStyle = browserSettings.windowTitlebarSeparatorStyle { - titlebarSeparatorStyle = windowTitlebarSeparatorStyle - } - alphaValue = browserSettings.windowAlphaValue - if let windowStyleMask = browserSettings.windowStyleMask { - styleMask = windowStyleMask - } - if let windowFrame = browserSettings.windowFrame { - setFrame(windowFrame, display: true) - } - reloadItem?.view?.isHidden = browserSettings.hideDefaultMenuItems - backItem?.view?.isHidden = browserSettings.hideDefaultMenuItems - forwardItem?.view?.isHidden = browserSettings.hideDefaultMenuItems - } - } - - public func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { - return [[ ToolbarIdentifiers.menuButton, - ToolbarIdentifiers.searchBar, - ToolbarIdentifiers.backButton, - ToolbarIdentifiers.forwardButton, - ToolbarIdentifiers.reloadButton, - .flexibleSpace ], actionItems.compactMap({ item in - return item.itemIdentifier - })].flatMap { $0 } - } - - public func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { - return [[.flexibleSpace, - ToolbarIdentifiers.searchBar, - .flexibleSpace, - ToolbarIdentifiers.reloadButton, - ToolbarIdentifiers.backButton, - ToolbarIdentifiers.forwardButton], - actionItems.compactMap({ item in - return item.itemIdentifier - }), - [ToolbarIdentifiers.menuButton]].flatMap { $0 } - } - - public func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? { - switch(itemIdentifier) { - case ToolbarIdentifiers.searchBar: - return searchItem - case ToolbarIdentifiers.backButton: - return backItem - case ToolbarIdentifiers.forwardButton: - return forwardItem - case ToolbarIdentifiers.reloadButton: - return reloadItem - case ToolbarIdentifiers.menuButton: - return menuItem - default: - let actionItem = actionItems.first { item in - return item.itemIdentifier == itemIdentifier - } - return actionItem - } - } - - public func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool { - if (commandSelector == #selector(NSResponder.insertNewline(_:))) { - // ENTER key - var searchField: NSSearchField? = nil - if #available(macOS 11.0, *), let searchBar = searchItem as? NSSearchToolbarItem { - searchField = searchBar.searchField - } else if let searchBar = searchItem { - searchField = searchBar.view as? NSSearchField - } - - guard let searchField, - let urlEncoded = searchField.stringValue.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), - let url = URL(string: urlEncoded) else { - return false - } - - let request = URLRequest(url: url) - (contentViewController as? InAppBrowserWebViewController)?.webView?.load(request) - - return true - } - - return false - } - - public func hide() { - orderOut(self) - } - - public func show() { - let mainWindow = parent ?? NSApplication.shared.mainWindow - if #available(macOS 10.12, *), - !(mainWindow?.tabbedWindows?.contains(self) ?? false), - browserSettings?.windowType == .tabbed { - mainWindow?.addTabbedWindow(self, ordered: .above) - } else if !(mainWindow?.childWindows?.contains(self) ?? false) { - mainWindow?.addChildWindow(self, ordered: .above) - } - makeKeyAndOrderFront(self) - NSApplication.shared.activate(ignoringOtherApps: true) - } - - public func setSettings(newSettings: InAppBrowserSettings, newSettingsMap: [String: Any]) { - if newSettingsMap["hidden"] != nil, browserSettings?.hidden != newSettings.hidden { - if newSettings.hidden { - hide() - } - else { - show() - } - } - - if newSettingsMap["hideUrlBar"] != nil, browserSettings?.hideUrlBar != newSettings.hideUrlBar { - searchBar?.isHidden = newSettings.hideUrlBar - } - - if newSettingsMap["hideToolbarTop"] != nil, browserSettings?.hideToolbarTop != newSettings.hideToolbarTop { - toolbar?.isVisible = !newSettings.hideToolbarTop - } - - if newSettingsMap["toolbarTopBackgroundColor"] != nil, browserSettings?.toolbarTopBackgroundColor != newSettings.toolbarTopBackgroundColor { - if let bgColor = newSettings.toolbarTopBackgroundColor, !bgColor.isEmpty { - backgroundColor = NSColor(hexString: bgColor) - } else { - backgroundColor = nil - } - } - if #available(macOS 11.0, *), newSettingsMap["windowTitlebarSeparatorStyle"] != nil, - browserSettings?.windowTitlebarSeparatorStyle != newSettings.windowTitlebarSeparatorStyle { - titlebarSeparatorStyle = newSettings.windowTitlebarSeparatorStyle! - } - if newSettingsMap["windowAlphaValue"] != nil, browserSettings?.windowAlphaValue != newSettings.windowAlphaValue { - alphaValue = newSettings.windowAlphaValue - } - if newSettingsMap["windowStyleMask"] != nil, browserSettings?.windowStyleMask != newSettings.windowStyleMask { - styleMask = newSettings.windowStyleMask! - } - if newSettingsMap["windowFrame"] != nil, browserSettings?.windowFrame != newSettings.windowFrame { - setFrame(newSettings.windowFrame!, display: true) - } - if newSettingsMap["hideDefaultMenuItems"] != nil, browserSettings?.hideDefaultMenuItems != newSettings.hideDefaultMenuItems { - reloadItem?.view?.isHidden = newSettings.hideDefaultMenuItems - backItem?.view?.isHidden = newSettings.hideDefaultMenuItems - forwardItem?.view?.isHidden = newSettings.hideDefaultMenuItems - } - browserSettings = newSettings - } - - public func windowWillClose(_ notification: Notification) { - dispose() - } - - @objc func onMainWindowWillClose(_ notification: Notification) { - if let webViewController = contentViewController as? InAppBrowserWebViewController { - webViewController.channelDelegate?.onMainWindowWillClose() - } - } - - public func dispose() { - delegate = nil - NotificationCenter.default.removeObserver(self, - name: NSWindow.willCloseNotification, - object: NSApplication.shared.mainWindow) - if let webViewController = contentViewController as? InAppBrowserWebViewController { - webViewController.dispose() - } - if #available(macOS 11.0, *) { - (searchItem as? NSSearchToolbarItem)?.searchField.delegate = nil - } else { - (searchItem?.view as? NSTextField)?.delegate = nil - searchItem?.view = nil - } - searchItem = nil - (backItem?.view as? NSButton)?.target = nil - backItem?.view = nil - backItem = nil - (forwardItem?.view as? NSButton)?.target = nil - forwardItem?.view = nil - forwardItem = nil - (reloadItem?.view as? NSButton)?.target = nil - reloadItem?.view = nil - reloadItem = nil - } - - deinit { - debugPrint("InAppBrowserWindow - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/ContextMenuSettings.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/ContextMenuSettings.swift deleted file mode 100644 index a1df58d92a..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/ContextMenuSettings.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// ContextMenuOptions.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 30/05/2020. -// - -import Foundation - -public class ContextMenuSettings: ISettings { - - var hideDefaultSystemContextMenuItems = false; - - override init(){ - super.init() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/CustomSchemeHandler.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/CustomSchemeHandler.swift deleted file mode 100755 index d4119f34b8..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/CustomSchemeHandler.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// CustomSchemeHandler.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 25/10/2019. -// - -import FlutterMacOS -import Foundation -import WebKit - -@available(macOS 10.13, *) -public class CustomSchemeHandler: NSObject, WKURLSchemeHandler { - var schemeHandlers: [Int: WKURLSchemeTask] = [:] - - public func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) { - schemeHandlers[urlSchemeTask.hash] = urlSchemeTask - let inAppWebView = webView as! InAppWebView - let request = WebResourceRequest.init(fromURLRequest: urlSchemeTask.request) - let callback = WebViewChannelDelegate.LoadResourceWithCustomSchemeCallback() - callback.nonNullSuccess = { (response: CustomSchemeResponse) in - if (self.schemeHandlers[urlSchemeTask.hash] != nil) { - let urlResponse = URLResponse(url: request.url, mimeType: response.contentType, expectedContentLength: -1, textEncodingName: response.contentEncoding) - urlSchemeTask.didReceive(urlResponse) - urlSchemeTask.didReceive(response.data) - urlSchemeTask.didFinish() - self.schemeHandlers.removeValue(forKey: urlSchemeTask.hash) - } - return false - } - callback.error = { (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - } - - if let channelDelegate = inAppWebView.channelDelegate { - channelDelegate.onLoadResourceWithCustomScheme(request: request, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - public func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) { - schemeHandlers.removeValue(forKey: urlSchemeTask.hash) - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/FlutterWebViewController.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/FlutterWebViewController.swift deleted file mode 100755 index 04895703fe..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/FlutterWebViewController.swift +++ /dev/null @@ -1,200 +0,0 @@ -// -// FlutterWebViewController.swift -// flutter_inappwebview -// -// Created by Lorenzo on 13/11/18. -// - -import Foundation -import WebKit -import FlutterMacOS - -public class FlutterWebViewController: NSView, Disposable { - - var keepAliveId: String? - - init(plugin: InAppWebViewFlutterPlugin, withFrame frame: CGRect, viewIdentifier viewId: Any, params: NSDictionary) { - super.init(frame: frame) - - keepAliveId = params["keepAliveId"] as? String - - let initialSettings = params["initialSettings"] as! [String: Any?] - let windowId = params["windowId"] as? Int64 - let initialUserScripts = params["initialUserScripts"] as? [[String: Any]] - - var userScripts: [UserScript] = [] - if let initialUserScripts = initialUserScripts { - for initialUserScript in initialUserScripts { - userScripts.append(UserScript.fromMap(map: initialUserScript, windowId: windowId)!) - } - } - - let settings = InAppWebViewSettings() - let _ = settings.parse(settings: initialSettings) - let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(settings: settings) - - var webView: InAppWebView? - - if let wId = windowId, let webViewTransport = plugin.inAppWebViewManager?.windowWebViews[wId] { - webView = webViewTransport.webView - webView!.id = viewId - webView!.plugin = plugin - let channel = FlutterMethodChannel(name: InAppWebView.METHOD_CHANNEL_NAME_PREFIX + String(describing: viewId), - binaryMessenger: plugin.registrar.messenger) - webView!.channelDelegate = WebViewChannelDelegate(webView: webView!, channel: channel) - webView!.frame = self.bounds - webView!.initialUserScripts = userScripts - } else { - webView = InAppWebView(id: viewId, - plugin: plugin, - frame: self.bounds, - configuration: preWebviewConfiguration, - userScripts: userScripts) - } - - let findInteractionController = FindInteractionController( - plugin: plugin, - id: viewId, webView: webView!, settings: nil) - webView!.findInteractionController = findInteractionController - findInteractionController.prepare() - - webView!.autoresizingMask = [.width, .height] - self.autoresizesSubviews = true - self.autoresizingMask = [.width, .height] - self.addSubview(webView!) - - webView!.settings = settings - webView!.prepare() - webView!.windowCreated = true - } - - required init?(coder nsCoder: NSCoder) { - super.init(coder: nsCoder) - } - - public func webView() -> InAppWebView? { - for subview in self.subviews - { - if let item = subview as? InAppWebView - { - return item - } - } - return nil - } - - public func view() -> NSView { - return self - } - - public func makeInitialLoad(params: NSDictionary) { - guard let webView = webView() else { - return - } - - let windowId = params["windowId"] as? Int64 - let initialUrlRequest = params["initialUrlRequest"] as? [String: Any?] - let initialFile = params["initialFile"] as? String - let initialData = params["initialData"] as? [String: String?] - - if windowId == nil { - if #available(macOS 10.13, *) { - webView.configuration.userContentController.removeAllContentRuleLists() - if let contentBlockers = webView.settings?.contentBlockers, contentBlockers.count > 0 { - do { - let jsonData = try JSONSerialization.data(withJSONObject: contentBlockers, options: []) - let blockRules = String(data: jsonData, encoding: .utf8) - WKContentRuleListStore.default().compileContentRuleList( - forIdentifier: "ContentBlockingRules", - encodedContentRuleList: blockRules) { (contentRuleList, error) in - - if let error = error { - print(error.localizedDescription) - return - } - - let configuration = webView.configuration - configuration.userContentController.add(contentRuleList!) - - self.load(initialUrlRequest: initialUrlRequest, initialFile: initialFile, initialData: initialData) - } - return - } catch { - print(error.localizedDescription) - } - } - } - load(initialUrlRequest: initialUrlRequest, initialFile: initialFile, initialData: initialData) - } - else if let wId = windowId { - webView.runWindowBeforeCreatedCallbacks() - } - } - - func load(initialUrlRequest: [String:Any?]?, initialFile: String?, initialData: [String: String?]?) { - guard let webView = webView() else { - return - } - - if let initialFile = initialFile { - do { - try webView.loadFile(assetFilePath: initialFile) - } - catch let error as NSError { - dump(error) - } - } - else if let initialData = initialData, let data = initialData["data"]!, - let mimeType = initialData["mimeType"]!, let encoding = initialData["encoding"]!, - let baseUrl = URL(string: initialData["baseUrl"]! ?? "about:blank") { - var allowingReadAccessToURL: URL? = nil - if let allowingReadAccessTo = webView.settings?.allowingReadAccessTo, baseUrl.scheme == "file" { - allowingReadAccessToURL = URL(string: allowingReadAccessTo) - if allowingReadAccessToURL?.scheme != "file" { - allowingReadAccessToURL = nil - } - } - webView.loadData(data: data, - mimeType: mimeType, - encoding: encoding, - baseUrl: baseUrl, - allowingReadAccessTo: allowingReadAccessToURL) - } - else if let initialUrlRequest = initialUrlRequest { - let urlRequest = URLRequest.init(fromPluginMap: initialUrlRequest) - var allowingReadAccessToURL: URL? = nil - if let allowingReadAccessTo = webView.settings?.allowingReadAccessTo, let url = urlRequest.url, url.scheme == "file" { - allowingReadAccessToURL = URL(string: allowingReadAccessTo) - if allowingReadAccessToURL?.scheme != "file" { - allowingReadAccessToURL = nil - } - } - webView.loadUrl(urlRequest: urlRequest, allowingReadAccessTo: allowingReadAccessToURL) - } - } - - // method added to fix: - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1837 - public func dispose(removeFromSuperview: Bool) { - if keepAliveId == nil { - if let webView = webView() { - webView.dispose() - if removeFromSuperview { - webView.removeFromSuperview() - } - } - if removeFromSuperview { - self.removeFromSuperview() - } - } - } - - public func dispose() { - dispose(removeFromSuperview: false) - } - - deinit { - debugPrint("FlutterWebViewController - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/FlutterWebViewFactory.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/FlutterWebViewFactory.swift deleted file mode 100755 index d659dc1a29..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/FlutterWebViewFactory.swift +++ /dev/null @@ -1,72 +0,0 @@ -// -// FlutterWebViewFactory.swift -// flutter_inappwebview -// -// Created by Lorenzo on 13/11/18. -// - -import SwiftUI -import Cocoa -import FlutterMacOS -import Foundation - -public class FlutterWebViewFactory: NSObject, FlutterPlatformViewFactory { - static let VIEW_TYPE_ID = "com.pichillilorenzo/flutter_inappwebview" - private var plugin: InAppWebViewFlutterPlugin - - init(plugin: InAppWebViewFlutterPlugin) { - self.plugin = plugin - super.init() - } - - public func createArgsCodec() -> (FlutterMessageCodec & NSObjectProtocol)? { - return FlutterStandardMessageCodec.sharedInstance() - } - - public func create(withViewIdentifier viewId: Int64, arguments args: Any?) -> NSView { - let arguments = args as? NSDictionary - var flutterWebView: FlutterWebViewController? - var id: Any = viewId - - let keepAliveId = arguments?["keepAliveId"] as? String - let headlessWebViewId = arguments?["headlessWebViewId"] as? String - - if let headlessWebViewId = headlessWebViewId, - let headlessWebView = plugin.headlessInAppWebViewManager?.webViews[headlessWebViewId], - let platformView = headlessWebView?.disposeAndGetFlutterWebView(withFrame: .zero) { - flutterWebView = platformView - flutterWebView?.keepAliveId = keepAliveId - } - - if let keepAliveId = keepAliveId, - flutterWebView == nil, - let keepAliveWebView = plugin.inAppWebViewManager?.keepAliveWebViews[keepAliveId] { - flutterWebView = keepAliveWebView - if let view = flutterWebView?.view() { - // remove from parent - view.removeFromSuperview() - } - } - - let shouldMakeInitialLoad = flutterWebView == nil - if flutterWebView == nil { - if let keepAliveId = keepAliveId { - id = keepAliveId - } - flutterWebView = FlutterWebViewController(plugin: plugin, - withFrame: .zero, - viewIdentifier: id, - params: arguments!) - } - - if let keepAliveId = keepAliveId { - plugin.inAppWebViewManager?.keepAliveWebViews[keepAliveId] = flutterWebView! - } - - if shouldMakeInitialLoad { - flutterWebView?.makeInitialLoad(params: arguments!) - } - - return flutterWebView! - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/InAppWebView.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/InAppWebView.swift deleted file mode 100755 index b3f7a297f3..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/InAppWebView.swift +++ /dev/null @@ -1,2851 +0,0 @@ -// -// InAppWebView.swift -// flutter_inappwebview -// -// Created by Lorenzo on 21/10/18. -// - -import FlutterMacOS -import Foundation -@preconcurrency import WebKit - -public class InAppWebView: WKWebView, WKUIDelegate, - WKNavigationDelegate, WKScriptMessageHandler, - WKDownloadDelegate, - Disposable { - static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_" - - var id: Any? // viewId - var plugin: InAppWebViewFlutterPlugin? - var windowId: Int64? - var windowCreated = false - var windowBeforeCreatedCallbacks: [() -> ()] = [] - var inAppBrowserDelegate: InAppBrowserDelegate? - var channelDelegate: WebViewChannelDelegate? - var settings: InAppWebViewSettings? - var findInteractionController: FindInteractionController? - var webMessageChannels: [String:WebMessageChannel] = [:] - var webMessageListeners: [WebMessageListener] = [] - var currentOriginalUrl: URL? - var inFullscreen = false - weak var fullscreenWindow: NSWindow? // Track the window that entered fullscreen - private var printJobCompletionHandler: PrintJobController.CompletionHandler? - - static var sslCertificatesMap: [String: SslCertificate] = [:] // [URL host name : SslCertificate] - static var credentialsProposed: [URLCredential] = [] - - var lastScrollX: CGFloat = 0 - var lastScrollY: CGFloat = 0 - - // Used to manage pauseTimers() and resumeTimers() - var isPausedTimers = false - var isPausedTimersCompletionHandler: (() -> Void)? - - var initialUserScripts: [UserScript] = [] - - var customIMPs: [IMP] = [] - - var callAsyncJavaScriptBelowMacOS11Results: [String:((Any?) -> Void)] = [:] - - var currentOpenPanel: NSOpenPanel? - - fileprivate var interceptOnlyAsyncAjaxRequestsPluginScript: PluginScript? - - private var exceptedBridgeSecret = NSUUID().uuidString - private var javaScriptBridgeEnabled = true - - public override var acceptsFirstResponder: Bool { return true } - - init(id: Any?, plugin: InAppWebViewFlutterPlugin?, frame: CGRect, configuration: WKWebViewConfiguration, - userScripts: [UserScript] = []) { - super.init(frame: frame, configuration: configuration) - self.id = id - self.plugin = plugin - if let id = id, let registrar = plugin?.registrar { - let channel = FlutterMethodChannel(name: InAppWebView.METHOD_CHANNEL_NAME_PREFIX + String(describing: id), - binaryMessenger: registrar.messenger) - self.channelDelegate = WebViewChannelDelegate(webView: self, channel: channel) - } - self.initialUserScripts = userScripts - uiDelegate = self - navigationDelegate = self - } - - required public init(coder aDecoder: NSCoder) { - super.init(coder: aDecoder)! - } - - public func prepare() { - addObserver(self, - forKeyPath: #keyPath(WKWebView.estimatedProgress), - options: .new, - context: nil) - - addObserver(self, - forKeyPath: #keyPath(WKWebView.url), - options: [.new, .old], - context: nil) - - addObserver(self, - forKeyPath: #keyPath(WKWebView.title), - options: [.new, .old], - context: nil) - - if #available(macOS 12.0, *) { - addObserver(self, - forKeyPath: #keyPath(WKWebView.cameraCaptureState), - options: [.new, .old], - context: nil) - - addObserver(self, - forKeyPath: #keyPath(WKWebView.microphoneCaptureState), - options: [.new, .old], - context: nil) - } - - // KVO observer for fullscreenState on macOS 13.0+ - // NOTE: KVO for fullscreenState doesn't reliably fire. - // The NSWindow notifications below serve as the primary fullscreen detection mechanism. - if #available(macOS 13.0, *) { - addObserver(self, - forKeyPath: #keyPath(WKWebView.fullscreenState), - options: [.new, .old], - context: nil) - } - - // Also listen for NSWindow notifications as a fallback for fullscreen detection - // (works for iframe-based video fullscreen like YouTube) - NotificationCenter.default.addObserver(self, - selector: #selector(onEnterFullscreen(_:)), - name: NSWindow.didEnterFullScreenNotification, - object: nil) - - NotificationCenter.default.addObserver(self, - selector: #selector(onExitFullscreen(_:)), - name: NSWindow.didExitFullScreenNotification, - object: nil) - - if let settings = settings { - if let viewAlpha = settings.alpha { - alphaValue = CGFloat(viewAlpha) - } - - javaScriptBridgeEnabled = settings.javaScriptBridgeEnabled - if let javaScriptBridgeOriginAllowList = settings.javaScriptBridgeOriginAllowList, javaScriptBridgeOriginAllowList.isEmpty { - // an empty list means that the JavaScript Bridge is not allowed for any origin. - javaScriptBridgeEnabled = false - } - - if #available(macOS 12.0, *), settings.transparentBackground { - underPageBackgroundColor = .clear - } - - allowsBackForwardNavigationGestures = settings.allowsBackForwardNavigationGestures - allowsLinkPreview = settings.allowsLinkPreview - if !settings.userAgent.isEmpty { - customUserAgent = settings.userAgent - } - - if #available(macOS 11.0, *) { - mediaType = settings.mediaType - pageZoom = CGFloat(settings.pageZoom) - } - - if #available(macOS 12.0, *) { - if let underPageBackgroundColor = settings.underPageBackgroundColor, !underPageBackgroundColor.isEmpty { - self.underPageBackgroundColor = NSColor(hexString: underPageBackgroundColor) - } - } - - if #available(macOS 13.3, *) { - isInspectable = settings.isInspectable - } - - if settings.clearCache { - clearCache() - } - } - - prepareAndAddUserScripts() - - if windowId != nil { - // The new created window webview has the same WKWebViewConfiguration variable reference. - // So, we cannot set another WKWebViewConfiguration for it unfortunately! - // This is a limitation of the official WebKit API. - return - } - - configuration.preferences = WKPreferences() - if let settings = settings { - configuration.allowsAirPlayForMediaPlayback = settings.allowsAirPlayForMediaPlayback - configuration.preferences.javaScriptCanOpenWindowsAutomatically = settings.javaScriptCanOpenWindowsAutomatically - configuration.preferences.minimumFontSize = CGFloat(settings.minimumFontSize) - - if #available(macOS 10.15, *) { - configuration.preferences.isFraudulentWebsiteWarningEnabled = settings.isFraudulentWebsiteWarningEnabled - configuration.defaultWebpagePreferences.preferredContentMode = WKWebpagePreferences.ContentMode(rawValue: settings.preferredContentMode)! - } - - configuration.preferences.javaScriptEnabled = settings.javaScriptEnabled - if #available(macOS 11.0, *) { - configuration.defaultWebpagePreferences.allowsContentJavaScript = settings.javaScriptEnabled - } - if #available(macOS 11.3, *) { - configuration.preferences.isTextInteractionEnabled = settings.isTextInteractionEnabled - } - if #available(macOS 12.3, *) { - configuration.preferences.isSiteSpecificQuirksModeEnabled = settings.isSiteSpecificQuirksModeEnabled - configuration.preferences.isElementFullscreenEnabled = settings.isElementFullscreenEnabled - } - if #available(macOS 13.3, *) { - configuration.preferences.shouldPrintBackgrounds = settings.shouldPrintBackgrounds - } - } - } - - public func prepareAndAddUserScripts() -> Void { - if windowId != nil { - // The new created window webview has the same WKWebViewConfiguration variable reference. - // So, we cannot set another WKWebViewConfiguration for it unfortunately! - // This is a limitation of the official WebKit API. - return - } - configuration.userContentController.initialize() - - if javaScriptBridgeEnabled { - let pluginScriptsOriginAllowList = settings?.pluginScriptsOriginAllowList - let pluginScriptsForMainFrameOnly = settings?.pluginScriptsForMainFrameOnly ?? true - - let javaScriptBridgeOriginAllowList = settings?.javaScriptBridgeOriginAllowList ?? pluginScriptsOriginAllowList - let javaScriptBridgeForMainFrameOnly = settings?.javaScriptBridgeForMainFrameOnly ?? pluginScriptsForMainFrameOnly - - configuration.userContentController.addPluginScript(PromisePolyfillJS.PROMISE_POLYFILL_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList, forMainFrameOnly: pluginScriptsForMainFrameOnly)) - configuration.userContentController.addPluginScript(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT(expectedBridgeSecret: exceptedBridgeSecret, allowedOriginRules: javaScriptBridgeOriginAllowList, forMainFrameOnly: javaScriptBridgeForMainFrameOnly)) - configuration.userContentController.addPluginScript(ConsoleLogJS.CONSOLE_LOG_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - configuration.userContentController.addPluginScript(PrintJS.PRINT_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList, forMainFrameOnly: pluginScriptsForMainFrameOnly)) - configuration.userContentController.addPluginScript(OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - configuration.userContentController.addPluginScript(OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - configuration.userContentController.addPluginScript(FindElementsAtPointJS.FIND_ELEMENTS_AT_POINT_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - configuration.userContentController.addPluginScript(FindTextHighlightJS.FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - configuration.userContentController.addPluginScript(OriginalViewPortMetaTagContentJS.ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - configuration.userContentController.addPluginScript(OnScrollChangedJS.ON_SCROLL_CHANGED_EVENT_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - if let settings = settings { - interceptOnlyAsyncAjaxRequestsPluginScript = InterceptAjaxRequestJS.createInterceptOnlyAsyncAjaxRequestsPluginScript(onlyAsync: settings.interceptOnlyAsyncAjaxRequests, - allowedOriginRules: pluginScriptsOriginAllowList, forMainFrameOnly: pluginScriptsForMainFrameOnly) - if settings.useShouldInterceptAjaxRequest { - if let interceptOnlyAsyncAjaxRequestsPluginScript = interceptOnlyAsyncAjaxRequestsPluginScript { - configuration.userContentController.addPluginScript(interceptOnlyAsyncAjaxRequestsPluginScript) - } - configuration.userContentController.addPluginScript(InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList, - forMainFrameOnly: pluginScriptsForMainFrameOnly, - initialUseOnAjaxReadyStateChange: settings.useOnAjaxReadyStateChange, - initialUseOnAjaxProgress: settings.useOnAjaxProgress)) - } - if settings.useShouldInterceptFetchRequest { - configuration.userContentController.addPluginScript(InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList, forMainFrameOnly: pluginScriptsForMainFrameOnly)) - } - if settings.useOnLoadResource { - configuration.userContentController.addPluginScript(OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList, forMainFrameOnly: pluginScriptsForMainFrameOnly)) - } - if !settings.supportZoom { - configuration.userContentController.addPluginScript(SupportZoomJS.NOT_SUPPORT_ZOOM_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - } else if settings.enableViewportScale { - configuration.userContentController.addPluginScript(EnableViewportScaleJS.ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT(allowedOriginRules: pluginScriptsOriginAllowList)) - } - } - } - configuration.userContentController.addUserOnlyScripts(initialUserScripts) - configuration.userContentController.sync(scriptMessageHandler: self) - } - - public static func preWKWebViewConfiguration(settings: InAppWebViewSettings?) -> WKWebViewConfiguration { - let configuration = WKWebViewConfiguration() - // initialzie WKUserContentController here to fix possible "undefined is not an object (evaluating 'window.webkit.messageHandlers')" javascript error - configuration.userContentController = WKUserContentController() - configuration.processPool = WKProcessPoolManager.sharedProcessPool - - if let settings = settings { - configuration.suppressesIncrementalRendering = settings.suppressesIncrementalRendering - - if settings.allowUniversalAccessFromFileURLs { - configuration.setValue(settings.allowUniversalAccessFromFileURLs, forKey: "allowUniversalAccessFromFileURLs") - } - - if settings.allowFileAccessFromFileURLs { - configuration.preferences.setValue(settings.allowFileAccessFromFileURLs, forKey: "allowFileAccessFromFileURLs") - } - - if settings.incognito { - configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent() - } else if settings.cacheEnabled { - configuration.websiteDataStore = WKWebsiteDataStore.default() - } - if !settings.applicationNameForUserAgent.isEmpty { - if let applicationNameForUserAgent = configuration.applicationNameForUserAgent { - configuration.applicationNameForUserAgent = applicationNameForUserAgent + " " + settings.applicationNameForUserAgent - } - } - - if #available(macOS 10.12, *) { - configuration.mediaTypesRequiringUserActionForPlayback = settings.mediaPlaybackRequiresUserGesture ? .all : [] - } - - if #available(macOS 10.13, *) { - for scheme in settings.resourceCustomSchemes { - configuration.setURLSchemeHandler(CustomSchemeHandler(), forURLScheme: scheme) - } - if settings.sharedCookiesEnabled { - // More info to sending cookies with WKWebView - // https://stackoverflow.com/questions/26573137/can-i-set-the-cookies-to-be-used-by-a-wkwebview/26577303#26577303 - // Set Cookies in iOS 11 and above, initialize websiteDataStore before setting cookies - // See also https://forums.developer.apple.com/thread/97194 - // check if websiteDataStore has not been initialized before - if(!settings.incognito && !settings.cacheEnabled) { - configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent() - } - for cookie in HTTPCookieStorage.shared.cookies ?? [] { - configuration.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil) - } - } - } - - if #available(macOS 11.0, *) { - configuration.limitsNavigationsToAppBoundDomains = settings.limitsNavigationsToAppBoundDomains - } - - if #available(macOS 11.3, *) { - configuration.upgradeKnownHostsToHTTPS = settings.upgradeKnownHostsToHTTPS - } - } - - return configuration - } - - override public func observeValue(forKeyPath keyPath: String?, of object: Any?, - change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { - if keyPath == #keyPath(WKWebView.estimatedProgress) { - initializeWindowIdJS() - let progress = Int(estimatedProgress * 100) - channelDelegate?.onProgressChanged(progress: progress) - inAppBrowserDelegate?.didChangeProgress(progress: estimatedProgress) - } else if keyPath == #keyPath(WKWebView.url) && change?[.newKey] is URL { - initializeWindowIdJS() - let newUrl = change?[NSKeyValueChangeKey.newKey] as? URL - channelDelegate?.onUpdateVisitedHistory(url: newUrl?.absoluteString, isReload: nil) - inAppBrowserDelegate?.didUpdateVisitedHistory(url: newUrl) - } else if keyPath == #keyPath(WKWebView.title) && change?[.newKey] is String { - let newTitle = change?[.newKey] as? String - channelDelegate?.onTitleChanged(title: newTitle) - inAppBrowserDelegate?.didChangeTitle(title: newTitle) - } - else { - if #available(macOS 12.0, *) { - if keyPath == #keyPath(WKWebView.cameraCaptureState) || keyPath == #keyPath(WKWebView.microphoneCaptureState) { - var oldState: WKMediaCaptureState? = nil - if let oldValue = change?[.oldKey] as? Int { - oldState = WKMediaCaptureState.init(rawValue: oldValue) - } - var newState: WKMediaCaptureState? = nil - if let newValue = change?[.newKey] as? Int { - newState = WKMediaCaptureState.init(rawValue: newValue) - } - if oldState != newState { - if keyPath == #keyPath(WKWebView.cameraCaptureState) { - channelDelegate?.onCameraCaptureStateChanged(oldState: oldState, newState: newState) - } else { - channelDelegate?.onMicrophoneCaptureStateChanged(oldState: oldState, newState: newState) - } - } - } - } - if #available(macOS 13.0, *) { - if keyPath == #keyPath(WKWebView.fullscreenState) { - if fullscreenState == .enteringFullscreen && !inFullscreen { - channelDelegate?.onEnterFullscreen() - inFullscreen = true - } else if fullscreenState == .exitingFullscreen && inFullscreen { - fullscreenWindow = nil - channelDelegate?.onExitFullscreen() - inFullscreen = false - } - } - } - } - } - - public func initializeWindowIdJS() { - if let windowId = windowId { - if #available(macOS 11.0, *) { - let contentWorlds = configuration.userContentController.getContentWorlds(with: windowId) - for contentWorld in contentWorlds { - let source = WindowIdJS.WINDOW_ID_INITIALIZE_JS_SOURCE().replacingOccurrences(of: PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, with: String(windowId)) - evaluateJavascript(source: source, contentWorld: contentWorld) - } - } else { - let source = WindowIdJS.WINDOW_ID_INITIALIZE_JS_SOURCE().replacingOccurrences(of: PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, with: String(windowId)) - evaluateJavascript(source: source) - } - } - } - - public func goBackOrForward(steps: Int) { - if canGoBackOrForward(steps: steps) { - if (steps > 0) { - let index = steps - 1 - go(to: self.backForwardList.forwardList[index]) - } - else if (steps < 0){ - let backListLength = self.backForwardList.backList.count - let index = backListLength + steps - go(to: self.backForwardList.backList[index]) - } - } - } - - public func canGoBackOrForward(steps: Int) -> Bool { - let currentIndex = self.backForwardList.backList.count - return (steps >= 0) - ? steps <= self.backForwardList.forwardList.count - : currentIndex + steps >= 0 - } - - @available(macOS 10.13, *) - public func takeScreenshot (with: [String: Any?]?, completionHandler: @escaping (_ screenshot: Data?) -> Void) { - var snapshotConfiguration: WKSnapshotConfiguration? = nil - if let with = with { - snapshotConfiguration = WKSnapshotConfiguration() - if let rect = with["rect"] as? [String: Double] { - snapshotConfiguration!.rect = CGRect.fromMap(map: rect) - } - if let snapshotWidth = with["snapshotWidth"] as? Double { - snapshotConfiguration!.snapshotWidth = NSNumber(value: snapshotWidth) - } - if #available(macOS 10.15, *), let afterScreenUpdates = with["afterScreenUpdates"] as? Bool { - snapshotConfiguration!.afterScreenUpdates = afterScreenUpdates - } - } - takeSnapshot(with: snapshotConfiguration, completionHandler: {(image, error) -> Void in - var imageData: Data? = nil - if let screenshot = image, let cgImage = screenshot.cgImage(forProposedRect: nil, context: nil, hints: nil) { - let newRep = NSBitmapImageRep(cgImage: cgImage) - if let with = with { - switch with["compressFormat"] as! String { - case "JPEG": - let quality = Float(with["quality"] as! Int) / 100 - imageData = newRep.representation(using: .jpeg, properties: [ - NSBitmapImageRep.PropertyKey.compressionFactor:quality]) - break - case "PNG": - imageData = newRep.representation(using: .png, properties: [:]) - break - default: - imageData = newRep.representation(using: .png, properties: [:]) - } - } - else { - imageData = newRep.representation(using: .png, properties: [:]) - } - } - completionHandler(imageData) - }) - } - - @available(macOS 11.0, *) - public func createPdf (configuration: [String: Any?]?, completionHandler: @escaping (_ pdf: Data?) -> Void) { - let pdfConfiguration: WKPDFConfiguration = .init() - if let configuration = configuration { - if let rect = configuration["rect"] as? [String: Double] { - pdfConfiguration.rect = CGRect.fromMap(map: rect) - } - } - createPDF(configuration: pdfConfiguration) { (result) in - switch (result) { - case .success(let data): - completionHandler(data) - return - case .failure(let error): - print(error.localizedDescription) - completionHandler(nil) - return - } - } - } - - @available(macOS 11.0, *) - public func createWebArchiveData (dataCompletionHandler: @escaping (_ webArchiveData: Data?) -> Void) { - createWebArchiveData(completionHandler: { (result) in - switch (result) { - case .success(let data): - dataCompletionHandler(data) - return - case .failure(let error): - print(error.localizedDescription) - dataCompletionHandler(nil) - return - } - }) - } - - @available(macOS 11.0, *) - public func saveWebArchive (filePath: String, autoname: Bool, completionHandler: @escaping (_ path: String?) -> Void) { - createWebArchiveData(dataCompletionHandler: { (webArchiveData) in - if let webArchiveData = webArchiveData { - var localUrl = URL(fileURLWithPath: filePath) - if autoname { - if let url = self.url { - // tries to mimic Android saveWebArchive method - let invalidCharacters = CharacterSet(charactersIn: "\\/:*?\"<>|") - .union(.newlines) - .union(.illegalCharacters) - .union(.controlCharacters) - - let currentPageUrlFileName = url.path - .components(separatedBy: invalidCharacters) - .joined(separator: "") - - let fullPath = filePath + "/" + currentPageUrlFileName + ".webarchive" - localUrl = URL(fileURLWithPath: fullPath) - } else { - completionHandler(nil) - return - } - } - do { - try webArchiveData.write(to: localUrl) - completionHandler(localUrl.path) - } catch { - // Catch any errors - print(error.localizedDescription) - completionHandler(nil) - } - } else { - completionHandler(nil) - } - }) - } - - public func loadUrl(urlRequest: URLRequest, allowingReadAccessTo: URL?) { - let url = urlRequest.url! - - if let allowingReadAccessTo = allowingReadAccessTo, url.scheme == "file", allowingReadAccessTo.scheme == "file" { - loadFileURL(url, allowingReadAccessTo: allowingReadAccessTo) - } else { - load(urlRequest) - } - } - - public func postUrl(url: URL, postData: Data) { - var request = URLRequest(url: url) - - request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") - request.httpMethod = "POST" - request.httpBody = postData - load(request) - } - - public func loadData(data: String, mimeType: String, encoding: String, baseUrl: URL, allowingReadAccessTo: URL?) { - if let allowingReadAccessTo = allowingReadAccessTo, baseUrl.scheme == "file", allowingReadAccessTo.scheme == "file" { - loadFileURL(baseUrl, allowingReadAccessTo: allowingReadAccessTo) - } - load(data.data(using: .utf8)!, mimeType: mimeType, characterEncodingName: encoding, baseURL: baseUrl) - } - - public func loadFile(assetFilePath: String) throws { - let assetURL = try Util.getUrlAsset(assetFilePath: assetFilePath) - let urlRequest = URLRequest(url: assetURL) - loadUrl(urlRequest: urlRequest, allowingReadAccessTo: nil) - } - - func setSettings(newSettings: InAppWebViewSettings, newSettingsMap: [String: Any]) { - - if newSettingsMap["alpha"] != nil, settings?.alpha != newSettings.alpha, let viewAlpha = newSettings.alpha { - alphaValue = CGFloat(viewAlpha) - } - - if (newSettingsMap["incognito"] != nil && settings?.incognito != newSettings.incognito && newSettings.incognito) { - configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent() - } else if (newSettingsMap["cacheEnabled"] != nil && settings?.cacheEnabled != newSettings.cacheEnabled && newSettings.cacheEnabled) { - configuration.websiteDataStore = WKWebsiteDataStore.default() - } - - if #available(macOS 10.13, *) { - if (newSettingsMap["sharedCookiesEnabled"] != nil && settings?.sharedCookiesEnabled != newSettings.sharedCookiesEnabled && newSettings.sharedCookiesEnabled) { - if(!newSettings.incognito && !newSettings.cacheEnabled) { - configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent() - } - for cookie in HTTPCookieStorage.shared.cookies ?? [] { - configuration.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil) - } - } - } - - if newSettingsMap["enableViewportScale"] != nil && settings?.enableViewportScale != newSettings.enableViewportScale { - if !newSettings.enableViewportScale { - if configuration.userContentController.containsPluginScript(with: EnableViewportScaleJS.ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT_GROUP_NAME) { - configuration.userContentController.removePluginScripts(with: EnableViewportScaleJS.ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT_GROUP_NAME, shouldAddPreviousScripts: false) - evaluateJavaScript(EnableViewportScaleJS.NOT_ENABLE_VIEWPORT_SCALE_JS_SOURCE()) - } - } else { - evaluateJavaScript(EnableViewportScaleJS.ENABLE_VIEWPORT_SCALE_JS_SOURCE) - if javaScriptBridgeEnabled { - configuration.userContentController.addPluginScript(EnableViewportScaleJS.ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT(allowedOriginRules: newSettings.pluginScriptsOriginAllowList)) - } - } - } - - if newSettingsMap["supportZoom"] != nil && settings?.supportZoom != newSettings.supportZoom { - if newSettings.supportZoom { - if configuration.userContentController.containsPluginScript(with: SupportZoomJS.NOT_SUPPORT_ZOOM_JS_PLUGIN_SCRIPT_GROUP_NAME) { - configuration.userContentController.removePluginScripts(with: SupportZoomJS.NOT_SUPPORT_ZOOM_JS_PLUGIN_SCRIPT_GROUP_NAME, shouldAddPreviousScripts: false) - evaluateJavaScript(SupportZoomJS.SUPPORT_ZOOM_JS_SOURCE()) - } - } else { - evaluateJavaScript(SupportZoomJS.NOT_SUPPORT_ZOOM_JS_SOURCE) - if javaScriptBridgeEnabled { - configuration.userContentController.addPluginScript(SupportZoomJS.NOT_SUPPORT_ZOOM_JS_PLUGIN_SCRIPT(allowedOriginRules: newSettings.pluginScriptsOriginAllowList)) - } - } - } - - if newSettingsMap["useOnLoadResource"] != nil && settings?.useOnLoadResource != newSettings.useOnLoadResource { - if javaScriptBridgeEnabled { - enablePluginScriptAtRuntime(flagVariable: OnLoadResourceJS.FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE(), - enable: newSettings.useOnLoadResource, - pluginScript: OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT(allowedOriginRules: newSettings.pluginScriptsOriginAllowList, - forMainFrameOnly: newSettings.pluginScriptsForMainFrameOnly)) - } - } - - if newSettingsMap["useShouldInterceptAjaxRequest"] != nil && settings?.useShouldInterceptAjaxRequest != newSettings.useShouldInterceptAjaxRequest { - if javaScriptBridgeEnabled { - enablePluginScriptAtRuntime(flagVariable: InterceptAjaxRequestJS.FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE(), - enable: newSettings.useShouldInterceptAjaxRequest, - pluginScript: InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT(allowedOriginRules: newSettings.pluginScriptsOriginAllowList, - forMainFrameOnly: newSettings.pluginScriptsForMainFrameOnly, - initialUseOnAjaxReadyStateChange: newSettings.useOnAjaxReadyStateChange, - initialUseOnAjaxProgress: newSettings.useOnAjaxProgress)) - } - } - - if newSettingsMap["useOnAjaxReadyStateChange"] != nil && settings?.useOnAjaxReadyStateChange != newSettings.useOnAjaxReadyStateChange { - if javaScriptBridgeEnabled { - evaluateJavaScript("\(InterceptAjaxRequestJS.FLAG_VARIABLE_FOR_ON_AJAX_READY_STATE_CHANGE()) = \(newSettings.useOnAjaxReadyStateChange);") - } - } - - if newSettingsMap["useOnAjaxProgress"] != nil && settings?.useOnAjaxProgress != newSettings.useOnAjaxProgress { - if javaScriptBridgeEnabled { - evaluateJavaScript("\(InterceptAjaxRequestJS.FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS()) = \(newSettings.useOnAjaxProgress);") - } - } - - if newSettingsMap["interceptOnlyAsyncAjaxRequests"] != nil && settings?.interceptOnlyAsyncAjaxRequests != newSettings.interceptOnlyAsyncAjaxRequests { - if let interceptOnlyAsyncAjaxRequestsPluginScript = interceptOnlyAsyncAjaxRequestsPluginScript { - if javaScriptBridgeEnabled { - enablePluginScriptAtRuntime(flagVariable: InterceptAjaxRequestJS.FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE(), - enable: newSettings.interceptOnlyAsyncAjaxRequests, - pluginScript: interceptOnlyAsyncAjaxRequestsPluginScript) - } - } - } - - if newSettingsMap["useShouldInterceptFetchRequest"] != nil && settings?.useShouldInterceptFetchRequest != newSettings.useShouldInterceptFetchRequest { - if javaScriptBridgeEnabled { - enablePluginScriptAtRuntime(flagVariable: InterceptFetchRequestJS.FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE(), - enable: newSettings.useShouldInterceptFetchRequest, - pluginScript: InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT(allowedOriginRules: newSettings.pluginScriptsOriginAllowList, - forMainFrameOnly: newSettings.pluginScriptsForMainFrameOnly)) - } - } - - if newSettingsMap["mediaPlaybackRequiresUserGesture"] != nil && settings?.mediaPlaybackRequiresUserGesture != newSettings.mediaPlaybackRequiresUserGesture { - if #available(macOS 10.12, *) { - configuration.mediaTypesRequiringUserActionForPlayback = (newSettings.mediaPlaybackRequiresUserGesture) ? .all : [] - } - } - - if newSettingsMap["suppressesIncrementalRendering"] != nil && settings?.suppressesIncrementalRendering != newSettings.suppressesIncrementalRendering { - configuration.suppressesIncrementalRendering = newSettings.suppressesIncrementalRendering - } - - if newSettingsMap["allowsBackForwardNavigationGestures"] != nil && settings?.allowsBackForwardNavigationGestures != newSettings.allowsBackForwardNavigationGestures { - allowsBackForwardNavigationGestures = newSettings.allowsBackForwardNavigationGestures - } - - if newSettingsMap["javaScriptCanOpenWindowsAutomatically"] != nil && settings?.javaScriptCanOpenWindowsAutomatically != newSettings.javaScriptCanOpenWindowsAutomatically { - configuration.preferences.javaScriptCanOpenWindowsAutomatically = newSettings.javaScriptCanOpenWindowsAutomatically - } - - if newSettingsMap["minimumFontSize"] != nil && settings?.minimumFontSize != newSettings.minimumFontSize { - configuration.preferences.minimumFontSize = CGFloat(newSettings.minimumFontSize) - } - - if #available(macOS 10.15, *) { - if newSettingsMap["isFraudulentWebsiteWarningEnabled"] != nil && settings?.isFraudulentWebsiteWarningEnabled != newSettings.isFraudulentWebsiteWarningEnabled { - configuration.preferences.isFraudulentWebsiteWarningEnabled = newSettings.isFraudulentWebsiteWarningEnabled - } - if newSettingsMap["preferredContentMode"] != nil && settings?.preferredContentMode != newSettings.preferredContentMode { - configuration.defaultWebpagePreferences.preferredContentMode = WKWebpagePreferences.ContentMode(rawValue: newSettings.preferredContentMode)! - } - } - - if newSettingsMap["allowsLinkPreview"] != nil && settings?.allowsLinkPreview != newSettings.allowsLinkPreview { - allowsLinkPreview = newSettings.allowsLinkPreview - } - if newSettingsMap["allowsAirPlayForMediaPlayback"] != nil && settings?.allowsAirPlayForMediaPlayback != newSettings.allowsAirPlayForMediaPlayback { - configuration.allowsAirPlayForMediaPlayback = newSettings.allowsAirPlayForMediaPlayback - } - if newSettingsMap["applicationNameForUserAgent"] != nil && settings?.applicationNameForUserAgent != newSettings.applicationNameForUserAgent && newSettings.applicationNameForUserAgent != "" { - configuration.applicationNameForUserAgent = newSettings.applicationNameForUserAgent - } - if newSettingsMap["userAgent"] != nil && settings?.userAgent != newSettings.userAgent && newSettings.userAgent != "" { - customUserAgent = newSettings.userAgent - } - - if newSettingsMap["allowUniversalAccessFromFileURLs"] != nil && settings?.allowUniversalAccessFromFileURLs != newSettings.allowUniversalAccessFromFileURLs { - configuration.setValue(newSettings.allowUniversalAccessFromFileURLs, forKey: "allowUniversalAccessFromFileURLs") - } - - if newSettingsMap["allowFileAccessFromFileURLs"] != nil && settings?.allowFileAccessFromFileURLs != newSettings.allowFileAccessFromFileURLs { - configuration.preferences.setValue(newSettings.allowFileAccessFromFileURLs, forKey: "allowFileAccessFromFileURLs") - } - - if newSettingsMap["clearCache"] != nil && newSettings.clearCache { - clearCache() - } - - if newSettingsMap["javaScriptEnabled"] != nil && settings?.javaScriptEnabled != newSettings.javaScriptEnabled { - configuration.preferences.javaScriptEnabled = newSettings.javaScriptEnabled - } - - if #available(macOS 11.0, *) { - if settings?.mediaType != newSettings.mediaType { - mediaType = newSettings.mediaType - } - - if newSettingsMap["pageZoom"] != nil && settings?.pageZoom != newSettings.pageZoom { - pageZoom = CGFloat(newSettings.pageZoom) - } - - if newSettingsMap["limitsNavigationsToAppBoundDomains"] != nil && settings?.limitsNavigationsToAppBoundDomains != newSettings.limitsNavigationsToAppBoundDomains { - configuration.limitsNavigationsToAppBoundDomains = newSettings.limitsNavigationsToAppBoundDomains - } - - if newSettingsMap["javaScriptEnabled"] != nil && settings?.javaScriptEnabled != newSettings.javaScriptEnabled { - configuration.defaultWebpagePreferences.allowsContentJavaScript = newSettings.javaScriptEnabled - } - } - - if #available(macOS 10.13, *), newSettingsMap["contentBlockers"] != nil { - configuration.userContentController.removeAllContentRuleLists() - let contentBlockers = newSettings.contentBlockers - if contentBlockers.count > 0 { - do { - let jsonData = try JSONSerialization.data(withJSONObject: contentBlockers, options: []) - let blockRules = String(data: jsonData, encoding: .utf8) - WKContentRuleListStore.default().compileContentRuleList( - forIdentifier: "ContentBlockingRules", - encodedContentRuleList: blockRules) { (contentRuleList, error) in - if let error = error { - print(error.localizedDescription) - return - } - self.configuration.userContentController.add(contentRuleList!) - } - } catch { - print(error.localizedDescription) - } - } - } - - if #available(macOS 11.3, *) { - if newSettingsMap["upgradeKnownHostsToHTTPS"] != nil && settings?.upgradeKnownHostsToHTTPS != newSettings.upgradeKnownHostsToHTTPS { - configuration.upgradeKnownHostsToHTTPS = newSettings.upgradeKnownHostsToHTTPS - } - if newSettingsMap["isTextInteractionEnabled"] != nil && settings?.isTextInteractionEnabled != newSettings.isTextInteractionEnabled { - configuration.preferences.isTextInteractionEnabled = newSettings.isTextInteractionEnabled - } - } - - if #available(macOS 12.0, *) { - if newSettingsMap["underPageBackgroundColor"] != nil, settings?.underPageBackgroundColor != newSettings.underPageBackgroundColor, - let underPageBackgroundColor = newSettings.underPageBackgroundColor, !underPageBackgroundColor.isEmpty { - self.underPageBackgroundColor = NSColor(hexString: underPageBackgroundColor) - } - } - if #available(macOS 12.3, *) { - if newSettingsMap["isSiteSpecificQuirksModeEnabled"] != nil, settings?.isSiteSpecificQuirksModeEnabled != newSettings.isSiteSpecificQuirksModeEnabled { - configuration.preferences.isSiteSpecificQuirksModeEnabled = newSettings.isSiteSpecificQuirksModeEnabled - } - } - if #available(macOS 13.3, *) { - if newSettingsMap["isInspectable"] != nil, settings?.isInspectable != newSettings.isInspectable { - isInspectable = newSettings.isInspectable - } - if newSettingsMap["shouldPrintBackgrounds"] != nil, settings?.shouldPrintBackgrounds != newSettings.shouldPrintBackgrounds { - configuration.preferences.shouldPrintBackgrounds = newSettings.shouldPrintBackgrounds - } - } - - self.settings = newSettings - } - - func getSettings() -> [String: Any?]? { - if (self.settings == nil) { - return nil - } - return self.settings!.getRealSettings(obj: self) - } - - public func enablePluginScriptAtRuntime(flagVariable: String, enable: Bool, pluginScript: PluginScript) { - evaluateJavascript(source: flagVariable) { (alreadyLoaded) in - if let alreadyLoaded = alreadyLoaded as? Bool, alreadyLoaded { - let enableSource = "\(flagVariable) = \(enable);" - if #available(macOS 11.0, *), pluginScript.requiredInAllContentWorlds { - for contentWorld in self.configuration.userContentController.contentWorlds { - self.evaluateJavaScript(enableSource, frame: nil, contentWorld: contentWorld, completionHandler: nil) - } - } else { - self.evaluateJavaScript(enableSource, completionHandler: nil) - } - if !enable { - self.configuration.userContentController.removePluginScripts(with: pluginScript.groupName!) - } - } - else if enable { - if #available(macOS 11.0, *), pluginScript.requiredInAllContentWorlds { - for contentWorld in self.configuration.userContentController.contentWorlds { - self.evaluateJavaScript(pluginScript.source, frame: nil, contentWorld: contentWorld, completionHandler: nil) - self.configuration.userContentController.addPluginScript(pluginScript) - } - } else { - self.evaluateJavaScript(pluginScript.source, completionHandler: nil) - self.configuration.userContentController.addPluginScript(pluginScript) - } - self.configuration.userContentController.sync(scriptMessageHandler: self) - } - } - } - - @available(*, deprecated, message: "Use InAppWebViewManager.clearAllCache instead.") - public func clearCache() { - let date = NSDate(timeIntervalSince1970: 0) - WKWebsiteDataStore.default().removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), modifiedSince: date as Date, completionHandler:{ }) - } - - public func injectDeferredObject(source: String, withWrapper jsWrapper: String?, completionHandler: ((Any?) -> Void)? = nil) { - var jsToInject = source - if let wrapper = jsWrapper { - let jsonData: Data? = try? JSONSerialization.data(withJSONObject: [source], options: []) - let sourceArrayString = String(data: jsonData!, encoding: .utf8) - let sourceString: String? = (sourceArrayString! as NSString).substring(with: NSRange(location: 1, length: (sourceArrayString?.count ?? 0) - 2)) - jsToInject = String(format: wrapper, sourceString!) - } - - evaluateJavaScript(jsToInject) { (value, error) in - guard let completionHandler = completionHandler else { - return - } - - if let error = error { - let userInfo = (error as NSError).userInfo - let errorMessage = userInfo["WKJavaScriptExceptionMessage"] ?? - userInfo["NSLocalizedDescription"] as? String ?? - error.localizedDescription - self.channelDelegate?.onConsoleMessage(message: String(describing: errorMessage), messageLevel: 3) - } - - if value == nil { - completionHandler(nil) - return - } - - completionHandler(value) - } - } - - @available(macOS 11.0, *) - public func injectDeferredObject(source: String, contentWorld: WKContentWorld, withWrapper jsWrapper: String?, completionHandler: ((Any?) -> Void)? = nil) { - var jsToInject = source - if let wrapper = jsWrapper { - let jsonData: Data? = try? JSONSerialization.data(withJSONObject: [source], options: []) - let sourceArrayString = String(data: jsonData!, encoding: .utf8) - let sourceString: String? = (sourceArrayString! as NSString).substring(with: NSRange(location: 1, length: (sourceArrayString?.count ?? 0) - 2)) - jsToInject = String(format: wrapper, sourceString!) - } - - jsToInject = configuration.userContentController.generateCodeForScriptEvaluation(scriptMessageHandler: self, source: jsToInject, contentWorld: contentWorld) - - evaluateJavaScript(jsToInject, frame: nil, contentWorld: contentWorld) { (evalResult) in - guard let completionHandler = completionHandler else { - return - } - - switch (evalResult) { - case .success(let value): - completionHandler(value) - return - case .failure(let error): - let userInfo = (error as NSError).userInfo - let errorMessage = userInfo["WKJavaScriptExceptionMessage"] ?? - userInfo["NSLocalizedDescription"] as? String ?? - error.localizedDescription - self.channelDelegate?.onConsoleMessage(message: String(describing: errorMessage), messageLevel: 3) - break - } - - completionHandler(nil) - } - } - -#if compiler(>=6.0) - public override func evaluateJavaScript(_ javaScriptString: String, completionHandler: (@MainActor @Sendable (Any?, (any Error)?) -> Void)? = nil) { - super.evaluateJavaScript(javaScriptString, completionHandler: completionHandler) - } -#else - public override func evaluateJavaScript(_ javaScriptString: String, completionHandler: ((Any?, Error?) -> Void)? = nil) { - super.evaluateJavaScript(javaScriptString, completionHandler: completionHandler) - } -#endif - - @available(macOS 11.0, *) - public func evaluateJavaScript(_ javaScript: String, frame: WKFrameInfo? = nil, contentWorld: WKContentWorld, completionHandler: ((Result) -> Void)? = nil) { - super.evaluateJavaScript(javaScript, in: frame, in: contentWorld, completionHandler: completionHandler) - } - - public func evaluateJavascript(source: String, completionHandler: ((Any?) -> Void)? = nil) { - injectDeferredObject(source: source, withWrapper: nil, completionHandler: completionHandler) - } - - @available(macOS 11.0, *) - public func evaluateJavascript(source: String, contentWorld: WKContentWorld, completionHandler: ((Any?) -> Void)? = nil) { - injectDeferredObject(source: source, contentWorld: contentWorld, withWrapper: nil, completionHandler: completionHandler) - } - - @available(macOS 11.0, *) - public func callAsyncJavaScript(_ functionBody: String, arguments: [String : Any] = [:], frame: WKFrameInfo? = nil, contentWorld: WKContentWorld, completionHandler: ((Result) -> Void)? = nil) { - super.callAsyncJavaScript(functionBody, arguments: arguments, in: frame, in: contentWorld, completionHandler: completionHandler) - } - - @available(macOS 11.0, *) - public func callAsyncJavaScript(functionBody: String, arguments: [String:Any], contentWorld: WKContentWorld, completionHandler: ((Any?) -> Void)? = nil) { - let jsToInject = configuration.userContentController.generateCodeForScriptEvaluation(scriptMessageHandler: self, source: functionBody, contentWorld: contentWorld) - - callAsyncJavaScript(jsToInject, arguments: arguments, frame: nil, contentWorld: contentWorld) { (evalResult) in - guard let completionHandler = completionHandler else { - return - } - - var body: [String: Any?] = [ - "value": nil, - "error": nil - ] - - switch (evalResult) { - case .success(let value): - body["value"] = value - break - case .failure(let error): - let userInfo = (error as NSError).userInfo - body["error"] = userInfo["WKJavaScriptExceptionMessage"] ?? - userInfo["NSLocalizedDescription"] as? String ?? - error.localizedDescription - self.channelDelegate?.onConsoleMessage(message: String(describing: body["error"]), messageLevel: 3) - break - } - - completionHandler(body) - } - } - - public func callAsyncJavaScript(functionBody: String, arguments: [String:Any], completionHandler: ((Any?) -> Void)? = nil) { - var jsToInject = functionBody - - let resultUuid = NSUUID().uuidString - if let completionHandler = completionHandler { - callAsyncJavaScriptBelowMacOS11Results[resultUuid] = completionHandler - } - - var functionArgumentNamesList: [String] = [] - var functionArgumentValuesList: [String] = [] - let keys = arguments.keys - keys.forEach { (key) in - functionArgumentNamesList.append(key) - functionArgumentValuesList.append("obj.\(key)") - } - - let functionArgumentNames = functionArgumentNamesList.joined(separator: ", ") - let functionArgumentValues = functionArgumentValuesList.joined(separator: ", ") - - jsToInject = CallAsyncJavaScriptBelowIOS14WrapperJS.CALL_ASYNC_JAVASCRIPT_BELOW_IOS_14_WRAPPER_JS() - .replacingOccurrences(of: PluginScriptsUtil.VAR_FUNCTION_ARGUMENT_NAMES, with: functionArgumentNames) - .replacingOccurrences(of: PluginScriptsUtil.VAR_FUNCTION_ARGUMENT_VALUES, with: functionArgumentValues) - .replacingOccurrences(of: PluginScriptsUtil.VAR_FUNCTION_ARGUMENTS_OBJ, with: Util.JSONStringify(value: arguments)) - .replacingOccurrences(of: PluginScriptsUtil.VAR_FUNCTION_BODY, with: jsToInject) - .replacingOccurrences(of: PluginScriptsUtil.VAR_RESULT_UUID, with: resultUuid) - - evaluateJavaScript(jsToInject) { (value, error) in - if let error = error { - let userInfo = (error as NSError).userInfo - let errorMessage = userInfo["WKJavaScriptExceptionMessage"] ?? - userInfo["NSLocalizedDescription"] as? String ?? - error.localizedDescription - self.channelDelegate?.onConsoleMessage(message: String(describing: errorMessage), messageLevel: 3) - completionHandler?(nil) - self.callAsyncJavaScriptBelowMacOS11Results.removeValue(forKey: resultUuid) - } - } - } - - public func injectJavascriptFileFromUrl(urlFile: String, scriptHtmlTagAttributes: [String:Any?]?) { - var scriptAttributes = "" - if let scriptHtmlTagAttributes = scriptHtmlTagAttributes { - if let typeAttr = scriptHtmlTagAttributes["type"] as? String { - scriptAttributes += " script.type = '\(typeAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let idAttr = scriptHtmlTagAttributes["id"] as? String { - let scriptIdEscaped = idAttr.replacingOccurrences(of: "\'", with: "\\'") - scriptAttributes += " script.id = '\(scriptIdEscaped)'; " - scriptAttributes += """ - script.onload = function() { - if (window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()) != null) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onInjectedScriptLoaded', '\(scriptIdEscaped)'); - } - }; - """ - scriptAttributes += """ - script.onerror = function() { - if (window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()) != null) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onInjectedScriptError', '\(scriptIdEscaped)'); - } - }; - """ - } - if let asyncAttr = scriptHtmlTagAttributes["async"] as? Bool, asyncAttr { - scriptAttributes += " script.async = true; " - } - if let deferAttr = scriptHtmlTagAttributes["defer"] as? Bool, deferAttr { - scriptAttributes += " script.defer = true; " - } - if let crossOriginAttr = scriptHtmlTagAttributes["crossOrigin"] as? String { - scriptAttributes += " script.crossOrigin = '\(crossOriginAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let integrityAttr = scriptHtmlTagAttributes["integrity"] as? String { - scriptAttributes += " script.integrity = '\(integrityAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let noModuleAttr = scriptHtmlTagAttributes["noModule"] as? Bool, noModuleAttr { - scriptAttributes += " script.noModule = true; " - } - if let nonceAttr = scriptHtmlTagAttributes["nonce"] as? String { - scriptAttributes += " script.nonce = '\(nonceAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let referrerPolicyAttr = scriptHtmlTagAttributes["referrerPolicy"] as? String { - scriptAttributes += " script.referrerPolicy = '\(referrerPolicyAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - } - let jsWrapper = "(function(d) { var script = d.createElement('script'); \(scriptAttributes) script.src = %@; d.body.appendChild(script); })(document);" - injectDeferredObject(source: urlFile, withWrapper: jsWrapper, completionHandler: nil) - } - - public func injectCSSCode(source: String) { - let jsWrapper = "(function(d) { var style = d.createElement('style'); style.innerHTML = %@; d.head.appendChild(style); })(document);" - injectDeferredObject(source: source, withWrapper: jsWrapper, completionHandler: nil) - } - - public func injectCSSFileFromUrl(urlFile: String, cssLinkHtmlTagAttributes: [String:Any?]?) { - var cssLinkAttributes = "" - var alternateStylesheet = "" - if let cssLinkHtmlTagAttributes = cssLinkHtmlTagAttributes { - if let idAttr = cssLinkHtmlTagAttributes["id"] as? String { - cssLinkAttributes += " link.id = '\(idAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let mediaAttr = cssLinkHtmlTagAttributes["media"] as? String { - cssLinkAttributes += " link.media = '\(mediaAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let crossOriginAttr = cssLinkHtmlTagAttributes["crossOrigin"] as? String { - cssLinkAttributes += " link.crossOrigin = '\(crossOriginAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let integrityAttr = cssLinkHtmlTagAttributes["integrity"] as? String { - cssLinkAttributes += " link.integrity = '\(integrityAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let referrerPolicyAttr = cssLinkHtmlTagAttributes["referrerPolicy"] as? String { - cssLinkAttributes += " link.referrerPolicy = '\(referrerPolicyAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - if let disabledAttr = cssLinkHtmlTagAttributes["disabled"] as? Bool, disabledAttr { - cssLinkAttributes += " link.disabled = true; " - } - if let alternateAttr = cssLinkHtmlTagAttributes["alternate"] as? Bool, alternateAttr { - alternateStylesheet = "alternate " - } - if let titleAttr = cssLinkHtmlTagAttributes["title"] as? String { - cssLinkAttributes += " link.title = '\(titleAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " - } - } - let jsWrapper = "(function(d) { var link = d.createElement('link'); link.rel='\(alternateStylesheet)stylesheet', link.type='text/css'; \(cssLinkAttributes) link.href = %@; d.head.appendChild(link); })(document);" - injectDeferredObject(source: urlFile, withWrapper: jsWrapper, completionHandler: nil) - } - - public func getCopyBackForwardList() -> [String: Any] { - let currentList = backForwardList - let currentIndex = currentList.backList.count - var completeList = currentList.backList - if currentList.currentItem != nil { - completeList.append(currentList.currentItem!) - } - completeList.append(contentsOf: currentList.forwardList) - - var history: [[String: Any]] = [] - - for (i, historyItem) in completeList.enumerated() { - var historyItemMap: [String: Any] = [:] - historyItemMap["originalUrl"] = historyItem.initialURL.absoluteString - historyItemMap["title"] = historyItem.title - historyItemMap["url"] = historyItem.url.absoluteString - historyItemMap["index"] = i - historyItemMap["offset"] = i - currentIndex - history.append(historyItemMap) - } - - var result: [String: Any] = [:] - result["list"] = history - result["currentIndex"] = currentIndex - - return result; - } - - @available(macOS 12.0, *) - public func webView(_ webView: WKWebView, - requestMediaCapturePermissionFor origin: WKSecurityOrigin, - initiatedByFrame frame: WKFrameInfo, - type: WKMediaCaptureType, - decisionHandler: @escaping (WKPermissionDecision) -> Void) { - let origin = "\(origin.protocol)://\(origin.host)\(origin.port != 0 ? ":" + String(origin.port) : "")" - let permissionRequest = PermissionRequest(origin: origin, resources: [type.rawValue], frame: frame) - - var decisionHandlerCalled = false - let callback = WebViewChannelDelegate.PermissionRequestCallback() - callback.nonNullSuccess = { (response: PermissionResponse) in - if let action = response.action { - decisionHandlerCalled = true - switch action { - case 1: - decisionHandler(.grant) - break - case 2: - decisionHandler(.prompt) - break - default: - decisionHandler(.deny) - } - return false - } - return true - } - callback.defaultBehaviour = { (response: PermissionResponse?) in - if !decisionHandlerCalled { - decisionHandlerCalled = true - decisionHandler(.deny) - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - if let channelDelegate = channelDelegate { - channelDelegate.onPermissionRequest(request: permissionRequest, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - @available(macOS 10.15, *) - public func webView(_ webView: WKWebView, - decidePolicyFor navigationAction: WKNavigationAction, - preferences: WKWebpagePreferences, - decisionHandler: @escaping (WKNavigationActionPolicy, WKWebpagePreferences) -> Void) { - self.webView(webView, decidePolicyFor: navigationAction, decisionHandler: {(navigationActionPolicy) -> Void in - decisionHandler(navigationActionPolicy, preferences) - }) - } - - @available(macOS 11.3, *) - public func download(_ download: WKDownload, decideDestinationUsing response: URLResponse, suggestedFilename: String, completionHandler: @escaping (URL?) -> Void) { - if let url = response.url, let useOnDownloadStart = settings?.useOnDownloadStart, useOnDownloadStart { - let downloadStartRequest = DownloadStartRequest(url: url.absoluteString, - userAgent: nil, - contentDisposition: nil, - mimeType: response.mimeType, - contentLength: response.expectedContentLength, - suggestedFilename: suggestedFilename, - textEncodingName: response.textEncodingName) - channelDelegate?.onDownloadStarting(request: downloadStartRequest) - } - download.delegate = nil - // cancel the download - completionHandler(nil) - } - - @available(macOS 11.3, *) - public func webView(_ webView: WKWebView, navigationResponse: WKNavigationResponse, didBecome download: WKDownload) { - let response = navigationResponse.response - if let url = response.url, let useOnDownloadStart = settings?.useOnDownloadStart, useOnDownloadStart { - let downloadStartRequest = DownloadStartRequest(url: url.absoluteString, - userAgent: nil, - contentDisposition: nil, - mimeType: response.mimeType, - contentLength: response.expectedContentLength, - suggestedFilename: response.suggestedFilename, - textEncodingName: response.textEncodingName) - channelDelegate?.onDownloadStarting(request: downloadStartRequest) - } - download.delegate = nil - } - - public func webView(_ webView: WKWebView, - decidePolicyFor navigationAction: WKNavigationAction, - decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { - var decisionHandlerCalled = false - let callback = WebViewChannelDelegate.ShouldOverrideUrlLoadingCallback() - callback.nonNullSuccess = { (response: WKNavigationActionPolicy) in - decisionHandlerCalled = true - decisionHandler(response) - return false - } - callback.defaultBehaviour = { (response: WKNavigationActionPolicy?) in - if !decisionHandlerCalled { - decisionHandlerCalled = true - decisionHandler(.allow) - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - let runCallback = { - if let useShouldOverrideUrlLoading = self.settings?.useShouldOverrideUrlLoading, useShouldOverrideUrlLoading, let channelDelegate = self.channelDelegate { - channelDelegate.shouldOverrideUrlLoading(navigationAction: navigationAction, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - if windowId != nil, !windowCreated { - windowBeforeCreatedCallbacks.append(runCallback) - } else { - runCallback() - } - } - - public func webView(_ webView: WKWebView, - decidePolicyFor navigationResponse: WKNavigationResponse, - decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) { - if let response = navigationResponse.response as? HTTPURLResponse, response.statusCode >= 400 { - let request = WebResourceRequest.init(fromWKNavigationResponse: navigationResponse) - let errorResponse = WebResourceResponse.init(fromWKNavigationResponse: navigationResponse) - channelDelegate?.onReceivedHttpError(request: request, errorResponse: errorResponse) - } - - let useOnNavigationResponse = settings?.useOnNavigationResponse - - if useOnNavigationResponse != nil, useOnNavigationResponse! { - var decisionHandlerCalled = false - let callback = WebViewChannelDelegate.NavigationResponseCallback() - callback.nonNullSuccess = { (response: WKNavigationResponsePolicy) in - decisionHandlerCalled = true - decisionHandler(response) - return false - } - callback.defaultBehaviour = { (response: WKNavigationResponsePolicy?) in - if !decisionHandlerCalled { - decisionHandlerCalled = true - decisionHandler(.allow) - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - if let channelDelegate = channelDelegate { - channelDelegate.onNavigationResponse(navigationResponse: navigationResponse, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - if let useOnDownloadStart = settings?.useOnDownloadStart, useOnDownloadStart { - if #available(macOS 11.3, *), !navigationResponse.canShowMIMEType, useOnNavigationResponse == nil || !useOnNavigationResponse! { - decisionHandler(.download) - return - } else { - let mimeType = navigationResponse.response.mimeType - if let url = navigationResponse.response.url, navigationResponse.isForMainFrame { - if url.scheme != "file", mimeType != nil, !mimeType!.starts(with: "text/") { - let downloadStartRequest = DownloadStartRequest(url: url.absoluteString, - userAgent: nil, - contentDisposition: nil, - mimeType: mimeType, - contentLength: navigationResponse.response.expectedContentLength, - suggestedFilename: navigationResponse.response.suggestedFilename, - textEncodingName: navigationResponse.response.textEncodingName) - channelDelegate?.onDownloadStarting(request: downloadStartRequest) - if useOnNavigationResponse == nil || !useOnNavigationResponse! { - decisionHandler(.cancel) - } - return - } - } - } - } - - if useOnNavigationResponse == nil || !useOnNavigationResponse! { - decisionHandler(.allow) - } - } - - public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { - currentOriginalUrl = url - - disposeWebMessageChannels() - initializeWindowIdJS() - - if #available(macOS 11.0, *) { - configuration.userContentController.resetContentWorlds(windowId: windowId) - } - - channelDelegate?.onLoadStart(url: url?.absoluteString) - - inAppBrowserDelegate?.didStartNavigation(url: url) - } - - public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { - initializeWindowIdJS() - - InAppWebView.credentialsProposed = [] - evaluateJavaScript(JavaScriptBridgeJS.PLATFORM_READY_JS_SOURCE, completionHandler: nil) - - channelDelegate?.onLoadStop(url: url?.absoluteString) - - inAppBrowserDelegate?.didFinishNavigation(url: url) - } - - public func webView(_ view: WKWebView, - didFailProvisionalNavigation navigation: WKNavigation!, - withError error: Error) { - webView(view, didFail: navigation, withError: error) - } - - public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { - InAppWebView.credentialsProposed = [] - - var urlError: URL = url ?? URL(string: "about:blank")! - var errorCode = -1 - var errorDescription = "domain=\(error._domain), code=\(error._code), \(error.localizedDescription)" - - if let info = error as? URLError { - if let failingURL = info.failingURL { - urlError = failingURL - } - errorCode = info.code.rawValue - errorDescription = info.localizedDescription - } - else if let info = error._userInfo as? [String: Any] { - if let failingUrl = info[NSURLErrorFailingURLErrorKey] as? URL { - urlError = failingUrl - } - if let failingUrlString = info[NSURLErrorFailingURLStringErrorKey] as? String, - let failingUrl = URL(string: failingUrlString) { - urlError = failingUrl - } - } - - let webResourceRequest = WebResourceRequest(url: urlError, headers: nil) - let webResourceError = WebResourceError(type: errorCode, errorDescription: errorDescription) - - channelDelegate?.onReceivedError(request: webResourceRequest, error: webResourceError) - - inAppBrowserDelegate?.didFailNavigation(url: url, error: error) - } - - public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { - var completionHandlerCalled = false - if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic || - challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodDefault || - challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPDigest || - challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodNegotiate || - challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodNTLM { - let host = challenge.protectionSpace.host - let prot = challenge.protectionSpace.protocol - let realm = challenge.protectionSpace.realm - let port = challenge.protectionSpace.port - - let callback = WebViewChannelDelegate.ReceivedHttpAuthRequestCallback() - callback.nonNullSuccess = { (response: HttpAuthResponse) in - if let action = response.action { - completionHandlerCalled = true - switch action { - case 0: - InAppWebView.credentialsProposed = [] - // used .performDefaultHandling to maintain consistency with Android - // because .cancelAuthenticationChallenge will call webView(_:didFail:withError:) - completionHandler(.performDefaultHandling, nil) - //completionHandler(.cancelAuthenticationChallenge, nil) - break - case 1: - let username = response.username - let password = response.password - let permanentPersistence = response.permanentPersistence - let persistence = (permanentPersistence) ? URLCredential.Persistence.permanent : URLCredential.Persistence.forSession - let credential = URLCredential(user: username, password: password, persistence: persistence) - completionHandler(.useCredential, credential) - break - case 2: - if InAppWebView.credentialsProposed.count == 0 { - for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { - if protectionSpace.host == host && protectionSpace.realm == realm && - protectionSpace.protocol == prot && protectionSpace.port == port { - for credential in credentials { - InAppWebView.credentialsProposed.append(credential.value) - } - break - } - } - } - if InAppWebView.credentialsProposed.count == 0, let credential = challenge.proposedCredential { - InAppWebView.credentialsProposed.append(credential) - } - - if let credential = InAppWebView.credentialsProposed.popLast() { - completionHandler(.useCredential, credential) - } - else { - completionHandler(.performDefaultHandling, nil) - } - break - default: - InAppWebView.credentialsProposed = [] - completionHandler(.performDefaultHandling, nil) - } - return false - } - return true - } - callback.defaultBehaviour = { (response: HttpAuthResponse?) in - if !completionHandlerCalled { - completionHandlerCalled = true - completionHandler(.performDefaultHandling, nil) - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - let runCallback = { - if let channelDelegate = self.channelDelegate { - channelDelegate.onReceivedHttpAuthRequest(challenge: HttpAuthenticationChallenge(fromChallenge: challenge), callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - if windowId != nil, !windowCreated { - windowBeforeCreatedCallbacks.append(runCallback) - } else { - runCallback() - } - } - else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { - guard let serverTrust = challenge.protectionSpace.serverTrust else { - completionHandler(.performDefaultHandling, nil) - return - } - - if let scheme = challenge.protectionSpace.protocol, scheme == "https" { - // workaround for ProtectionSpace SSL Certificate - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global().async { - if let sslCertificate = challenge.protectionSpace.sslCertificate { - DispatchQueue.main.async { - InAppWebView.sslCertificatesMap[challenge.protectionSpace.host] = sslCertificate - } - } - } - } - - let callback = WebViewChannelDelegate.ReceivedServerTrustAuthRequestCallback() - callback.nonNullSuccess = { (response: ServerTrustAuthResponse) in - if let action = response.action { - completionHandlerCalled = true - switch action { - case 0: - InAppWebView.credentialsProposed = [] - completionHandler(.cancelAuthenticationChallenge, nil) - break - case 1: - // workaround for https://github.com/pichillilorenzo/flutter_inappwebview/issues/1924 - DispatchQueue.global().async { - let exceptions = SecTrustCopyExceptions(serverTrust) - SecTrustSetExceptions(serverTrust, exceptions) - let credential = URLCredential(trust: serverTrust) - completionHandler(.useCredential, credential) - } - break - default: - InAppWebView.credentialsProposed = [] - completionHandler(.performDefaultHandling, nil) - } - return false - } - return true - } - callback.defaultBehaviour = { (response: ServerTrustAuthResponse?) in - if !completionHandlerCalled { - completionHandlerCalled = true - completionHandler(.performDefaultHandling, nil) - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - let runCallback = { - if let channelDelegate = self.channelDelegate { - channelDelegate.onReceivedServerTrustAuthRequest(challenge: ServerTrustChallenge(fromChallenge: challenge), callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - if windowId != nil, !windowCreated { - windowBeforeCreatedCallbacks.append(runCallback) - } else { - runCallback() - } - } - else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate { - let callback = WebViewChannelDelegate.ReceivedClientCertRequestCallback() - callback.nonNullSuccess = { (response: ClientCertResponse) in - if let action = response.action { - completionHandlerCalled = true - switch action { - case 0: - completionHandler(.cancelAuthenticationChallenge, nil) - break - case 1: - let certificatePath = response.certificatePath - let certificatePassword = response.certificatePassword ?? ""; - - var path: String = certificatePath - do { - path = try Util.getAbsPathAsset(assetFilePath: certificatePath) - } catch {} - - if let PKCS12Data = NSData(contentsOfFile: path), - let identityAndTrust: IdentityAndTrust = self.extractIdentity(PKCS12Data: PKCS12Data, password: certificatePassword) { - let urlCredential: URLCredential = URLCredential( - identity: identityAndTrust.identityRef, - certificates: identityAndTrust.certArray as? [AnyObject], - persistence: URLCredential.Persistence.forSession); - completionHandler(.useCredential, urlCredential) - } else { - completionHandler(.performDefaultHandling, nil) - } - - break - case 2: - completionHandler(.cancelAuthenticationChallenge, nil) - break - default: - completionHandler(.performDefaultHandling, nil) - } - return false - } - return true - } - callback.defaultBehaviour = { (response: ClientCertResponse?) in - if !completionHandlerCalled { - completionHandlerCalled = true - completionHandler(.performDefaultHandling, nil) - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - let runCallback = { - if let channelDelegate = self.channelDelegate { - channelDelegate.onReceivedClientCertRequest(challenge: ClientCertChallenge(fromChallenge: challenge), callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - if windowId != nil, !windowCreated { - windowBeforeCreatedCallbacks.append(runCallback) - } else { - runCallback() - } - } - else { - completionHandler(.performDefaultHandling, nil) - } - } - - struct IdentityAndTrust { - var identityRef: SecIdentity - var trust: SecTrust - var certArray: AnyObject - } - - func extractIdentity(PKCS12Data: NSData, password: String) -> IdentityAndTrust? { - var identityAndTrust: IdentityAndTrust? - var securityError: OSStatus = errSecSuccess - - var importResult: CFArray? = nil - securityError = SecPKCS12Import( - PKCS12Data as NSData, - [kSecImportExportPassphrase as String: password] as NSDictionary, - &importResult - ) - - if securityError == errSecSuccess { - let certItems: CFArray = importResult! as CFArray; - let certItemsArray: Array = certItems as Array - let dict: AnyObject? = certItemsArray.first; - if let certEntry: Dictionary = dict as? Dictionary { - // grab the identity - let identityPointer: AnyObject? = certEntry["identity"] - let secIdentityRef:SecIdentity = (identityPointer as! SecIdentity?)! - // grab the trust - let trustPointer: AnyObject? = certEntry["trust"] - let trustRef:SecTrust = trustPointer as! SecTrust - // grab the cert - let chainPointer: AnyObject? = certEntry["chain"] - identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef, trust: trustRef, certArray: chainPointer!) - } - } else { - print("Security Error: " + securityError.description) - print(SecCopyErrorMessageString(securityError,nil) ?? "") - } - return identityAndTrust; - } - - @available(macOS 10.12, *) - public func webView( - _ webView: WKWebView, - runOpenPanelWith parameters: WKOpenPanelParameters, - initiatedByFrame frame: WKFrameInfo, - completionHandler: @escaping ([URL]?) -> Void - ) { - let openPanel = NSOpenPanel() - currentOpenPanel = openPanel - openPanel.canChooseFiles = true - if #available(macOS 10.13.4, *) { - openPanel.canChooseDirectories = parameters.allowsDirectories - } - openPanel.allowsMultipleSelection = parameters.allowsMultipleSelection - openPanel.begin { (result) in - if result == .OK { - completionHandler(openPanel.urls) - } else { - completionHandler([]) - } - self.currentOpenPanel = nil - } - } - - func createAlertDialog(message: String?, responseMessage: String?, confirmButtonTitle: String?, completionHandler: @escaping () -> Void) { - let title = responseMessage != nil && !responseMessage!.isEmpty ? responseMessage : message - let okButton = confirmButtonTitle != nil && !confirmButtonTitle!.isEmpty ? confirmButtonTitle : NSLocalizedString("Ok", comment: "") - - let alert = NSAlert() - alert.messageText = title ?? "" - alert.alertStyle = .informational - alert.addButton(withTitle: okButton ?? "") - alert.runModal() - completionHandler() - } - - public func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, - initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { - - if (isPausedTimers) { - isPausedTimersCompletionHandler = completionHandler - return - } - - var completionHandlerCalled = false - - let callback = WebViewChannelDelegate.JsAlertCallback() - callback.nonNullSuccess = { (response: JsAlertResponse) in - if response.handledByClient { - completionHandlerCalled = true - let action = response.action ?? 1 - switch action { - case 0: - completionHandler() - break - default: - completionHandler() - } - return false - } - return true - } - callback.defaultBehaviour = { [weak self] (response: JsAlertResponse?) in - if !completionHandlerCalled { - completionHandlerCalled = true - let responseMessage = response?.message - let confirmButtonTitle = response?.confirmButtonTitle - self?.createAlertDialog(message: message, responseMessage: responseMessage, - confirmButtonTitle: confirmButtonTitle, completionHandler: completionHandler) - } - } - callback.error = { (code: String, message: String?, details: Any?) in - if !completionHandlerCalled { - completionHandlerCalled = true - print(code + ", " + (message ?? "")) - completionHandler() - } - } - - if let channelDelegate = channelDelegate { - channelDelegate.onJsAlert(url: frame.request.url, message: message, isMainFrame: frame.isMainFrame, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - func createConfirmDialog(message: String?, responseMessage: String?, confirmButtonTitle: String?, cancelButtonTitle: String?, completionHandler: @escaping (Bool) -> Void) { - let dialogMessage = responseMessage != nil && !responseMessage!.isEmpty ? responseMessage : message - let okButton = confirmButtonTitle != nil && !confirmButtonTitle!.isEmpty ? confirmButtonTitle : NSLocalizedString("Ok", comment: "") - let cancelButton = cancelButtonTitle != nil && !cancelButtonTitle!.isEmpty ? cancelButtonTitle : NSLocalizedString("Cancel", comment: "") - - let alert = NSAlert() - alert.messageText = dialogMessage ?? "" - alert.alertStyle = .informational - alert.addButton(withTitle: okButton ?? "") - alert.addButton(withTitle: cancelButton ?? "") - let res = alert.runModal() - completionHandler(res == .alertFirstButtonReturn) - } - - public func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, - completionHandler: @escaping (Bool) -> Void) { - var completionHandlerCalled = false - - let callback = WebViewChannelDelegate.JsConfirmCallback() - callback.nonNullSuccess = { (response: JsConfirmResponse) in - if response.handledByClient { - completionHandlerCalled = true - let action = response.action ?? 1 - switch action { - case 0: - completionHandler(true) - break - case 1: - completionHandler(false) - break - default: - completionHandler(false) - } - return false - } - return true - } - callback.defaultBehaviour = { [weak self] (response: JsConfirmResponse?) in - if !completionHandlerCalled { - completionHandlerCalled = true - let responseMessage = response?.message - let confirmButtonTitle = response?.confirmButtonTitle - let cancelButtonTitle = response?.cancelButtonTitle - self?.createConfirmDialog(message: message, responseMessage: responseMessage, confirmButtonTitle: confirmButtonTitle, cancelButtonTitle: cancelButtonTitle, completionHandler: completionHandler) - } - } - callback.error = { (code: String, message: String?, details: Any?) in - if !completionHandlerCalled { - completionHandlerCalled = true - print(code + ", " + (message ?? "")) - completionHandler(false) - } - } - - if let channelDelegate = channelDelegate { - channelDelegate.onJsConfirm(url: frame.request.url, message: message, isMainFrame: frame.isMainFrame, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - func createPromptDialog(message: String, defaultValue: String?, responseMessage: String?, confirmButtonTitle: String?, cancelButtonTitle: String?, value: String?, completionHandler: @escaping (String?) -> Void) { - let dialogMessage = responseMessage != nil && !responseMessage!.isEmpty ? responseMessage : message - let okButton = confirmButtonTitle != nil && !confirmButtonTitle!.isEmpty ? confirmButtonTitle : NSLocalizedString("Ok", comment: "") - let cancelButton = cancelButtonTitle != nil && !cancelButtonTitle!.isEmpty ? cancelButtonTitle : NSLocalizedString("Cancel", comment: "") - - let alert = NSAlert() - alert.messageText = dialogMessage ?? "" - alert.alertStyle = .informational - alert.addButton(withTitle: okButton ?? "") - alert.addButton(withTitle: cancelButton ?? "") - let txt = NSTextField(frame: NSRect(x: 0, y: 0, width: 200, height: 24)) - txt.stringValue = defaultValue ?? "" - alert.accessoryView = txt - let res = alert.runModal() - - completionHandler(value != nil ? value : (res == .alertFirstButtonReturn ? txt.stringValue : nil)) - } - - public func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt message: String, defaultText defaultValue: String?, initiatedByFrame frame: WKFrameInfo, - completionHandler: @escaping (String?) -> Void) { - - var completionHandlerCalled = false - - let callback = WebViewChannelDelegate.JsPromptCallback() - callback.nonNullSuccess = { (response: JsPromptResponse) in - if response.handledByClient { - completionHandlerCalled = true - let action = response.action ?? 1 - switch action { - case 0: - completionHandler(response.value) - break - case 1: - completionHandler(nil) - break - default: - completionHandler(nil) - } - return false - } - return true - } - callback.defaultBehaviour = { [weak self] (response: JsPromptResponse?) in - if !completionHandlerCalled { - completionHandlerCalled = true - let responseMessage = response?.message - let confirmButtonTitle = response?.confirmButtonTitle - let cancelButtonTitle = response?.cancelButtonTitle - let value = response?.value - self?.createPromptDialog(message: message, defaultValue: defaultValue, responseMessage: responseMessage, confirmButtonTitle: confirmButtonTitle, - cancelButtonTitle: cancelButtonTitle, value: value, completionHandler: completionHandler) - } - } - callback.error = { (code: String, message: String?, details: Any?) in - if !completionHandlerCalled { - completionHandlerCalled = true - print(code + ", " + (message ?? "")) - completionHandler(nil) - } - } - - if let channelDelegate = channelDelegate { - channelDelegate.onJsPrompt(url: frame.request.url, message: message, defaultValue: defaultValue, isMainFrame: frame.isMainFrame, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - public func webView(_ webView: WKWebView, - createWebViewWith configuration: WKWebViewConfiguration, - for navigationAction: WKNavigationAction, - windowFeatures: WKWindowFeatures) -> WKWebView? { - var windowId: Int64 = 0 - let inAppWebViewManager = plugin?.inAppWebViewManager - if let inAppWebViewManager = inAppWebViewManager { - inAppWebViewManager.windowAutoincrementId += 1 - windowId = inAppWebViewManager.windowAutoincrementId - } - - let windowWebView = InAppWebView(id: nil, plugin: nil, frame: CGRect.zero, configuration: configuration) - windowWebView.windowId = windowId - - let webViewTransport = WebViewTransport( - webView: windowWebView, - request: navigationAction.request - ) - - inAppWebViewManager?.windowWebViews[windowId] = webViewTransport - - let createWindowAction = CreateWindowAction(navigationAction: navigationAction, windowId: windowId, windowFeatures: windowFeatures, isDialog: nil) - - let callback = WebViewChannelDelegate.CreateWindowCallback() - callback.nonNullSuccess = { (handledByClient: Bool) in - return !handledByClient - } - callback.defaultBehaviour = { [weak self] (handledByClient: Bool?) in - if inAppWebViewManager?.windowWebViews[windowId] != nil { - inAppWebViewManager?.windowWebViews.removeValue(forKey: windowId) - } - self?.loadUrl(urlRequest: navigationAction.request, allowingReadAccessTo: nil) - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - if let channelDelegate = channelDelegate { - channelDelegate.onCreateWindow(createWindowAction: createWindowAction, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - - return windowWebView - } - - public func webView(_ webView: WKWebView, - authenticationChallenge challenge: URLAuthenticationChallenge, - shouldAllowDeprecatedTLS decisionHandler: @escaping (Bool) -> Void) { - var decisionHandlerCalled = false - let callback = WebViewChannelDelegate.ShouldAllowDeprecatedTLSCallback() - callback.nonNullSuccess = { (action: Bool) in - decisionHandlerCalled = true - decisionHandler(action) - return false - } - callback.defaultBehaviour = { (action: Bool?) in - if !decisionHandlerCalled { - decisionHandlerCalled = true - decisionHandler(false) - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - - let runCallback = { - if let channelDelegate = self.channelDelegate { - channelDelegate.shouldAllowDeprecatedTLS(challenge: challenge, callback: callback) - } else { - callback.defaultBehaviour(nil) - } - } - - if windowId != nil, !windowCreated { - windowBeforeCreatedCallbacks.append(runCallback) - } else { - runCallback() - } - } - - public func webViewDidClose(_ webView: WKWebView) { - channelDelegate?.onCloseWindow() - } - - public func webViewWebContentProcessDidTerminate(_ webView: WKWebView) { - channelDelegate?.onWebContentProcessDidTerminate() - } - - public func webView(_ webView: WKWebView, - didCommit navigation: WKNavigation!) { - channelDelegate?.onPageCommitVisible(url: url?.absoluteString) - } - - public func webView(_ webView: WKWebView, - didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) { - channelDelegate?.onDidReceiveServerRedirectForProvisionalNavigation() - } - -// @available(iOS 13.0, *) -// public func webView(_ webView: WKWebView, -// contextMenuConfigurationForElement elementInfo: WKContextMenuElementInfo, -// completionHandler: @escaping (UIContextMenuConfiguration?) -> Void) { -// print("contextMenuConfigurationForElement") -// let actionProvider: UIContextMenuActionProvider = { _ in -// let editMenu = UIMenu(title: "Edit...", children: [ -// UIAction(title: "Copy") { action in -// -// }, -// UIAction(title: "Duplicate") { action in -// -// } -// ]) -// return UIMenu(title: "Title", children: [ -// UIAction(title: "Share") { action in -// -// }, -// editMenu -// ]) -// } -// let contextMenuConfiguration = UIContextMenuConfiguration(identifier: nil, previewProvider: nil, actionProvider: actionProvider) -// //completionHandler(contextMenuConfiguration) -// completionHandler(nil) -//// onContextMenuConfigurationForElement(linkURL: elementInfo.linkURL?.absoluteString, result: nil/*{(result) -> Void in -//// if result is FlutterError { -//// print((result as! FlutterError).message ?? "") -//// } -//// else if (result as? NSObject) == FlutterMethodNotImplemented { -//// completionHandler(nil) -//// } -//// else { -//// var response: [String: Any] -//// if let r = result { -//// response = r as! [String: Any] -//// var action = response["action"] as? Int -//// action = action != nil ? action : 0; -//// switch action { -//// case 0: -//// break -//// case 1: -//// break -//// default: -//// completionHandler(nil) -//// } -//// return; -//// } -//// completionHandler(nil) -//// } -//// }*/) -// } -//// -// @available(iOS 13.0, *) -// public func webView(_ webView: WKWebView, -// contextMenuDidEndForElement elementInfo: WKContextMenuElementInfo) { -// print("contextMenuDidEndForElement") -// print(elementInfo) -// //onContextMenuDidEndForElement(linkURL: elementInfo.linkURL?.absoluteString) -// } -// -// @available(iOS 13.0, *) -// public func webView(_ webView: WKWebView, -// contextMenuForElement elementInfo: WKContextMenuElementInfo, -// willCommitWithAnimator animator: UIContextMenuInteractionCommitAnimating) { -// print("willCommitWithAnimator") -// print(elementInfo) -//// onWillCommitWithAnimator(linkURL: elementInfo.linkURL?.absoluteString, result: nil/*{(result) -> Void in -//// if result is FlutterError { -//// print((result as! FlutterError).message ?? "") -//// } -//// else if (result as? NSObject) == FlutterMethodNotImplemented { -//// -//// } -//// else { -//// var response: [String: Any] -//// if let r = result { -//// response = r as! [String: Any] -//// var action = response["action"] as? Int -//// action = action != nil ? action : 0; -////// switch action { -////// case 0: -////// break -////// case 1: -////// break -////// default: -////// -////// } -//// return; -//// } -//// -//// } -//// }*/) -// } -// -// @available(iOS 13.0, *) -// public func webView(_ webView: WKWebView, -// contextMenuWillPresentForElement elementInfo: WKContextMenuElementInfo) { -// print("contextMenuWillPresentForElement") -// print(elementInfo.linkURL) -// //onContextMenuWillPresentForElement(linkURL: elementInfo.linkURL?.absoluteString) -// } - - - /// Determines if the window notification is likely for a fullscreen video/media presentation. - /// Uses heuristics based on window properties rather than private class names to avoid App Store rejection. - /// See: https://github.com/pichillilorenzo/flutter_inappwebview/issues/2754 - private func isFullscreenMediaWindow(_ notificationObject: AnyObject?) -> Bool { - guard let window = notificationObject as? NSWindow else { - return false - } - - // Exclude windows that are clearly not fullscreen media - guard let screen = window.screen ?? NSScreen.main else { - return false - } - - let screenFrame = screen.frame - let windowFrame = window.frame - - // Check if the window is full screen or close to it (allowing small margins) - let isFullScreenSize = windowFrame.width >= screenFrame.width * 0.9 && - windowFrame.height >= screenFrame.height * 0.9 - - // Check if the window's content view controller suggests it's a media presentation - // AVPlayerViewController and similar media controllers are used for fullscreen playback - let hasMediaViewController: Bool - if let contentVC = window.contentViewController { - let vcTypeName = String(describing: type(of: contentVC)) - hasMediaViewController = vcTypeName.contains("AVFullScreen") || - vcTypeName.contains("AVPlayer") || - vcTypeName.contains("WebFullScreen") || - vcTypeName.contains("WKFullScreen") - } else { - hasMediaViewController = false - } - - // Check window type description (using type description instead of NSClassFromString to avoid private API issues) - let windowTypeDescription = String(describing: type(of: window)) - let isLikelyMediaWindow = windowTypeDescription.contains("FullScreen") && - windowTypeDescription.contains("WebCore") - - // Exclude obvious non-media windows - let isLikelySystemWindow = windowTypeDescription.contains("Menu") || - windowTypeDescription.contains("Tooltip") || - windowTypeDescription.contains("StatusBar") || - windowTypeDescription.contains("Panel") - - if isLikelySystemWindow { - return false - } - - return isFullScreenSize && (hasMediaViewController || isLikelyMediaWindow) - } - - @objc func onEnterFullscreen(_ notification: Notification) { - // Check if already in fullscreen to avoid double-firing - // (both KVO observer and NSWindow notification might trigger this) - guard !inFullscreen else { return } - - if isFullscreenMediaWindow(notification.object as AnyObject?) { - fullscreenWindow = notification.object as? NSWindow - channelDelegate?.onEnterFullscreen() - inFullscreen = true - } - } - - @objc func onExitFullscreen(_ notification: Notification) { - // Check if not in fullscreen to avoid double-firing - // (both KVO observer and NSWindow notification might trigger this) - guard inFullscreen else { return } - - // Check if this is the same window that entered fullscreen - // or if it's a fullscreen-like media window exiting - let exitingWindow = notification.object as? NSWindow - let isTrackedFullscreenWindow = fullscreenWindow != nil && fullscreenWindow === exitingWindow - let isLikelyFullscreenExit = isTrackedFullscreenWindow || isFullscreenMediaWindow(notification.object as AnyObject?) - - if isLikelyFullscreenExit { - fullscreenWindow = nil - channelDelegate?.onExitFullscreen() - inFullscreen = false - } - } - -// public func onContextMenuConfigurationForElement(linkURL: String?, result: FlutterResult?) { -// let arguments: [String: Any?] = ["linkURL": linkURL] -// channel?.invokeMethod("onContextMenuConfigurationForElement", arguments: arguments, result: result) -// } -// -// public func onContextMenuDidEndForElement(linkURL: String?) { -// let arguments: [String: Any?] = ["linkURL": linkURL] -// channel?.invokeMethod("onContextMenuDidEndForElement", arguments: arguments) -// } -// -// public func onWillCommitWithAnimator(linkURL: String?, result: FlutterResult?) { -// let arguments: [String: Any?] = ["linkURL": linkURL] -// channel?.invokeMethod("onWillCommitWithAnimator", arguments: arguments, result: result) -// } -// -// public func onContextMenuWillPresentForElement(linkURL: String?) { -// let arguments: [String: Any?] = ["linkURL": linkURL] -// channel?.invokeMethod("onContextMenuWillPresentForElement", arguments: arguments) -// } - - public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - guard javaScriptBridgeEnabled else { - return - } - - guard let body = message.body as? [String: Any?] else { - return - } - - guard let bridgeSecret = body["_bridgeSecret"] as? String, bridgeSecret == exceptedBridgeSecret else { - print("Bridge access attempt with wrong secret token, possibly from malicious code from origin \(message.frameInfo.securityOrigin)") - return - } - - var sourceOrigin: URL? = nil - let securityOrigin = message.frameInfo.securityOrigin - let scheme = securityOrigin.protocol - let host = securityOrigin.host - let port = securityOrigin.port - if !scheme.isEmpty, !host.isEmpty { - sourceOrigin = URL(string: "\(scheme)://\(host)\(port != 0 ? ":" + String(port) : "")") - } - let requestUrl = message.frameInfo.request.url - - var isOriginAllowed = false - if let javaScriptHandlersOriginAllowList = settings?.javaScriptHandlersOriginAllowList { - if let origin = sourceOrigin?.absoluteString { - for allowedOrigin in javaScriptHandlersOriginAllowList { - if origin.range(of: allowedOrigin, options: .regularExpression, range: nil, locale: nil) != nil { - isOriginAllowed = true - break - } - } - } - } else { - // origin is by default allowed if the allow list is null - isOriginAllowed = true - } - - if !isOriginAllowed { - print("Bridge access attempt from an origin not allowed: \(message.frameInfo.securityOrigin)") - return - } - - if message.name == "callHandler" { - guard let handlerName = body["handlerName"] as? String else { - print("handlerName is null or undefined") - return - } - - let _windowId = body["_windowId"] as? Int64 - var webView = self - if let wId = _windowId, let webViewTransport = plugin?.inAppWebViewManager?.windowWebViews[wId] { - webView = webViewTransport.webView - } - var isInternalHandler = true - switch (handlerName) { - case "onPrintRequest": - let settings = PrintJobSettings() - settings.handledByClient = true - if let printJobId = webView.printCurrentPage(settings: settings) { - let callback = WebViewChannelDelegate.PrintRequestCallback() - callback.nonNullSuccess = { (handledByClient: Bool) in - return !handledByClient - } - callback.defaultBehaviour = { (handledByClient: Bool?) in - if let printJob = webView.plugin?.printJobManager?.jobs[printJobId] { - printJob?.disposeWhenDidRun = true - } - } - callback.error = { [weak callback] (code: String, message: String?, details: Any?) in - print(code + ", " + (message ?? "")) - callback?.defaultBehaviour(nil) - } - webView.channelDelegate?.onPrintRequest(url: webView.url, printJobId: printJobId, callback: callback) - } - break - case "onConsoleMessage": - if let args = body["args"] as? String, let data = args.data(using: .utf8) { - let jsonArgs = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String: Any]] - if let jsonData = jsonArgs?.first { - var messageLevel = 1 - switch (jsonData["level"] as? String) { - case "log": - messageLevel = 1 - break - case "debug": - // on Android, console.debug is TIP - messageLevel = 0 - break - case "error": - messageLevel = 3 - break - case "info": - // on Android, console.info is LOG - messageLevel = 1 - break - case "warn": - messageLevel = 2 - break - default: - messageLevel = 1 - break - } - let consoleMessage = jsonData["message"] as? String ?? "" - - webView.channelDelegate?.onConsoleMessage(message: consoleMessage, messageLevel: messageLevel) - } - } - break - case "onFindResultReceived": - if let args = body["args"] as? String, let data = args.data(using: .utf8) { - let jsonArgs = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String: Any]] - if let jsonData = jsonArgs?.first, - let findResult = jsonData["findResult"] as? [String: Any], - let activeMatchOrdinal = findResult["activeMatchOrdinal"] as? Int, - let numberOfMatches = findResult["numberOfMatches"] as? Int, - let isDoneCounting = findResult["isDoneCounting"] as? Bool { - webView.findInteractionController?.channelDelegate?.onFindResultReceived(activeMatchOrdinal: activeMatchOrdinal, numberOfMatches: numberOfMatches, isDoneCounting: isDoneCounting) - webView.channelDelegate?.onFindResultReceived(activeMatchOrdinal: activeMatchOrdinal, numberOfMatches: numberOfMatches, isDoneCounting: isDoneCounting) - } - } - break - case "onCallAsyncJavaScriptResultBelowIOS14Received": - if let args = body["args"] as? String, let data = args.data(using: .utf8) { - let jsonArgs = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String: Any]] - if let jsonData = jsonArgs?.first, - let resultUuid = jsonData["resultUuid"] as? String, - let result = webView.callAsyncJavaScriptBelowMacOS11Results[resultUuid] { - result([ - "value": jsonData["value"], - "error": jsonData["error"] - ]) - webView.callAsyncJavaScriptBelowMacOS11Results.removeValue(forKey: resultUuid) - } - } - break - case "onWebMessagePortMessageReceived": - if let args = body["args"] as? String, let data = args.data(using: .utf8) { - let jsonArgs = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String: Any]] - if let jsonData = jsonArgs?.first, - let webMessageChannelId = jsonData["webMessageChannelId"] as? String, - let index = jsonData["index"] as? Int64 { - var webMessage: WebMessage? = nil - if let webMessageMap = jsonData["message"] as? [String : Any?] { - webMessage = WebMessage.fromMap(map: webMessageMap) - } - - if let webMessageChannel = webView.webMessageChannels[webMessageChannelId] { - webMessageChannel.channelDelegate?.onMessage(index: index, message: webMessage) - } - } - } - break - case "onWebMessageListenerPostMessageReceived": - if let args = body["args"] as? String, let data = args.data(using: .utf8) { - let jsonArgs = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String: Any]] - if let jsonData = jsonArgs?.first, let jsObjectName = jsonData["jsObjectName"] as? String { - var webMessage: WebMessage? = nil - if let webMessageMap = jsonData["message"] as? [String : Any?] { - webMessage = WebMessage.fromMap(map: webMessageMap) - } - - if let webMessageListener = webView.webMessageListeners.first(where: ({($0.jsObjectName == jsObjectName)})) { - let isMainFrame = message.frameInfo.isMainFrame - - let securityOrigin = message.frameInfo.securityOrigin - let scheme = securityOrigin.protocol - let host = securityOrigin.host - let port = securityOrigin.port - - if !webMessageListener.isOriginAllowed(scheme: scheme, host: host, port: port) { - return - } - - var sourceOrigin: URL? = nil - if !scheme.isEmpty, !host.isEmpty { - sourceOrigin = URL(string: "\(scheme)://\(host)\(port != 0 ? ":" + String(port) : "")") - } - webMessageListener.channelDelegate?.onPostMessage(message: webMessage, sourceOrigin: sourceOrigin, isMainFrame: isMainFrame) - } - } - } - break - case "onScrollChanged": - if let args = body["args"] as? String, let data = args.data(using: .utf8) { - let jsonArgs = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String: Any]] - if let jsonData = jsonArgs?.first, - let x = jsonData["x"] as? Int, - let y = jsonData["y"] as? Int { - webView.channelDelegate?.onScrollChanged(x: x, y: y) - } - } - break - default: - isInternalHandler = false - break - } - - let _callHandlerID = body["_callHandlerID"] as? Int64 ?? 0 - - if isInternalHandler { - evaluateJavaScript(""" -if(window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)] != null) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)].resolve(); - delete window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)]; -} -""", completionHandler: nil) - return - } - - let args = body["args"] as? String ?? "" - - let callback = WebViewChannelDelegate.CallJsHandlerCallback() - callback.defaultBehaviour = { (response: Any?) in - var json = "null" - if let r = response as? String { - json = r - } - - webView.evaluateJavaScript(""" -if(window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)] != null) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)].resolve(\(json)); - delete window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)]; -} -""", completionHandler: nil) - } - callback.error = { (code: String, message: String?, details: Any?) in - let errorMessage = code + (message != nil ? ", " + (message ?? "") : "") - print(errorMessage) - - webView.evaluateJavaScript(""" -if(window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)] != null) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)].reject(new Error('\(errorMessage.replacingOccurrences(of: "\'", with: "\\'"))')); - delete window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)]; -} -""", completionHandler: nil) - } - - if let channelDelegate = webView.channelDelegate { - let data = JavaScriptHandlerFunctionData( - args: args, isMainFrame: message.frameInfo.isMainFrame, - origin: sourceOrigin?.absoluteString ?? "", - requestUrl: requestUrl?.absoluteString ?? "" - ) - channelDelegate.onCallJsHandler(handlerName: handlerName, data: data, callback: callback) - } - } - } - - public func scrollTo(x: Int, y: Int, animated: Bool) { - evaluateJavaScript("window.scrollTo({left: \(x), top: \(y), behavior: \(animated ? "'smooth'" : "'auto'")})") - } - - public func scrollBy(x: Int, y: Int, animated: Bool) { - evaluateJavaScript("window.scrollBy({left: \(x), top: \(y), behavior: \(animated ? "'smooth'" : "'auto'")})") - } - - - public func pauseTimers() { - if !isPausedTimers { - isPausedTimers = true - let script = "alert();"; - self.evaluateJavaScript(script, completionHandler: nil) - } - } - - public func resumeTimers() { - if isPausedTimers { - if let completionHandler = isPausedTimersCompletionHandler { - self.isPausedTimersCompletionHandler = nil - completionHandler() - } - isPausedTimers = false - } - } - - public func printCurrentPage(settings: PrintJobSettings? = nil, - completionHandler: PrintJobController.CompletionHandler? = nil) -> String? { - if #available(macOS 11.0, *) { - var printJobId: String? = nil - if let settings = settings, settings.handledByClient { - printJobId = NSUUID().uuidString - } - - var printInfoDictionary: [NSPrintInfo.AttributeKey : Any] = [:] - if let settings = settings { - if let jobSavingURL = settings.jobSavingURL, let url = URL(string: jobSavingURL) { - printInfoDictionary[.jobSavingURL] = url - } - printInfoDictionary[.copies] = settings.copies - if let firstPage = settings.firstPage { - printInfoDictionary[.firstPage] = firstPage - } - if let lastPage = settings.lastPage { - printInfoDictionary[.lastPage] = lastPage - } - printInfoDictionary[.detailedErrorReporting] = settings.detailedErrorReporting - printInfoDictionary[.faxNumber] = settings.faxNumber ?? "" - printInfoDictionary[.headerAndFooter] = settings.headerAndFooter - if let mustCollate = settings.mustCollate { - printInfoDictionary[.mustCollate] = mustCollate - } - if let pagesAcross = settings.pagesAcross { - printInfoDictionary[.pagesAcross] = pagesAcross - } - if let pagesDown = settings.pagesDown { - printInfoDictionary[.pagesDown] = pagesDown - } - if let time = settings.time { - printInfoDictionary[.time] = Date(timeIntervalSince1970: TimeInterval(Double(time)/1000)) - } - } - - let printInfo = NSPrintInfo(dictionary: printInfoDictionary) - - if let settings = settings { - if let orientationValue = settings.orientation, - let orientation = NSPrintInfo.PaperOrientation.init(rawValue: orientationValue) { - printInfo.orientation = orientation - } - if let margins = settings.margins { - printInfo.topMargin = margins.top - printInfo.rightMargin = margins.right - printInfo.bottomMargin = margins.bottom - printInfo.leftMargin = margins.left - } - if let numberOfPages = settings.numberOfPages { - printInfo.printSettings["com_apple_print_PrintSettings_PMLastPage"] = numberOfPages - } - if let colorMode = settings.colorMode { - printInfo.printSettings["ColorModel"] = colorMode - } - if let scalingFactor = settings.scalingFactor { - printInfo.scalingFactor = scalingFactor - } - if let jobDisposition = settings.jobDisposition { - printInfo.jobDisposition = Util.getNSPrintInfoJobDisposition(name: jobDisposition) - } - if let paperName = settings.paperName { - printInfo.paperName = NSPrinter.PaperName.init(rawValue: paperName) - } - if let horizontalPagination = settings.horizontalPagination, - let pagination = NSPrintInfo.PaginationMode.init(rawValue: horizontalPagination) { - printInfo.horizontalPagination = pagination - } - if let verticalPagination = settings.verticalPagination, - let pagination = NSPrintInfo.PaginationMode.init(rawValue: verticalPagination) { - printInfo.verticalPagination = pagination - } - printInfo.isHorizontallyCentered = settings.isHorizontallyCentered - printInfo.isVerticallyCentered = settings.isVerticallyCentered - } - let printOperation = printOperation(with: printInfo) - printOperation.jobTitle = settings?.jobName ?? (title ?? url?.absoluteString ?? "") + " Document" - printOperation.view?.frame = bounds - - if let settings = settings { - if let pageOrder = settings.pageOrder, let order = NSPrintOperation.PageOrder.init(rawValue: pageOrder) { - printOperation.pageOrder = order - } - printOperation.canSpawnSeparateThread = settings.canSpawnSeparateThread - printOperation.showsPrintPanel = settings.showsPrintPanel - printOperation.showsProgressPanel = settings.showsProgressPanel - if settings.showsPaperOrientation { - printOperation.printPanel.options.insert(.showsOrientation) - } else { - printOperation.printPanel.options.remove(.showsOrientation) - } - if settings.showsNumberOfCopies { - printOperation.printPanel.options.insert(.showsCopies) - } else { - printOperation.printPanel.options.remove(.showsCopies) - } - if settings.showsPaperSize { - printOperation.printPanel.options.insert(.showsPaperSize) - } else { - printOperation.printPanel.options.remove(.showsPaperSize) - } - if settings.showsScaling { - printOperation.printPanel.options.insert(.showsScaling) - } else { - printOperation.printPanel.options.remove(.showsScaling) - } - if settings.showsPageRange { - printOperation.printPanel.options.insert(.showsPageRange) - } else { - printOperation.printPanel.options.remove(.showsPageRange) - } - if settings.showsPageSetupAccessory { - printOperation.printPanel.options.insert(.showsPageSetupAccessory) - } else { - printOperation.printPanel.options.remove(.showsPageSetupAccessory) - } - if settings.showsPreview { - printOperation.printPanel.options.insert(.showsPreview) - } else { - printOperation.printPanel.options.remove(.showsPreview) - } - if settings.showsPrintSelection { - printOperation.printPanel.options.insert(.showsPrintSelection) - } else { - printOperation.printPanel.options.remove(.showsPrintSelection) - } - } - - if let id = printJobId, let plugin = plugin { - let printJob = PrintJobController(plugin: plugin, id: id, job: printOperation, settings: settings) - plugin.printJobManager?.jobs[id] = printJob - printJob.present(parentWindow: window, completionHandler: completionHandler) - } else if let window = window { - printJobCompletionHandler = completionHandler - printOperation.runModal(for: window, delegate: self, didRun: #selector(printOperationDidRun), contextInfo: nil) - } else { - printView(self) - } - - return printJobId - } else { - printView(self) - } - return nil - } - - @objc func printOperationDidRun(printOperation: NSPrintOperation, - success: Bool, - contextInfo: UnsafeMutableRawPointer?) { - if let completionHandler = printJobCompletionHandler { - completionHandler(printOperation, success, contextInfo) - printJobCompletionHandler = nil - } - } - - public func getContentHeight(completionHandler: @escaping ((Int64?, Error?) -> Void)) { - evaluateJavaScript("document.body.scrollHeight") { scrollHeight, error in - if let error = error { - completionHandler(nil, error) - } else { - completionHandler(Int64(scrollHeight as? Double ?? 0.0), nil) - } - } - } - - public func getContentWidth(completionHandler: @escaping ((Int64?, Error?) -> Void)) { - evaluateJavaScript("document.body.scrollWidth") { scrollWidth, error in - if let error = error { - completionHandler(nil, error) - } else { - completionHandler(Int64(scrollWidth as? Double ?? 0.0), nil) - } - } - } - - public func getOriginalUrl() -> URL? { - return currentOriginalUrl - } - - public func getSelectedText(completionHandler: @escaping (Any?, Error?) -> Void) { - if configuration.preferences.javaScriptEnabled { - evaluateJavaScript(PluginScriptsUtil.GET_SELECTED_TEXT_JS_SOURCE, completionHandler: completionHandler) - } else { - completionHandler(nil, nil) - } - } - - public func clearFocus() -> Bool { - return (self.superview?.window ?? self.window)?.makeFirstResponder(nil) ?? false - } - - public func requestFocus() -> Bool { - return (self.superview?.window ?? self.window)?.makeFirstResponder(self) ?? false - } - - // Workaround for https://github.com/pichillilorenzo/flutter_inappwebview/issues/2380 - // TODO: remove when Flutter fixes this - private var _isFirstResponder = true - override open func becomeFirstResponder() -> Bool { - _isFirstResponder = true - return super.becomeFirstResponder() - } - private func _fixFocus(callback: @escaping () -> Void) { - if _isFirstResponder, let channelDelegate = channelDelegate { - _isFirstResponder = false - channelDelegate._onMouseDown(callback: { [weak self] in - let _ = self?.requestFocus() - callback() - }) - } else { - callback() - } - } - override public func mouseDown(with event: NSEvent) { - _fixFocus { - super.mouseDown(with: event) - } - } - override public func rightMouseDown(with event: NSEvent) { - _fixFocus { - super.rightMouseDown(with: event) - } - } - override public func otherMouseDown(with event: NSEvent) { - _fixFocus { - super.otherMouseDown(with: event) - } - } - - public func getCertificate() -> SslCertificate? { - guard let scheme = url?.scheme, - scheme == "https", - let host = url?.host, - let sslCertificate = InAppWebView.sslCertificatesMap[host] else { - return nil - } - return sslCertificate - } - - public func isSecureContext(completionHandler: @escaping (_ isSecureContext: Bool) -> Void) { - evaluateJavascript(source: "window.isSecureContext") { (isSecureContext) in - if let isSecureContext = isSecureContext { - completionHandler(isSecureContext as? Bool ?? false) - return - } - completionHandler(false) - } - } - - public func canScrollVertically(completionHandler: @escaping ((Bool, Error?) -> Void)) { - getContentHeight { contentHeight, error in - if let error = error { - completionHandler(false, error) - } else { - completionHandler(CGFloat(contentHeight ?? 0) > self.frame.height, nil) - } - } - } - - public func canScrollHorizontally(completionHandler: @escaping ((Bool, Error?) -> Void)) { - getContentWidth { contentWidth, error in - if let error = error { - completionHandler(false, error) - } else { - completionHandler(CGFloat(contentWidth ?? 0) > self.frame.width, nil) - } - } - } - - public func createWebMessageChannel(completionHandler: ((WebMessageChannel?) -> Void)? = nil) -> WebMessageChannel? { - guard let plugin = plugin else { - completionHandler?(nil) - return nil - } - let id = NSUUID().uuidString - let webMessageChannel = WebMessageChannel(plugin: plugin, id: id) - webMessageChannel.initJsInstance(webView: self, completionHandler: completionHandler) - webMessageChannels[id] = webMessageChannel - - return webMessageChannel - } - - public func postWebMessage(message: WebMessage, targetOrigin: String, completionHandler: ((Any?) -> Void)? = nil) throws { - var portsString = "null" - if let ports = message.ports { - var portArrayString: [String] = [] - for port in ports { - if port.isStarted { - throw NSError(domain: "Port is already started", code: 0) - } - if port.isClosed || port.isTransferred { - throw NSError(domain: "Port is already closed or transferred", code: 0) - } - port.isTransferred = true - portArrayString.append("\(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())['\(port.webMessageChannel!.id)'].\(port.name)") - } - portsString = "[" + portArrayString.joined(separator: ", ") + "]" - } - - let url = URL(string: targetOrigin)?.absoluteString ?? "*" - let source = """ - (function() { - window.postMessage(\(message.jsData), '\(url)', \(portsString)); - })(); - """ - evaluateJavascript(source: source, completionHandler: completionHandler) - message.dispose() - } - - public func addWebMessageListener(webMessageListener: WebMessageListener) throws { - if webMessageListeners.map({ ($0.jsObjectName) }).contains(webMessageListener.jsObjectName) { - throw NSError(domain: "jsObjectName \(webMessageListener.jsObjectName) was already added.", code: 0) - } - try webMessageListener.assertOriginRulesValid() - webMessageListener.initJsInstance(webView: self) - webMessageListeners.append(webMessageListener) - } - - public func disposeWebMessageChannels() { - for webMessageChannel in webMessageChannels.values { - webMessageChannel.dispose() - } - webMessageChannels.removeAll() - } - - public func getScrollX(completionHandler: @escaping ((Int64?, Error?) -> Void)) { - evaluateJavaScript("window.scrollX") { scrollX, error in - if let error = error { - completionHandler(nil, error) - } else { - completionHandler(Int64(scrollX as? Double ?? 0.0), nil) - } - } - } - - public func getScrollY(completionHandler: @escaping ((Int64?, Error?) -> Void)) { - evaluateJavaScript("window.scrollY") { scrollY, error in - if let error = error { - completionHandler(nil, error) - } else { - completionHandler(Int64(scrollY as? Double ?? 0.0), nil) - } - } - } - - @available(macOS 12.0, *) - public func saveState() -> Data? { - return interactionState is NSData || interactionState is Data ? interactionState as? Data : nil - } - - @available(macOS 12.0, *) - public func restoreState(state: Data) { - interactionState = state - } - - public func runWindowBeforeCreatedCallbacks() { - let callbacks = windowBeforeCreatedCallbacks - callbacks.forEach { (callback) in - callback() - } - windowBeforeCreatedCallbacks.removeAll() - } - - public func dispose() { - channelDelegate?.dispose() - channelDelegate = nil - runWindowBeforeCreatedCallbacks() - currentOpenPanel?.cancel(self) - currentOpenPanel?.close() - currentOpenPanel = nil - printJobCompletionHandler = nil - removeObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress)) - removeObserver(self, forKeyPath: #keyPath(WKWebView.url)) - removeObserver(self, forKeyPath: #keyPath(WKWebView.title)) - if #available(macOS 12.0, *) { - removeObserver(self, forKeyPath: #keyPath(WKWebView.cameraCaptureState)) - removeObserver(self, forKeyPath: #keyPath(WKWebView.microphoneCaptureState)) - } - if #available(macOS 13.0, *) { - removeObserver(self, forKeyPath: #keyPath(WKWebView.fullscreenState)) - } - resumeTimers() - stopLoading() - disposeWebMessageChannels() - for webMessageListener in webMessageListeners { - webMessageListener.dispose() - } - webMessageListeners.removeAll() - interceptOnlyAsyncAjaxRequestsPluginScript = nil - if windowId == nil { - configuration.userContentController.removeAllPluginScriptMessageHandlers() - configuration.userContentController.removeAllUserScripts() - if #available(macOS 10.13, *) { - configuration.userContentController.removeAllContentRuleLists() - } - } else if let wId = windowId, plugin?.inAppWebViewManager?.windowWebViews[wId] != nil { - plugin?.inAppWebViewManager?.windowWebViews.removeValue(forKey: wId) - } - configuration.userContentController.dispose(windowId: windowId) - NotificationCenter.default.removeObserver(self) - for imp in customIMPs { - imp_removeBlock(imp) - } - findInteractionController?.dispose() - findInteractionController = nil - uiDelegate = nil - navigationDelegate = nil - isPausedTimersCompletionHandler = nil - callAsyncJavaScriptBelowMacOS11Results.removeAll() - plugin = nil - } - - deinit { - debugPrint("InAppWebView - dealloc") - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/InAppWebViewManager.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/InAppWebViewManager.swift deleted file mode 100755 index d4d369bd69..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/InAppWebViewManager.swift +++ /dev/null @@ -1,132 +0,0 @@ -// -// InAppWebViewManager.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 08/12/2019. -// - -import Foundation -import WebKit -import FlutterMacOS - -public class InAppWebViewManager: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_manager" - var plugin: InAppWebViewFlutterPlugin? - var webViewForUserAgent: WKWebView? - var defaultUserAgent: String? - - var keepAliveWebViews: [String:FlutterWebViewController?] = [:] - var windowWebViews: [Int64:WebViewTransport] = [:] - var windowAutoincrementId: Int64 = 0 - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: InAppWebViewManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger)) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "getDefaultUserAgent": - getDefaultUserAgent(completionHandler: { (value) in - result(value) - }) - break - case "handlesURLScheme": - let urlScheme = arguments!["urlScheme"] as! String - if #available(macOS 10.13, *) { - result(WKWebView.handlesURLScheme(urlScheme)) - } else { - result(false) - } - break - case "disposeKeepAlive": - let keepAliveId = arguments!["keepAliveId"] as! String - disposeKeepAlive(keepAliveId: keepAliveId) - result(true) - break - case "clearAllCache": - let includeDiskFiles = arguments!["includeDiskFiles"] as! Bool - clearAllCache(includeDiskFiles: includeDiskFiles, completionHandler: { - result(true) - }) - case "setJavaScriptBridgeName": - let bridgeName = arguments!["bridgeName"] as! String - JavaScriptBridgeJS.set_JAVASCRIPT_BRIDGE_NAME(bridgeName: bridgeName) - result(true) - break - case "getJavaScriptBridgeName": - result(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func getDefaultUserAgent(completionHandler: @escaping (_ value: String?) -> Void) { - if defaultUserAgent == nil { - webViewForUserAgent = WKWebView() - webViewForUserAgent?.evaluateJavaScript("navigator.userAgent") { (value, error) in - - if error != nil { - print("Error occurred to get userAgent") - self.webViewForUserAgent = nil - completionHandler(nil) - return - } - - if let unwrappedUserAgent = value as? String { - self.defaultUserAgent = unwrappedUserAgent - completionHandler(self.defaultUserAgent) - } else { - print("Failed to get userAgent") - } - self.webViewForUserAgent = nil - } - } else { - completionHandler(defaultUserAgent) - } - } - - public func disposeKeepAlive(keepAliveId: String) { - if let flutterWebView = keepAliveWebViews[keepAliveId] as? FlutterWebViewController { - flutterWebView.keepAliveId = nil - flutterWebView.dispose(removeFromSuperview: true) - keepAliveWebViews[keepAliveId] = nil - } - } - - public func clearAllCache(includeDiskFiles: Bool, completionHandler: @escaping () -> Void) { - var websiteDataTypes = Set([WKWebsiteDataTypeMemoryCache]) - if includeDiskFiles { - websiteDataTypes.insert(WKWebsiteDataTypeDiskCache) - if #available(macOS 10.13.4, *) { - websiteDataTypes.insert(WKWebsiteDataTypeFetchCache) - } - websiteDataTypes.insert(WKWebsiteDataTypeOfflineWebApplicationCache) - } - let date = NSDate(timeIntervalSince1970: 0) - WKWebsiteDataStore.default().removeData(ofTypes: websiteDataTypes, modifiedSince: date as Date, completionHandler: completionHandler) - } - - public override func dispose() { - super.dispose() - let keepAliveWebViewValues = keepAliveWebViews.values - keepAliveWebViewValues.forEach {(keepAliveWebView: FlutterWebViewController?) in - if let keepAliveId = keepAliveWebView?.keepAliveId { - disposeKeepAlive(keepAliveId: keepAliveId) - } - } - keepAliveWebViews.removeAll() - windowWebViews.removeAll() - webViewForUserAgent = nil - defaultUserAgent = nil - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/InAppWebViewSettings.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/InAppWebViewSettings.swift deleted file mode 100755 index 1bd9e3f835..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/InAppWebViewSettings.swift +++ /dev/null @@ -1,129 +0,0 @@ -// -// InAppWebViewSettings.swift -// flutter_inappwebview -// -// Created by Lorenzo on 21/10/18. -// - -import Foundation -import WebKit - -@objcMembers -public class InAppWebViewSettings: ISettings { - - var useShouldOverrideUrlLoading = false - var useOnLoadResource = false - var useOnDownloadStart = false - @available(*, deprecated, message: "Use InAppWebViewManager.clearAllCache instead.") - var clearCache = false - var userAgent = "" - var applicationNameForUserAgent = "" - var javaScriptEnabled = true - var javaScriptCanOpenWindowsAutomatically = false - var mediaPlaybackRequiresUserGesture = true - var resourceCustomSchemes: [String] = [] - var contentBlockers: [[String: [String : Any]]] = [] - var minimumFontSize = 0 - var useShouldInterceptAjaxRequest = false - var useOnAjaxReadyStateChange = false - var useOnAjaxProgress = false - var interceptOnlyAsyncAjaxRequests = true - var useShouldInterceptFetchRequest = false - var incognito = false - var cacheEnabled = true - var transparentBackground = false - var supportZoom = true - var allowUniversalAccessFromFileURLs = false - var allowFileAccessFromFileURLs = false - - var enableViewportScale = false - var suppressesIncrementalRendering = false - var allowsAirPlayForMediaPlayback = true - var allowsBackForwardNavigationGestures = true - var allowsLinkPreview = true - var isFraudulentWebsiteWarningEnabled = true - var preferredContentMode = 0 - var sharedCookiesEnabled = false - var mediaType: String? = nil - var pageZoom = 1.0 - var limitsNavigationsToAppBoundDomains = false - var useOnNavigationResponse = false - var allowingReadAccessTo: String? = nil - var underPageBackgroundColor: String? - var isTextInteractionEnabled = true - var isSiteSpecificQuirksModeEnabled = true - var upgradeKnownHostsToHTTPS = true - var isElementFullscreenEnabled = true - var isInspectable = false - var shouldPrintBackgrounds = false - var javaScriptHandlersOriginAllowList: [String]? = nil - var javaScriptBridgeEnabled = true - var javaScriptBridgeOriginAllowList: [String]? = nil - var javaScriptBridgeForMainFrameOnly = false - var pluginScriptsOriginAllowList: [String]? = nil - var pluginScriptsForMainFrameOnly = false - var alpha: Double? = nil - - override init(){ - super.init() - } - - override func parse(settings: [String: Any?]) -> InAppWebViewSettings { - var settings = settings // re-assing to be able to use removeValue - // nullable values with primitive type (Int, Double, etc.) - // must be handled here as super.parse will not work - if let alphaValue = settings["alpha"] as? Double { - alpha = alphaValue - settings.removeValue(forKey: "alpha") - } - let _ = super.parse(settings: settings) - return self - } - - override func getRealSettings(obj: InAppWebView?) -> [String: Any?] { - var realSettings: [String: Any?] = toMap() - if let webView = obj { - let configuration = webView.configuration - realSettings["userAgent"] = webView.customUserAgent - realSettings["applicationNameForUserAgent"] = configuration.applicationNameForUserAgent - realSettings["allowsAirPlayForMediaPlayback"] = configuration.allowsAirPlayForMediaPlayback - realSettings["allowsLinkPreview"] = webView.allowsLinkPreview - realSettings["javaScriptCanOpenWindowsAutomatically"] = configuration.preferences.javaScriptCanOpenWindowsAutomatically - if #available(macOS 10.12, *) { - realSettings["mediaPlaybackRequiresUserGesture"] = configuration.mediaTypesRequiringUserActionForPlayback == .all - } - realSettings["minimumFontSize"] = Int(configuration.preferences.minimumFontSize) - realSettings["suppressesIncrementalRendering"] = configuration.suppressesIncrementalRendering - realSettings["allowsBackForwardNavigationGestures"] = webView.allowsBackForwardNavigationGestures - if #available(macOS 10.15, *) { - realSettings["isFraudulentWebsiteWarningEnabled"] = configuration.preferences.isFraudulentWebsiteWarningEnabled - realSettings["preferredContentMode"] = configuration.defaultWebpagePreferences.preferredContentMode.rawValue - } - realSettings["allowUniversalAccessFromFileURLs"] = configuration.value(forKey: "allowUniversalAccessFromFileURLs") as? Bool - realSettings["allowFileAccessFromFileURLs"] = configuration.preferences.value(forKey: "allowFileAccessFromFileURLs") as? Bool - realSettings["javaScriptEnabled"] = configuration.preferences.javaScriptEnabled - if #available(macOS 11.0, *) { - realSettings["mediaType"] = webView.mediaType - realSettings["pageZoom"] = Float(webView.pageZoom) - realSettings["limitsNavigationsToAppBoundDomains"] = configuration.limitsNavigationsToAppBoundDomains - realSettings["javaScriptEnabled"] = configuration.defaultWebpagePreferences.allowsContentJavaScript - } - if #available(macOS 11.3, *) { - realSettings["isTextInteractionEnabled"] = configuration.preferences.isTextInteractionEnabled - realSettings["upgradeKnownHostsToHTTPS"] = configuration.upgradeKnownHostsToHTTPS - } - if #available(macOS 12.0, *) { - realSettings["underPageBackgroundColor"] = webView.underPageBackgroundColor.hexString - } - if #available(macOS 12.3, *) { - realSettings["isSiteSpecificQuirksModeEnabled"] = configuration.preferences.isSiteSpecificQuirksModeEnabled - realSettings["isElementFullscreenEnabled"] = configuration.preferences.isElementFullscreenEnabled - } - if #available(macOS 13.3, *) { - realSettings["isInspectable"] = webView.isInspectable - realSettings["shouldPrintBackgrounds"] = configuration.preferences.shouldPrintBackgrounds - } - } - return realSettings - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebMessage/WebMessageChannel.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebMessage/WebMessageChannel.swift deleted file mode 100644 index 76deada77b..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebMessage/WebMessageChannel.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// WebMessageChannel.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/03/21. -// - -import Foundation -import FlutterMacOS - -public class WebMessageChannel: FlutterMethodCallDelegate { - static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_web_message_channel_" - var id: String - var plugin: InAppWebViewFlutterPlugin? - var channelDelegate: WebMessageChannelChannelDelegate? - weak var webView: InAppWebView? - var ports: [WebMessagePort] = [] - - public init(plugin: InAppWebViewFlutterPlugin, id: String) { - self.id = id - self.plugin = plugin - super.init() - let channel = FlutterMethodChannel(name: WebMessageChannel.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: plugin.registrar.messenger) - self.channelDelegate = WebMessageChannelChannelDelegate(webMessageChannel: self, channel: channel) - self.ports = [ - WebMessagePort(name: "port1", index: 0, webMessageChannelId: self.id, webMessageChannel: self), - WebMessagePort(name: "port2", index: 1, webMessageChannelId: self.id, webMessageChannel: self) - ] - } - - public func initJsInstance(webView: InAppWebView, completionHandler: ((WebMessageChannel?) -> Void)? = nil) { - self.webView = webView - if let webView = self.webView { - webView.evaluateJavascript(source: """ - (function() { - \(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())["\(id)"] = new MessageChannel(); - })(); - """) { (_) in - completionHandler?(self) - } - } else { - completionHandler?(nil) - } - } - - public func toMap() -> [String:Any?] { - return [ - "id": id - ] - } - - public func dispose() { - channelDelegate?.dispose() - channelDelegate = nil - for port in ports { - port.dispose() - } - ports.removeAll() - webView?.evaluateJavascript(source: """ - (function() { - var webMessageChannel = \(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())["\(id)"]; - if (webMessageChannel != null) { - webMessageChannel.port1.close(); - webMessageChannel.port2.close(); - delete \(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())["\(id)"]; - } - })(); - """) - webView = nil - plugin = nil - } - - deinit { - debugPrint("WebMessageChannel - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebMessage/WebMessageChannelChannelDelegate.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebMessage/WebMessageChannelChannelDelegate.swift deleted file mode 100644 index 462141c508..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebMessage/WebMessageChannelChannelDelegate.swift +++ /dev/null @@ -1,103 +0,0 @@ -// -// WebMessageChannelChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation -import FlutterMacOS - -public class WebMessageChannelChannelDelegate: ChannelDelegate { - private weak var webMessageChannel: WebMessageChannel? - - public init(webMessageChannel: WebMessageChannel, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.webMessageChannel = webMessageChannel - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "setWebMessageCallback": - if let _ = webMessageChannel?.webView, let ports = webMessageChannel?.ports, ports.count > 0 { - let index = arguments!["index"] as! Int - let port = ports[index] - do { - try port.setWebMessageCallback { (_) in - result(true) - } - } catch let error as NSError { - result(FlutterError(code: "WebMessageChannel", message: error.domain, details: nil)) - } - - } else { - result(true) - } - break - case "postMessage": - if let webView = webMessageChannel?.webView, let ports = webMessageChannel?.ports, ports.count > 0 { - let index = arguments!["index"] as! Int - let port = ports[index] - var message = WebMessage.fromMap(map: arguments!["message"] as! [String: Any?]) - - var ports: [WebMessagePort] = [] - if let notConnectedPorts = message.ports { - for notConnectedPort in notConnectedPorts { - if let webMessageChannel = webView.webMessageChannels[notConnectedPort.webMessageChannelId] { - ports.append(webMessageChannel.ports[Int(notConnectedPort.index)]) - } - } - } - message.ports = ports - - do { - try port.postMessage(message: message) { (_) in - result(true) - } - } catch let error as NSError { - result(FlutterError(code: "WebMessageChannel", message: error.domain, details: nil)) - } - } else { - result(true) - } - break - case "close": - if let _ = webMessageChannel?.webView, let ports = webMessageChannel?.ports, ports.count > 0 { - let index = arguments!["index"] as! Int - let port = ports[index] - do { - try port.close { (_) in - result(true) - } - } catch let error as NSError { - result(FlutterError(code: "WebMessageChannel", message: error.domain, details: nil)) - } - } else { - result(true) - } - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func onMessage(index: Int64, message: WebMessage?) { - let arguments: [String:Any?] = [ - "index": index, - "message": message?.toMap() - ] - channel?.invokeMethod("onMessage", arguments: arguments) - } - - public override func dispose() { - super.dispose() - webMessageChannel = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebMessage/WebMessageListener.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebMessage/WebMessageListener.swift deleted file mode 100644 index 782861b82f..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebMessage/WebMessageListener.swift +++ /dev/null @@ -1,279 +0,0 @@ -// -// WebMessageListener.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/03/21. -// - -import Foundation -import WebKit -import FlutterMacOS - -public class WebMessageListener: FlutterMethodCallDelegate { - static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_web_message_listener_" - var id: String - var jsObjectName: String - var allowedOriginRules: Set - var channelDelegate: WebMessageListenerChannelDelegate? - weak var webView: InAppWebView? - var plugin: InAppWebViewFlutterPlugin? - - public init(plugin: InAppWebViewFlutterPlugin, id: String, jsObjectName: String, allowedOriginRules: Set) { - self.id = id - self.plugin = plugin - self.jsObjectName = jsObjectName - self.allowedOriginRules = allowedOriginRules - super.init() - let channel = FlutterMethodChannel(name: WebMessageListener.METHOD_CHANNEL_NAME_PREFIX + self.id + "_" + self.jsObjectName, - binaryMessenger: plugin.registrar.messenger) - self.channelDelegate = WebMessageListenerChannelDelegate(webMessageListener: self, channel: channel) - } - - public func assertOriginRulesValid() throws { - for (index, originRule) in allowedOriginRules.enumerated() { - if originRule.isEmpty { - throw NSError(domain: "allowedOriginRules[\(index)] is empty", code: 0) - } - if originRule == "*" { - continue - } - if let url = URL(string: originRule) { - guard let scheme = url.scheme else { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - if scheme == "http" || scheme == "https", url.host == nil || url.host!.isEmpty { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - if scheme != "http", scheme != "https", url.host != nil || url.port != nil { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - if url.host == nil || url.host!.isEmpty, url.port != nil { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - if !url.path.isEmpty { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - if let hostname = url.host { - if let firstIndex = hostname.firstIndex(of: "*") { - let distance = hostname.distance(from: hostname.startIndex, to: firstIndex) - if distance != 0 || (distance == 0 && hostname.prefix(2) != "*.") { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - } - if hostname.hasPrefix("[") { - if !hostname.hasSuffix("]") { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - let fromIndex = hostname.index(hostname.startIndex, offsetBy: 1) - let toIndex = hostname.index(hostname.startIndex, offsetBy: hostname.count - 1) - let indexRange = Range(uncheckedBounds: (lower: fromIndex, upper: toIndex)) - let ipv6 = String(hostname[indexRange]) - if !Util.isIPv6(address: ipv6) { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - } - } - } else { - throw NSError(domain: "allowedOriginRules \(originRule) is invalid", code: 0) - } - } - } - - public func initJsInstance(webView: InAppWebView) { - self.webView = webView - if let webView = self.webView { - let jsObjectNameEscaped = jsObjectName.replacingOccurrences(of: "\'", with: "\\'") - let allowedOriginRulesString = allowedOriginRules.map { (allowedOriginRule) -> String in - if allowedOriginRule == "*" { - return "'*'" - } - let rule = URL(string: allowedOriginRule)! - let host = rule.host != nil ? "'" + rule.host!.replacingOccurrences(of: "\'", with: "\\'") + "'" : "null" - return """ - {scheme: '\(rule.scheme!)', host: \(host), port: \(rule.port != nil ? String(rule.port!) : "null")} - """ - }.joined(separator: ", ") - let source = """ - (function() { - \(WebMessageListener.isOriginAllowedJs) - - var allowedOriginRules = [\(allowedOriginRulesString)]; - var isPageBlank = window.location.href === "about:blank"; - var scheme = !isPageBlank ? window.location.protocol.replace(":", "") : null; - var host = !isPageBlank ? window.location.hostname : null; - var port = !isPageBlank ? window.location.port : null; - if (_isOriginAllowed(allowedOriginRules, scheme, host, port)) { - window['\(jsObjectNameEscaped)'] = new FlutterInAppWebViewWebMessageListener('\(jsObjectNameEscaped)'); - } - })(); - """ - - let allowedOriginRules = webView.settings?.pluginScriptsOriginAllowList - let forMainFrameOnly = webView.settings?.pluginScriptsForMainFrameOnly ?? true - - webView.configuration.userContentController.addPluginScript(PluginScript( - groupName: "WebMessageListener-" + id + "-" + jsObjectName, - source: source, - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: [] - )) - webView.configuration.userContentController.sync(scriptMessageHandler: webView) - } - } - - public static func fromMap(plugin: InAppWebViewFlutterPlugin, map: [String:Any?]?) -> WebMessageListener? { - guard let map = map else { - return nil - } - return WebMessageListener( - plugin: plugin, - id: map["id"] as! String, - jsObjectName: map["jsObjectName"] as! String, - allowedOriginRules: Set(map["allowedOriginRules"] as! [String]) - ) - } - - public func isOriginAllowed(scheme: String?, host: String?, port: Int?) -> Bool { - for allowedOriginRule in allowedOriginRules { - if allowedOriginRule == "*" { - return true - } - if scheme == nil || scheme!.isEmpty { - continue - } - if scheme == nil || scheme!.isEmpty, host == nil || host!.isEmpty, port == nil || port == 0 { - continue - } - if let rule = URL(string: allowedOriginRule) { - let rulePort = rule.port == nil || rule.port == 0 ? (rule.scheme == "https" ? 443 : 80) : rule.port! - let currentPort = port == nil || port == 0 ? (scheme == "https" ? 443 : 80) : port! - var IPv6: String? = nil - if let hostname = rule.host, hostname.hasPrefix("[") { - let fromIndex = hostname.index(hostname.startIndex, offsetBy: 1) - let toIndex = hostname.index(hostname.startIndex, offsetBy: hostname.count - 1) - let indexRange = Range(uncheckedBounds: (lower: fromIndex, upper: toIndex)) - do { - IPv6 = try Util.normalizeIPv6(address: String(hostname[indexRange])) - } catch {} - } - var hostIPv6: String? = nil - if let host = host, Util.isIPv6(address: host) { - do { - hostIPv6 = try Util.normalizeIPv6(address: host) - } catch {} - } - - let schemeAllowed = scheme != nil && !scheme!.isEmpty && scheme == rule.scheme - - let hostAllowed = rule.host == nil || - rule.host!.isEmpty || - host == rule.host || - (rule.host!.hasPrefix("*") && host != nil && host!.hasSuffix(rule.host!.split(separator: "*", omittingEmptySubsequences: false)[1])) || - (hostIPv6 != nil && IPv6 != nil && hostIPv6 == IPv6) - - let portAllowed = rulePort == currentPort - - if schemeAllowed, hostAllowed, portAllowed { - return true - } - } - } - return false - } - - private static let isOriginAllowedJs = """ - var _normalizeIPv6 = function(ip_string) { - // replace ipv4 address if any - var ipv4 = ip_string.match(/(.*:)([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$)/); - if (ipv4) { - ip_string = ipv4[1]; - ipv4 = ipv4[2].match(/[0-9]+/g); - for (var i = 0;i < 4;i ++) { - var byte = parseInt(ipv4[i],10); - ipv4[i] = ("0" + byte.toString(16)).substr(-2); - } - ip_string += ipv4[0] + ipv4[1] + ':' + ipv4[2] + ipv4[3]; - } - - // take care of leading and trailing :: - ip_string = ip_string.replace(/^:|:$/g, ''); - - var ipv6 = ip_string.split(':'); - - for (var i = 0; i < ipv6.length; i ++) { - var hex = ipv6[i]; - if (hex != "") { - // normalize leading zeros - ipv6[i] = ("0000" + hex).substr(-4); - } - else { - // normalize grouped zeros :: - hex = []; - for (var j = ipv6.length; j <= 8; j ++) { - hex.push('0000'); - } - ipv6[i] = hex.join(':'); - } - } - - return ipv6.join(':'); - }; - - var _isOriginAllowed = function(allowedOriginRules, scheme, host, port) { - for (var rule of allowedOriginRules) { - if (rule === "*") { - return true; - } - if (scheme == null || scheme === "") { - continue; - } - if ((scheme == null || scheme === "") && (host == null || host === "") && (port === 0 || port === "" || port == null)) { - continue; - } - var rulePort = rule.port == null || rule.port === 0 ? (rule.scheme == "https" ? 443 : 80) : rule.port; - var currentPort = port === 0 || port === "" || port == null ? (scheme == "https" ? 443 : 80) : port; - var IPv6 = null; - if (rule.host != null && rule.host[0] === "[") { - try { - IPv6 = _normalizeIPv6(rule.host.substring(1, rule.host.length - 1)); - } catch {} - } - var hostIPv6 = null; - try { - hostIPv6 = _normalizeIPv6(host); - } catch {} - - var schemeAllowed = scheme == rule.scheme; - - var hostAllowed = rule.host == null || - rule.host === "" || - host === rule.host || - (rule.host[0] === "*" && host != null && host.indexOf(rule.host.split("*")[1]) >= 0) || - (hostIPv6 != null && IPv6 != null && hostIPv6 === IPv6); - - var portAllowed = rulePort === currentPort; - - if (schemeAllowed && hostAllowed && portAllowed) { - return true; - } - } - return false; - }; - """ - - - public func dispose() { - channelDelegate?.dispose() - channelDelegate = nil - webView = nil - plugin = nil - } - - deinit { - debugPrint("WebMessageListener - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebMessage/WebMessageListenerChannelDelegate.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebMessage/WebMessageListenerChannelDelegate.swift deleted file mode 100644 index 39304daeef..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebMessage/WebMessageListenerChannelDelegate.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// WebMessageListenerChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation -import FlutterMacOS - -public class WebMessageListenerChannelDelegate: ChannelDelegate { - private weak var webMessageListener: WebMessageListener? - - public init(webMessageListener: WebMessageListener, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.webMessageListener = webMessageListener - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "postMessage": - if let webView = webMessageListener?.webView, let jsObjectName = webMessageListener?.jsObjectName { - let jsObjectNameEscaped = jsObjectName.replacingOccurrences(of: "\'", with: "\\'") - let message = WebMessage.fromMap(map: arguments!["message"] as! [String: Any?]) - - let source = """ - (function() { - var webMessageListener = window['\(jsObjectNameEscaped)']; - if (webMessageListener != null) { - var event = {data: \(message.jsData)}; - if (webMessageListener.onmessage != null) { - webMessageListener.onmessage(event); - } - for (var listener of webMessageListener.listeners) { - listener(event); - } - } - })(); - """ - webView.evaluateJavascript(source: source) { (_) in - result(true) - } - } else { - result(true) - } - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func onPostMessage(message: WebMessage?, sourceOrigin: URL?, isMainFrame: Bool) { - let arguments: [String:Any?] = [ - "message": message?.toMap(), - "sourceOrigin": sourceOrigin?.absoluteString, - "isMainFrame": isMainFrame - ] - channel?.invokeMethod("onPostMessage", arguments: arguments) - } - - public override func dispose() { - super.dispose() - webMessageListener = nil - } - - deinit { - dispose() - } -} - diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebViewChannelDelegate.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebViewChannelDelegate.swift deleted file mode 100644 index 27389babb7..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebViewChannelDelegate.swift +++ /dev/null @@ -1,1211 +0,0 @@ -// -// WebViewChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 06/05/22. -// - -import Foundation -import WebKit -import FlutterMacOS - -public class WebViewChannelDelegate: ChannelDelegate { - private weak var webView: InAppWebView? - - public init(webView: InAppWebView, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.webView = webView - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - guard let method = WebViewChannelDelegateMethods.init(rawValue: call.method) else { - result(FlutterMethodNotImplemented) - return - } - - switch method { - case .getUrl: - result(webView?.url?.absoluteString) - break - case .getTitle: - result(webView?.title) - break - case .getProgress: - result( (webView != nil) ? Int(webView!.estimatedProgress * 100) : nil ) - break - case .loadUrl: - let urlRequest = arguments!["urlRequest"] as! [String:Any?] - let allowingReadAccessTo = arguments!["allowingReadAccessTo"] as? String - var allowingReadAccessToURL: URL? = nil - if let allowingReadAccessTo = allowingReadAccessTo { - allowingReadAccessToURL = URL(string: allowingReadAccessTo) - } - webView?.loadUrl(urlRequest: URLRequest.init(fromPluginMap: urlRequest), allowingReadAccessTo: allowingReadAccessToURL) - result(true) - break - case .postUrl: - if let webView = webView { - let url = arguments!["url"] as! String - let postData = arguments!["postData"] as! FlutterStandardTypedData - webView.postUrl(url: URL(string: url)!, postData: postData.data) - } - result(true) - break - case .loadData: - let data = arguments!["data"] as! String - let mimeType = arguments!["mimeType"] as! String - let encoding = arguments!["encoding"] as! String - let baseUrl = URL(string: arguments!["baseUrl"] as! String)! - let allowingReadAccessTo = arguments!["allowingReadAccessTo"] as? String - var allowingReadAccessToURL: URL? = nil - if let allowingReadAccessTo = allowingReadAccessTo { - allowingReadAccessToURL = URL(string: allowingReadAccessTo) - } - webView?.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl, allowingReadAccessTo: allowingReadAccessToURL) - result(true) - break - case .loadFile: - let assetFilePath = arguments!["assetFilePath"] as! String - - do { - try webView?.loadFile(assetFilePath: assetFilePath) - } - catch let error as NSError { - result(FlutterError(code: "WebViewChannelDelegate", message: error.domain, details: nil)) - return - } - result(true) - break - case .evaluateJavascript: - if let webView = webView { - let source = arguments!["source"] as! String - let contentWorldMap = arguments!["contentWorld"] as? [String:Any?] - if #available(macOS 11.0, *), let contentWorldMap = contentWorldMap { - let contentWorld = WKContentWorld.fromMap(map: contentWorldMap, windowId: webView.windowId)! - webView.evaluateJavascript(source: source, contentWorld: contentWorld) { (value) in - result(value) - } - } else { - webView.evaluateJavascript(source: source) { (value) in - result(value) - } - } - } - else { - result(nil) - } - break - case .injectJavascriptFileFromUrl: - let urlFile = arguments!["urlFile"] as! String - let scriptHtmlTagAttributes = arguments!["scriptHtmlTagAttributes"] as? [String:Any?] - webView?.injectJavascriptFileFromUrl(urlFile: urlFile, scriptHtmlTagAttributes: scriptHtmlTagAttributes) - result(true) - break - case .injectCSSCode: - let source = arguments!["source"] as! String - webView?.injectCSSCode(source: source) - result(true) - break - case .injectCSSFileFromUrl: - let urlFile = arguments!["urlFile"] as! String - let cssLinkHtmlTagAttributes = arguments!["cssLinkHtmlTagAttributes"] as? [String:Any?] - webView?.injectCSSFileFromUrl(urlFile: urlFile, cssLinkHtmlTagAttributes: cssLinkHtmlTagAttributes) - result(true) - break - case .reload: - webView?.reload() - result(true) - break - case .goBack: - webView?.goBack() - result(true) - break - case .canGoBack: - result(webView?.canGoBack ?? false) - break - case .goForward: - webView?.goForward() - result(true) - break - case .canGoForward: - result(webView?.canGoForward ?? false) - break - case .goBackOrForward: - let steps = arguments!["steps"] as! Int - webView?.goBackOrForward(steps: steps) - result(true) - break - case .canGoBackOrForward: - let steps = arguments!["steps"] as! Int - result(webView?.canGoBackOrForward(steps: steps) ?? false) - break - case .stopLoading: - webView?.stopLoading() - result(true) - break - case .isLoading: - result(webView?.isLoading ?? false) - break - case .takeScreenshot: - if let webView = webView, #available(macOS 10.13, *) { - let screenshotConfiguration = arguments!["screenshotConfiguration"] as? [String: Any?] - webView.takeScreenshot(with: screenshotConfiguration, completionHandler: { (screenshot) -> Void in - result(screenshot) - }) - } - else { - result(nil) - } - break - case .setSettings: - if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController { - let inAppBrowserSettings = InAppBrowserSettings() - let inAppBrowserSettingsMap = arguments!["settings"] as! [String: Any] - let _ = inAppBrowserSettings.parse(settings: inAppBrowserSettingsMap) - iabController.setSettings(newSettings: inAppBrowserSettings, newSettingsMap: inAppBrowserSettingsMap) - } else { - let inAppWebViewSettings = InAppWebViewSettings() - let inAppWebViewSettingsMap = arguments!["settings"] as! [String: Any] - let _ = inAppWebViewSettings.parse(settings: inAppWebViewSettingsMap) - webView?.setSettings(newSettings: inAppWebViewSettings, newSettingsMap: inAppWebViewSettingsMap) - } - result(true) - break - case .getSettings: - if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController { - result(iabController.getSettings()) - } else { - result(webView?.getSettings()) - } - break - case .close: - if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController { - iabController.close() - result(true) - } else { - result(FlutterMethodNotImplemented) - } - break - case .show: - if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController { - iabController.show() - result(true) - } else { - result(FlutterMethodNotImplemented) - } - break - case .hide: - if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController { - iabController.hide() - result(true) - } else { - result(FlutterMethodNotImplemented) - } - break - case .isHidden: - if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController { - result(iabController.isHidden) - } else { - result(FlutterMethodNotImplemented) - } - break - case .getCopyBackForwardList: - result(webView?.getCopyBackForwardList()) - break - case .findAll: - if let webView = webView, let findInteractionController = webView.findInteractionController { - let find = arguments!["find"] as! String - findInteractionController.findAll(find: find, completionHandler: {(value, error) in - if error != nil { - result(FlutterError(code: "WebViewChannelDelegate", message: error?.localizedDescription, details: nil)) - return - } - result(true) - }) - } else { - result(false) - } - break - case .findNext: - if let webView = webView, let findInteractionController = webView.findInteractionController { - let forward = arguments!["forward"] as! Bool - findInteractionController.findNext(forward: forward, completionHandler: {(value, error) in - if error != nil { - result(FlutterError(code: "WebViewChannelDelegate", message: error?.localizedDescription, details: nil)) - return - } - result(true) - }) - } else { - result(false) - } - break - case .clearMatches: - if let webView = webView, let findInteractionController = webView.findInteractionController { - findInteractionController.clearMatches(completionHandler: {(value, error) in - if error != nil { - result(FlutterError(code: "WebViewChannelDelegate", message: error?.localizedDescription, details: nil)) - return - } - result(true) - }) - } else { - result(false) - } - break - case .clearCache: - webView?.clearCache() - result(true) - break - case .scrollTo: - let x = arguments!["x"] as! Int - let y = arguments!["y"] as! Int - let animated = arguments!["animated"] as! Bool - webView?.scrollTo(x: x, y: y, animated: animated) - result(true) - break - case .scrollBy: - let x = arguments!["x"] as! Int - let y = arguments!["y"] as! Int - let animated = arguments!["animated"] as! Bool - webView?.scrollBy(x: x, y: y, animated: animated) - result(true) - break - case .pauseTimers: - webView?.pauseTimers() - result(true) - break - case .resumeTimers: - webView?.resumeTimers() - result(true) - break - case .printCurrentPage: - if let webView = webView { - let settings = PrintJobSettings() - if let settingsMap = arguments!["settings"] as? [String: Any?] { - let _ = settings.parse(settings: settingsMap) - } - result(webView.printCurrentPage(settings: settings)) - } else { - result(nil) - } - break - case .getContentHeight: - webView?.getContentHeight { contentHeight, error in - if let error = error { - print(error) - result(nil) - return - } - result(contentHeight) - } - break - case .getContentWidth: - webView?.getContentWidth { contentWidth, error in - if let error = error { - print(error) - result(nil) - return - } - result(contentWidth) - } - break - case .reloadFromOrigin: - webView?.reloadFromOrigin() - result(true) - break - case .getOriginalUrl: - result(webView?.getOriginalUrl()?.absoluteString) - break - case .getZoomScale: - result(nil) - break - case .hasOnlySecureContent: - result(webView?.hasOnlySecureContent ?? false) - break - case .getSelectedText: - if let webView = webView { - webView.getSelectedText { (value, error) in - if let err = error { - print(err.localizedDescription) - result("") - return - } - result(value) - } - } - else { - result(nil) - } - break - case .getScrollX: - if let webView = webView { - webView.getScrollX { scrollX, error in - if let error = error { - print(error) - result(nil) - return - } - result(scrollX) - } - - } else { - result(nil) - } - break - case .getScrollY: - if let webView = webView { - webView.getScrollY { scrollY, error in - if let error = error { - print(error) - result(nil) - return - } - result(scrollY) - } - - } else { - result(nil) - } - break - case .clearFocus: - result(webView?.clearFocus()) - break - case .requestFocus: - result(webView?.requestFocus()) - break - case .getCertificate: - result(webView?.getCertificate()?.toMap()) - break - case .addUserScript: - if let webView = webView { - let userScriptMap = arguments!["userScript"] as! [String: Any?] - let userScript = UserScript.fromMap(map: userScriptMap, windowId: webView.windowId)! - webView.configuration.userContentController.addUserOnlyScript(userScript) - webView.configuration.userContentController.sync(scriptMessageHandler: webView) - } - result(true) - break - case .removeUserScript: - let index = arguments!["index"] as! Int - let userScriptMap = arguments!["userScript"] as! [String: Any?] - let userScript = UserScript.fromMap(map: userScriptMap, windowId: webView?.windowId)! - webView?.configuration.userContentController.removeUserOnlyScript(at: index, injectionTime: userScript.injectionTime) - result(true) - break - case .removeUserScriptsByGroupName: - let groupName = arguments!["groupName"] as! String - webView?.configuration.userContentController.removeUserOnlyScripts(with: groupName) - result(true) - break - case .removeAllUserScripts: - webView?.configuration.userContentController.removeAllUserOnlyScripts() - result(true) - break - case .callAsyncJavaScript: - if let webView = webView { - if #available(macOS 11.0, *) { // on iOS 14.0, for some reason, it crashes - let functionBody = arguments!["functionBody"] as! String - let functionArguments = arguments!["arguments"] as! [String:Any] - var contentWorld = WKContentWorld.page - if let contentWorldMap = arguments!["contentWorld"] as? [String:Any?] { - contentWorld = WKContentWorld.fromMap(map: contentWorldMap, windowId: webView.windowId)! - } - webView.callAsyncJavaScript(functionBody: functionBody, arguments: functionArguments, contentWorld: contentWorld) { (value) in - result(value) - } - } else { - let functionBody = arguments!["functionBody"] as! String - let functionArguments = arguments!["arguments"] as! [String:Any] - webView.callAsyncJavaScript(functionBody: functionBody, arguments: functionArguments) { (value) in - result(value) - } - } - } - else { - result(nil) - } - break - case .createPdf: - if let webView = webView, #available(macOS 11.0, *) { - let configuration = arguments!["pdfConfiguration"] as? [String: Any?] - webView.createPdf(configuration: configuration, completionHandler: { (pdf) -> Void in - result(pdf) - }) - } - else { - result(nil) - } - break - case .createWebArchiveData: - if let webView = webView, #available(macOS 11.0, *) { - webView.createWebArchiveData(dataCompletionHandler: { (webArchiveData) -> Void in - result(webArchiveData) - }) - } - else { - result(nil) - } - break - case .saveWebArchive: - if let webView = webView, #available(macOS 11.0, *) { - let filePath = arguments!["filePath"] as! String - let autoname = arguments!["autoname"] as! Bool - webView.saveWebArchive(filePath: filePath, autoname: autoname, completionHandler: { (path) -> Void in - result(path) - }) - } - else { - result(nil) - } - break - case .isSecureContext: - if let webView = webView { - webView.isSecureContext(completionHandler: { (isSecureContext) in - result(isSecureContext) - }) - } - else { - result(false) - } - break - case .createWebMessageChannel: - if let webView = webView { - let _ = webView.createWebMessageChannel { (webMessageChannel) in - guard let webMessageChannel = webMessageChannel else { - result(nil) - return - } - result(webMessageChannel.toMap()) - } - } else { - result(nil) - } - break - case .postWebMessage: - if let webView = webView { - var message = WebMessage.fromMap(map: arguments!["message"] as! [String: Any?]) - let targetOrigin = arguments!["targetOrigin"] as! String - - var ports: [WebMessagePort] = [] - if let notConnectedPorts = message.ports { - for notConnectedPort in notConnectedPorts { - if let webMessageChannel = webView.webMessageChannels[notConnectedPort.webMessageChannelId] { - ports.append(webMessageChannel.ports[Int(notConnectedPort.index)]) - } - } - } - message.ports = ports - - do { - try webView.postWebMessage(message: message, targetOrigin: targetOrigin) { (_) in - result(true) - } - } catch let error as NSError { - result(FlutterError(code: "WebViewChannelDelegate", message: error.domain, details: nil)) - } - } else { - result(false) - } - break - case .addWebMessageListener: - if let webView = webView, let plugin = webView.plugin { - let webMessageListenerMap = arguments!["webMessageListener"] as! [String: Any?] - let webMessageListener = WebMessageListener.fromMap(plugin: plugin, map: webMessageListenerMap)! - do { - try webView.addWebMessageListener(webMessageListener: webMessageListener) - result(false) - } catch let error as NSError { - result(FlutterError(code: "WebViewChannelDelegate", message: error.domain, details: nil)) - } - } else { - result(false) - } - break - case .canScrollVertically: - if let webView = webView { - webView.canScrollVertically { canScrollVertically, error in - if let error = error { - print(error) - result(false) - return - } - result(canScrollVertically) - } - } else { - result(false) - } - break - case .canScrollHorizontally: - if let webView = webView { - webView.canScrollHorizontally { canScrollHorizontally, error in - if let error = error { - print(error) - result(false) - return - } - result(canScrollHorizontally) - } - } else { - result(false) - } - break - case .pauseAllMediaPlayback: - if let webView = webView, #available(macOS 12.0 , *) { - webView.pauseAllMediaPlayback(completionHandler: { () -> Void in - result(true) - }) - } else { - result(false) - } - break - case .setAllMediaPlaybackSuspended: - if let webView = webView, #available(macOS 12.0 , *) { - let suspended = arguments!["suspended"] as! Bool - webView.setAllMediaPlaybackSuspended(suspended, completionHandler: { () -> Void in - result(true) - }) - } else { - result(false) - } - break - case .closeAllMediaPresentations: - if let webView = self.webView, #available(macOS 11.3, *) { - if #available(macOS 12.0, *) { - webView.closeAllMediaPresentations { - result(true) - } - } else { - webView.closeAllMediaPresentations() - result(true) - } - } else { - result(false) - } - break - case .requestMediaPlaybackState: - if let webView = webView, #available(macOS 12.0, *) { - webView.requestMediaPlaybackState(completionHandler: { (state) -> Void in - result(state.rawValue) - }) - } else { - result(nil) - } - break - case .getMetaThemeColor: - if let webView = webView, #available(macOS 12.0, *) { - result(webView.themeColor?.hexString) - } else { - result(nil) - } - break - case .isInFullscreen: - if let webView = webView { - if #available(macOS 13.0, *) { - result(webView.fullscreenState == .inFullscreen) - } else { - result(webView.inFullscreen) - } - } - else { - result(false) - } - break - case .getCameraCaptureState: - if let webView = webView, #available(macOS 12.0, *) { - result(webView.cameraCaptureState.rawValue) - } else { - result(nil) - } - break - case .setCameraCaptureState: - if let webView = webView, #available(macOS 12.0, *) { - let state = WKMediaCaptureState.init(rawValue: arguments!["state"] as! Int) ?? WKMediaCaptureState.none - webView.setCameraCaptureState(state) { - result(true) - } - } else { - result(false) - } - break - case .getMicrophoneCaptureState: - if let webView = webView, #available(macOS 12.0, *) { - result(webView.microphoneCaptureState.rawValue) - } else { - result(nil) - } - break - case .setMicrophoneCaptureState: - if let webView = webView, #available(macOS 12.0, *) { - let state = WKMediaCaptureState.init(rawValue: arguments!["state"] as! Int) ?? WKMediaCaptureState.none - webView.setMicrophoneCaptureState(state) { - result(true) - } - } else { - result(false) - } - break - case .loadSimulatedRequest: - if let webView = webView, #available(macOS 12.0, *) { - let request = URLRequest.init(fromPluginMap: arguments!["urlRequest"] as! [String:Any?]) - let data = arguments!["data"] as! FlutterStandardTypedData - var response: URLResponse? = nil - if let urlResponse = arguments!["urlResponse"] as? [String:Any?] { - response = URLResponse.init(fromPluginMap: urlResponse) - } - if let response = response { - webView.loadSimulatedRequest(request, response: response, responseData: data.data) - } else { - webView.loadSimulatedRequest(request, responseHTML: String(decoding: data.data, as: UTF8.self)) - } - result(true) - } else { - result(false) - } - break - case .saveState: - if let webView = webView, #available(macOS 12.0, *) { - result(webView.saveState()) - } else { - result(nil) - } - break - case .restoreState: - if let webView = webView, #available(macOS 12.0, *) { - let state = arguments!["state"] as! FlutterStandardTypedData - webView.restoreState(state: state.data) - result(true) - } else { - result(false) - } - break - } - } - - @available(*, deprecated, message: "Use FindInteractionChannelDelegate.onFindResultReceived instead.") - public func onFindResultReceived(activeMatchOrdinal: Int, numberOfMatches: Int, isDoneCounting: Bool) { - let arguments: [String : Any?] = [ - "activeMatchOrdinal": activeMatchOrdinal, - "numberOfMatches": numberOfMatches, - "isDoneCounting": isDoneCounting - ] - channel?.invokeMethod("onFindResultReceived", arguments: arguments) - } - - public func onLongPressHitTestResult(hitTestResult: HitTestResult) { - channel?.invokeMethod("onLongPressHitTestResult", arguments: hitTestResult.toMap()) - } - - public func onScrollChanged(x: Int, y: Int) { - let arguments: [String: Any?] = ["x": x, "y": y] - channel?.invokeMethod("onScrollChanged", arguments: arguments) - } - - public func onDownloadStarting(request: DownloadStartRequest) { - channel?.invokeMethod("onDownloadStarting", arguments: request.toMap()) - } - - public func onCreateContextMenu(hitTestResult: HitTestResult) { - channel?.invokeMethod("onCreateContextMenu", arguments: hitTestResult.toMap()) - } - - public func onOverScrolled(x: Int, y: Int, clampedX: Bool, clampedY: Bool) { - let arguments: [String: Any?] = ["x": x, "y": y, "clampedX": clampedX, "clampedY": clampedY] - channel?.invokeMethod("onOverScrolled", arguments: arguments) - } - - public func onContextMenuActionItemClicked(id: Any, title: String) { - let arguments: [String: Any?] = [ - "id": id, - "iosId": id is Int64 ? String(id as! Int64) : id as! String, - "androidId": nil, - "title": title - ] - channel?.invokeMethod("onContextMenuActionItemClicked", arguments: arguments) - } - - public func onHideContextMenu() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onHideContextMenu", arguments: arguments) - } - - public func onEnterFullscreen() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onEnterFullscreen", arguments: arguments) - } - - public func onExitFullscreen() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onExitFullscreen", arguments: arguments) - } - - public class JsAlertCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return JsAlertResponse.fromMap(map: obj as? [String:Any?]) - } - } - } - - public func onJsAlert(url: URL?, message: String, isMainFrame: Bool, callback: JsAlertCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - let arguments: [String: Any?] = [ - "url": url?.absoluteString, - "message": message, - "isMainFrame": isMainFrame - ] - channel?.invokeMethod("onJsAlert", arguments: arguments, callback: callback) - } - - public class JsConfirmCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return JsConfirmResponse.fromMap(map: obj as? [String:Any?]) - } - } - } - - public func onJsConfirm(url: URL?, message: String, isMainFrame: Bool, callback: JsConfirmCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - let arguments: [String: Any?] = [ - "url": url?.absoluteString, - "message": message, - "isMainFrame": isMainFrame - ] - channel?.invokeMethod("onJsConfirm", arguments: arguments, callback: callback) - } - - public class JsPromptCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return JsPromptResponse.fromMap(map: obj as? [String:Any?]) - } - } - } - - public func onJsPrompt(url: URL?, message: String, defaultValue: String?, isMainFrame: Bool, callback: JsPromptCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - let arguments: [String: Any?] = [ - "url": url?.absoluteString, - "message": message, - "defaultValue": defaultValue, - "isMainFrame": isMainFrame - ] - channel?.invokeMethod("onJsPrompt", arguments: arguments, callback: callback) - } - - public class CreateWindowCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return obj is Bool && obj as! Bool - } - } - } - - public func onCreateWindow(createWindowAction: CreateWindowAction, callback: CreateWindowCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - channel?.invokeMethod("onCreateWindow", arguments: createWindowAction.toMap(), callback: callback) - } - - public func onCloseWindow() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onCloseWindow", arguments: arguments) - } - - public func onConsoleMessage(message: String, messageLevel: Int) { - let arguments: [String: Any?] = [ - "message": message, - "messageLevel": messageLevel - ] - channel?.invokeMethod("onConsoleMessage", arguments: arguments) - } - - public func onProgressChanged(progress: Int) { - let arguments: [String: Any?] = [ - "progress": progress - ] - channel?.invokeMethod("onProgressChanged", arguments: arguments) - } - - public func onTitleChanged(title: String?) { - let arguments: [String: Any?] = [ - "title": title - ] - channel?.invokeMethod("onTitleChanged", arguments: arguments) - } - - public class PermissionRequestCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return PermissionResponse.fromMap(map: obj as? [String:Any?]) - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func onPermissionRequest(request: PermissionRequest, callback: PermissionRequestCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - channel?.invokeMethod("onPermissionRequest", arguments: request.toMap(), callback: callback) - } - - public class ShouldOverrideUrlLoadingCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - if let action = obj as? Int { - return WKNavigationActionPolicy.init(rawValue: action) ?? WKNavigationActionPolicy.cancel - } - return WKNavigationActionPolicy.cancel - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func shouldOverrideUrlLoading(navigationAction: WKNavigationAction, callback: ShouldOverrideUrlLoadingCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - channel?.invokeMethod("shouldOverrideUrlLoading", arguments: navigationAction.toMap(), callback: callback) - } - - public func onLoadStart(url: String?) { - let arguments: [String: Any?] = ["url": url] - channel?.invokeMethod("onLoadStart", arguments: arguments) - } - - public func onLoadStop(url: String?) { - let arguments: [String: Any?] = ["url": url] - channel?.invokeMethod("onLoadStop", arguments: arguments) - } - - public func onUpdateVisitedHistory(url: String?, isReload: Bool?) { - let arguments: [String: Any?] = [ - "url": url, - "isReload": nil - ] - channel?.invokeMethod("onUpdateVisitedHistory", arguments: arguments) - } - - public func onReceivedError(request: WebResourceRequest, error: WebResourceError) { - let arguments: [String: Any?] = [ - "request": request.toMap(), - "error": error.toMap() - ] - channel?.invokeMethod("onReceivedError", arguments: arguments) - } - - public func onReceivedHttpError(request: WebResourceRequest, errorResponse: WebResourceResponse) { - let arguments: [String: Any?] = [ - "request": request.toMap(), - "errorResponse": errorResponse.toMap() - ] - channel?.invokeMethod("onReceivedHttpError", arguments: arguments) - } - - public class ReceivedHttpAuthRequestCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return HttpAuthResponse.fromMap(map: obj as? [String:Any?]) - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func onReceivedHttpAuthRequest(challenge: HttpAuthenticationChallenge, callback: ReceivedHttpAuthRequestCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - // workaround for ProtectionSpace.toMap() SSL Certificate - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global().async { - let arguments = challenge.toMap() - DispatchQueue.main.async { [weak self] in - if self?.channel == nil { - callback.defaultBehaviour(nil) - return - } - self?.channel?.invokeMethod("onReceivedHttpAuthRequest", arguments: arguments, callback: callback) - } - } - } - - public class ReceivedServerTrustAuthRequestCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return ServerTrustAuthResponse.fromMap(map: obj as? [String:Any?]) - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func onReceivedServerTrustAuthRequest(challenge: ServerTrustChallenge, callback: ReceivedServerTrustAuthRequestCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - // workaround for ProtectionSpace.toMap() SSL Certificate - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global().async { - let arguments = challenge.toMap() - DispatchQueue.main.async { [weak self] in - if self?.channel == nil { - callback.defaultBehaviour(nil) - return - } - self?.channel?.invokeMethod("onReceivedServerTrustAuthRequest", arguments: arguments, callback: callback) - } - } - } - - public class ReceivedClientCertRequestCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return ClientCertResponse.fromMap(map: obj as? [String:Any?]) - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func onReceivedClientCertRequest(challenge: ClientCertChallenge, callback: ReceivedClientCertRequestCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - // workaround for ProtectionSpace.toMap() SSL Certificate - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global().async { - let arguments = challenge.toMap() - DispatchQueue.main.async { [weak self] in - if self?.channel == nil { - callback.defaultBehaviour(nil) - return - } - self?.channel?.invokeMethod("onReceivedClientCertRequest", arguments: arguments, callback: callback) - } - } - } - - public func onZoomScaleChanged(newScale: Float, oldScale: Float) { - let arguments: [String: Any?] = [ - "newScale": newScale, - "oldScale": oldScale - ] - channel?.invokeMethod("onZoomScaleChanged", arguments: arguments) - } - - public func onPageCommitVisible(url: String?) { - let arguments: [String: Any?] = [ - "url": url - ] - channel?.invokeMethod("onPageCommitVisible", arguments: arguments) - } - - public class LoadResourceWithCustomSchemeCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return CustomSchemeResponse.fromMap(map: obj as? [String:Any?]) - } - } - } - - public func onLoadResourceWithCustomScheme(request: WebResourceRequest, callback: LoadResourceWithCustomSchemeCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - let arguments: [String: Any?] = ["request": request.toMap()] - channel?.invokeMethod("onLoadResourceWithCustomScheme", arguments: arguments, callback: callback) - } - - public class CallJsHandlerCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return obj - } - } - } - - public func onCallJsHandler(handlerName: String, data: JavaScriptHandlerFunctionData, callback: CallJsHandlerCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - let arguments: [String: Any?] = [ - "handlerName": handlerName, - "data": data.toMap() - ] - channel?.invokeMethod("onCallJsHandler", arguments: arguments, callback: callback) - } - - public class NavigationResponseCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - if let action = obj as? Int { - return WKNavigationResponsePolicy.init(rawValue: action) ?? WKNavigationResponsePolicy.cancel - } - return WKNavigationResponsePolicy.cancel - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func onNavigationResponse(navigationResponse: WKNavigationResponse, callback: NavigationResponseCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - channel?.invokeMethod("onNavigationResponse", arguments: navigationResponse.toMap(), callback: callback) - } - - public class ShouldAllowDeprecatedTLSCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - if let action = obj as? Int { - return action == 1 - } - return false - } - } - - deinit { - self.defaultBehaviour(nil) - } - } - - public func shouldAllowDeprecatedTLS(challenge: URLAuthenticationChallenge, callback: ShouldAllowDeprecatedTLSCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - // workaround for ProtectionSpace.toMap() SSL Certificate - // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global().async { - let arguments = challenge.toMap() - DispatchQueue.main.async { [weak self] in - if self?.channel == nil { - callback.defaultBehaviour(nil) - return - } - self?.channel?.invokeMethod("shouldAllowDeprecatedTLS", arguments: arguments, callback: callback) - } - } - } - - public func onWebContentProcessDidTerminate() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onWebContentProcessDidTerminate", arguments: arguments) - } - - public func onDidReceiveServerRedirectForProvisionalNavigation() { - let arguments: [String: Any?] = [:] - channel?.invokeMethod("onDidReceiveServerRedirectForProvisionalNavigation", arguments: arguments) - } - - @available(macOS 12.0, *) - public func onCameraCaptureStateChanged(oldState: WKMediaCaptureState?, newState: WKMediaCaptureState?) { - let arguments = [ - "oldState": oldState?.rawValue, - "newState": newState?.rawValue - ] - channel?.invokeMethod("onCameraCaptureStateChanged", arguments: arguments) - } - - @available(macOS 12.0, *) - public func onMicrophoneCaptureStateChanged(oldState: WKMediaCaptureState?, newState: WKMediaCaptureState?) { - let arguments = [ - "oldState": oldState?.rawValue, - "newState": newState?.rawValue - ] - channel?.invokeMethod("onMicrophoneCaptureStateChanged", arguments: arguments) - } - - public class PrintRequestCallback: BaseCallbackResult { - override init() { - super.init() - self.decodeResult = { (obj: Any?) in - return obj is Bool && obj as! Bool - } - } - } - - public func onPrintRequest(url: URL?, printJobId: String?, callback: PrintRequestCallback) { - if channel == nil { - callback.defaultBehaviour(nil) - return - } - let arguments = [ - "url": url?.absoluteString, - "printJobId": printJobId, - ] - channel?.invokeMethod("onPrintRequest", arguments: arguments, callback: callback) - } - - internal func _onMouseDown(callback: @escaping () -> Void) { - if channel == nil { - return - } - let arguments: [String:Any] = [:]; - channel?.invokeMethod("_onMouseDown", arguments: arguments) {(result) -> Void in - callback() - } - } - - public override func dispose() { - super.dispose() - webView = nil - } - - deinit { - debugPrint("WebViewChannelDelegate - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebViewChannelDelegateMethods.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebViewChannelDelegateMethods.swift deleted file mode 100644 index b432dc6088..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebView/WebViewChannelDelegateMethods.swift +++ /dev/null @@ -1,91 +0,0 @@ -// -// WebViewChannelDelegateMethods.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 08/10/22. -// - -import Foundation - -public enum WebViewChannelDelegateMethods: String { - case getUrl = "getUrl" - case getTitle = "getTitle" - case getProgress = "getProgress" - case loadUrl = "loadUrl" - case postUrl = "postUrl" - case loadData = "loadData" - case loadFile = "loadFile" - case evaluateJavascript = "evaluateJavascript" - case injectJavascriptFileFromUrl = "injectJavascriptFileFromUrl" - case injectCSSCode = "injectCSSCode" - case injectCSSFileFromUrl = "injectCSSFileFromUrl" - case reload = "reload" - case goBack = "goBack" - case canGoBack = "canGoBack" - case goForward = "goForward" - case canGoForward = "canGoForward" - case goBackOrForward = "goBackOrForward" - case canGoBackOrForward = "canGoBackOrForward" - case stopLoading = "stopLoading" - case isLoading = "isLoading" - case takeScreenshot = "takeScreenshot" - case setSettings = "setSettings" - case getSettings = "getSettings" - case close = "close" - case show = "show" - case hide = "hide" - case isHidden = "isHidden" - case getCopyBackForwardList = "getCopyBackForwardList" - @available(*, deprecated, message: "Use FindInteractionController.findAll instead.") - case findAll = "findAll" - @available(*, deprecated, message: "Use FindInteractionController.findNext instead.") - case findNext = "findNext" - @available(*, deprecated, message: "Use FindInteractionController.clearMatches instead.") - case clearMatches = "clearMatches" - @available(*, deprecated, message: "Use InAppWebViewManager.clearAllCache instead.") - case clearCache = "clearCache" - case scrollTo = "scrollTo" - case scrollBy = "scrollBy" - case pauseTimers = "pauseTimers" - case resumeTimers = "resumeTimers" - case printCurrentPage = "printCurrentPage" - case getContentHeight = "getContentHeight" - case getContentWidth = "getContentWidth" - case reloadFromOrigin = "reloadFromOrigin" - case getOriginalUrl = "getOriginalUrl" - case getZoomScale = "getZoomScale" - case hasOnlySecureContent = "hasOnlySecureContent" - case getSelectedText = "getSelectedText" - case getScrollX = "getScrollX" - case getScrollY = "getScrollY" - case clearFocus = "clearFocus" - case requestFocus = "requestFocus" - case getCertificate = "getCertificate" - case addUserScript = "addUserScript" - case removeUserScript = "removeUserScript" - case removeUserScriptsByGroupName = "removeUserScriptsByGroupName" - case removeAllUserScripts = "removeAllUserScripts" - case callAsyncJavaScript = "callAsyncJavaScript" - case createPdf = "createPdf" - case createWebArchiveData = "createWebArchiveData" - case saveWebArchive = "saveWebArchive" - case isSecureContext = "isSecureContext" - case createWebMessageChannel = "createWebMessageChannel" - case postWebMessage = "postWebMessage" - case addWebMessageListener = "addWebMessageListener" - case canScrollVertically = "canScrollVertically" - case canScrollHorizontally = "canScrollHorizontally" - case pauseAllMediaPlayback = "pauseAllMediaPlayback" - case setAllMediaPlaybackSuspended = "setAllMediaPlaybackSuspended" - case closeAllMediaPresentations = "closeAllMediaPresentations" - case requestMediaPlaybackState = "requestMediaPlaybackState" - case getMetaThemeColor = "getMetaThemeColor" - case isInFullscreen = "isInFullscreen" - case getCameraCaptureState = "getCameraCaptureState" - case setCameraCaptureState = "setCameraCaptureState" - case getMicrophoneCaptureState = "getMicrophoneCaptureState" - case setMicrophoneCaptureState = "setMicrophoneCaptureState" - case loadSimulatedRequest = "loadSimulatedRequest" - case saveState = "saveState" - case restoreState = "restoreState" -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebViewFlutterPlugin.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebViewFlutterPlugin.swift deleted file mode 100644 index 57f6dddaab..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/InAppWebViewFlutterPlugin.swift +++ /dev/null @@ -1,94 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -import Cocoa -import FlutterMacOS -import AppKit -import WebKit -import Foundation -import AVFoundation -import SafariServices - -public class InAppWebViewFlutterPlugin: NSObject, FlutterPlugin { - - var registrar: FlutterPluginRegistrar - var platformUtil: PlatformUtil? - var inAppWebViewManager: InAppWebViewManager? - var myCookieManager: Any? - var myWebStorageManager: MyWebStorageManager? - var credentialDatabase: CredentialDatabase? - var inAppBrowserManager: InAppBrowserManager? - var headlessInAppWebViewManager: HeadlessInAppWebViewManager? - var webAuthenticationSessionManager: WebAuthenticationSessionManager? - var printJobManager: PrintJobManager? - var proxyManager: Any? - - var webViewControllers: [String: InAppBrowserWebViewController?] = [:] - var safariViewControllers: [String: Any?] = [:] - - public init(with registrar: FlutterPluginRegistrar) { - self.registrar = registrar - super.init() - registrar.register(FlutterWebViewFactory(plugin: self) as FlutterPlatformViewFactory, withId: FlutterWebViewFactory.VIEW_TYPE_ID) - - platformUtil = PlatformUtil(plugin: self) - inAppBrowserManager = InAppBrowserManager(plugin: self) - headlessInAppWebViewManager = HeadlessInAppWebViewManager(plugin: self) - inAppWebViewManager = InAppWebViewManager(plugin: self) - credentialDatabase = CredentialDatabase(plugin: self) - if #available(macOS 10.13, *) { - myCookieManager = MyCookieManager(plugin: self) - } - myWebStorageManager = MyWebStorageManager(plugin: self) - webAuthenticationSessionManager = WebAuthenticationSessionManager(plugin: self) - printJobManager = PrintJobManager(plugin: self) - if #available(macOS 14.0, *) { - proxyManager = ProxyManager(plugin: self) - } - } - - public static func register(with registrar: FlutterPluginRegistrar) { - let _ = InAppWebViewFlutterPlugin(with: registrar) - } - - public func detachFromEngine(for registrar: FlutterPluginRegistrar) { - platformUtil?.dispose() - platformUtil = nil - inAppBrowserManager?.dispose() - inAppBrowserManager = nil - headlessInAppWebViewManager?.dispose() - headlessInAppWebViewManager = nil - inAppWebViewManager?.dispose() - inAppWebViewManager = nil - credentialDatabase?.dispose() - credentialDatabase = nil - if #available(macOS 10.13, *) { - (myCookieManager as? MyCookieManager)?.dispose() - myCookieManager = nil - } - myWebStorageManager?.dispose() - myWebStorageManager = nil - webAuthenticationSessionManager?.dispose() - webAuthenticationSessionManager = nil - printJobManager?.dispose() - printJobManager = nil - if #available(macOS 14.0, *) { - (proxyManager as? ProxyManager)?.dispose() - proxyManager = nil - } - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/LeakAvoider.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/LeakAvoider.swift deleted file mode 100755 index 9f447142a6..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/LeakAvoider.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// LeakAvoider.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 15/12/2019. -// - -import Foundation -import FlutterMacOS - -public class LeakAvoider: NSObject { - weak var delegate : FlutterMethodCallDelegate? - - init(delegate: FlutterMethodCallDelegate) { - super.init() - self.delegate = delegate - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - self.delegate?.handle(call, result: result) - } - - deinit { - debugPrint("LeakAvoider - dealloc") - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/MyCookieManager.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/MyCookieManager.swift deleted file mode 100755 index 856ac1a25e..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/MyCookieManager.swift +++ /dev/null @@ -1,290 +0,0 @@ -// -// MyCookieManager.swift -// flutter_inappwebview -// -// Created by Lorenzo on 26/10/18. -// - -import Foundation -import WebKit -import FlutterMacOS - -@available(macOS 10.13, *) -public class MyCookieManager: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_cookiemanager" - var plugin: InAppWebViewFlutterPlugin? - static var httpCookieStore = WKWebsiteDataStore.default().httpCookieStore - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: MyCookieManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger)) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - switch call.method { - case "setCookie": - let url = arguments!["url"] as! String - let name = arguments!["name"] as! String - let value = arguments!["value"] as! String - let path = arguments!["path"] as! String - - var expiresDate: Int64? - if let expiresDateString = arguments!["expiresDate"] as? String { - expiresDate = Int64(expiresDateString) - } - - let maxAge = arguments!["maxAge"] as? Int64 - let isSecure = arguments!["isSecure"] as? Bool - let isHttpOnly = arguments!["isHttpOnly"] as? Bool - let sameSite = arguments!["sameSite"] as? String - let domain = arguments!["domain"] as? String - - MyCookieManager.setCookie(url: url, - name: name, - value: value, - path: path, - domain: domain, - expiresDate: expiresDate, - maxAge: maxAge, - isSecure: isSecure, - isHttpOnly: isHttpOnly, - sameSite: sameSite, - result: result) - break - case "getCookies": - let url = arguments!["url"] as! String - MyCookieManager.getCookies(url: url, result: result) - break - case "getAllCookies": - MyCookieManager.getAllCookies(result: result) - break - case "deleteCookie": - let url = arguments!["url"] as! String - let name = arguments!["name"] as! String - let path = arguments!["path"] as! String - let domain = arguments!["domain"] as? String - MyCookieManager.deleteCookie(url: url, name: name, path: path, domain: domain, result: result) - break; - case "deleteCookies": - let url = arguments!["url"] as! String - let path = arguments!["path"] as! String - let domain = arguments!["domain"] as? String - MyCookieManager.deleteCookies(url: url, path: path, domain: domain, result: result) - break; - case "deleteAllCookies": - MyCookieManager.deleteAllCookies(result: result) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public static func setCookie(url: String, - name: String, - value: String, - path: String, - domain: String?, - expiresDate: Int64?, - maxAge: Int64?, - isSecure: Bool?, - isHttpOnly: Bool?, - sameSite: String?, - result: @escaping FlutterResult) { - var properties: [HTTPCookiePropertyKey: Any] = [:] - properties[.originURL] = url - properties[.name] = name - properties[.value] = value - properties[.path] = path - - if domain != nil { - properties[.domain] = domain - } - - if expiresDate != nil { - // convert from milliseconds - properties[.expires] = Date(timeIntervalSince1970: TimeInterval(Double(expiresDate!)/1000)) - } - if maxAge != nil { - properties[.maximumAge] = String(maxAge!) - } - if isSecure != nil && isSecure! { - properties[.secure] = "TRUE" - } - if isHttpOnly != nil && isHttpOnly! { - properties[.init("HttpOnly")] = "YES" - } - if sameSite != nil { - if #available(macOS 10.15, *) { - var sameSiteValue = HTTPCookieStringPolicy(rawValue: "None") - switch sameSite { - case "Lax": - sameSiteValue = HTTPCookieStringPolicy.sameSiteLax - case "Strict": - sameSiteValue = HTTPCookieStringPolicy.sameSiteStrict - default: - break - } - properties[.sameSitePolicy] = sameSiteValue - } else { - properties[.init("SameSite")] = sameSite - } - } - - if let cookie = HTTPCookie(properties: properties) { - MyCookieManager.httpCookieStore.setCookie(cookie, completionHandler: {() in - result(true) - }) - } else { - result(false) - } - } - - public static func getCookies(url: String, result: @escaping FlutterResult) { - var cookieList: [[String: Any?]] = [] - - if let urlHost = URL(string: url)?.host { - MyCookieManager.httpCookieStore.getAllCookies { (cookies) in - for cookie in cookies { - if urlHost.hasSuffix(cookie.domain) || ".\(urlHost)".hasSuffix(cookie.domain) { - var sameSite: String? = nil - if #available(macOS 10.15, *) { - if let sameSiteValue = cookie.sameSitePolicy?.rawValue { - sameSite = sameSiteValue.prefix(1).capitalized + sameSiteValue.dropFirst() - } - } - - var expiresDateTimestamp: Int64 = -1 - if let expiresDate = cookie.expiresDate?.timeIntervalSince1970 { - // convert to milliseconds - expiresDateTimestamp = Int64(expiresDate * 1000) - } - - cookieList.append([ - "name": cookie.name, - "value": cookie.value, - "expiresDate": expiresDateTimestamp != -1 ? expiresDateTimestamp : nil, - "isSessionOnly": cookie.isSessionOnly, - "domain": cookie.domain, - "sameSite": sameSite, - "isSecure": cookie.isSecure, - "isHttpOnly": cookie.isHTTPOnly, - "path": cookie.path, - ]) - } - } - result(cookieList) - } - return - } else { - print("Cannot get WebView cookies. No HOST found for URL: \(url)") - } - - result(cookieList) - } - - public static func getAllCookies(result: @escaping FlutterResult) { - var cookieList: [[String: Any?]] = [] - - MyCookieManager.httpCookieStore.getAllCookies { (cookies) in - for cookie in cookies { - var sameSite: String? = nil - if #available(macOS 10.15, *) { - if let sameSiteValue = cookie.sameSitePolicy?.rawValue { - sameSite = sameSiteValue.prefix(1).capitalized + sameSiteValue.dropFirst() - } - } - - var expiresDateTimestamp: Int64 = -1 - if let expiresDate = cookie.expiresDate?.timeIntervalSince1970 { - // convert to milliseconds - expiresDateTimestamp = Int64(expiresDate * 1000) - } - - cookieList.append([ - "name": cookie.name, - "value": cookie.value, - "expiresDate": expiresDateTimestamp != -1 ? expiresDateTimestamp : nil, - "isSessionOnly": cookie.isSessionOnly, - "domain": cookie.domain, - "sameSite": sameSite, - "isSecure": cookie.isSecure, - "isHttpOnly": cookie.isHTTPOnly, - "path": cookie.path, - ]) - } - result(cookieList) - } - } - - public static func deleteCookie(url: String, name: String, path: String, domain: String?, result: @escaping FlutterResult) { - var domain = domain - MyCookieManager.httpCookieStore.getAllCookies { (cookies) in - for cookie in cookies { - var originURL = url - if cookie.properties![.originURL] is String { - originURL = cookie.properties![.originURL] as! String - } - else if cookie.properties![.originURL] is URL { - originURL = (cookie.properties![.originURL] as! URL).absoluteString - } - if domain == nil, let domainUrl = URL(string: originURL) { - domain = domainUrl.host - } - if let domain = domain, cookie.domain == domain, cookie.name == name, cookie.path == path { - MyCookieManager.httpCookieStore.delete(cookie, completionHandler: { - result(true) - }) - return - } - } - result(false) - } - } - - public static func deleteCookies(url: String, path: String, domain: String?, result: @escaping FlutterResult) { - var domain = domain - let dispatchGroup = DispatchGroup() - MyCookieManager.httpCookieStore.getAllCookies { (cookies) in - for cookie in cookies { - var originURL = url - if cookie.properties![.originURL] is String { - originURL = cookie.properties![.originURL] as! String - } - else if cookie.properties![.originURL] is URL { - originURL = (cookie.properties![.originURL] as! URL).absoluteString - } - if domain == nil, let domainUrl = URL(string: originURL) { - domain = domainUrl.host - } - if let domain = domain, cookie.domain == domain, cookie.path == path { - dispatchGroup.enter() - MyCookieManager.httpCookieStore.delete(cookie) { - dispatchGroup.leave() - } - } - } - dispatchGroup.notify(queue: .main) { - result(true) - } - } - } - - public static func deleteAllCookies(result: @escaping FlutterResult) { - let websiteDataTypes = NSSet(array: [WKWebsiteDataTypeCookies]) - let date = NSDate(timeIntervalSince1970: 0) - WKWebsiteDataStore.default().removeData(ofTypes: websiteDataTypes as! Set, modifiedSince: date as Date, completionHandler:{ - result(true) - }) - } - - public override func dispose() { - super.dispose() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/MyWebStorageManager.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/MyWebStorageManager.swift deleted file mode 100755 index c77840bbb1..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/MyWebStorageManager.swift +++ /dev/null @@ -1,95 +0,0 @@ -// -// MyWebStorageManager.swift -// connectivity -// -// Created by Lorenzo Pichilli on 16/12/2019. -// - -import Foundation -import WebKit -import FlutterMacOS - -public class MyWebStorageManager: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webstoragemanager" - var plugin: InAppWebViewFlutterPlugin? - static var websiteDataStore = WKWebsiteDataStore.default() - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: MyWebStorageManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger)) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - switch call.method { - case "fetchDataRecords": - let dataTypes = Set(arguments!["dataTypes"] as! [String]) - MyWebStorageManager.fetchDataRecords(dataTypes: dataTypes, result: result) - break - case "removeDataFor": - let dataTypes = Set(arguments!["dataTypes"] as! [String]) - let recordList = arguments!["recordList"] as! [[String: Any?]] - MyWebStorageManager.removeDataFor(dataTypes: dataTypes, recordList: recordList, result: result) - break - case "removeDataModifiedSince": - let dataTypes = Set(arguments!["dataTypes"] as! [String]) - let timestamp = arguments!["timestamp"] as! Int64 - MyWebStorageManager.removeDataModifiedSince(dataTypes: dataTypes, timestamp: timestamp, result: result) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public static func fetchDataRecords(dataTypes: Set, result: @escaping FlutterResult) { - var recordList: [[String: Any?]] = [] - - MyWebStorageManager.websiteDataStore.fetchDataRecords(ofTypes: dataTypes) { (data) in - for record in data { - recordList.append([ - "displayName": record.displayName, - "dataTypes": record.dataTypes.map({ (dataType) -> String in - return dataType - }) - ]) - } - result(recordList) - } - } - - public static func removeDataFor(dataTypes: Set, recordList: [[String: Any?]], result: @escaping FlutterResult) { - var records: [WKWebsiteDataRecord] = [] - - MyWebStorageManager.websiteDataStore.fetchDataRecords(ofTypes: dataTypes) { (data) in - for record in data { - for r in recordList { - let displayName = r["displayName"] as! String - if (record.displayName == displayName) { - records.append(record) - break - } - } - } - websiteDataStore.removeData(ofTypes: dataTypes, for: records) { - result(true) - } - } - } - - public static func removeDataModifiedSince(dataTypes: Set, timestamp: Int64, result: @escaping FlutterResult) { - let date = NSDate(timeIntervalSince1970: TimeInterval(timestamp)) - MyWebStorageManager.websiteDataStore.removeData(ofTypes: dataTypes, modifiedSince: date as Date) { - result(true) - } - } - - public override func dispose() { - super.dispose() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PlatformUtil.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PlatformUtil.swift deleted file mode 100644 index 20f96e9cf3..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PlatformUtil.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// PlatformUtil.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 01/03/21. -// - -import Foundation -import FlutterMacOS - -public class PlatformUtil: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_platformutil" - var plugin: InAppWebViewFlutterPlugin? - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: PlatformUtil.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger)) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "getSystemVersion": - let version = ProcessInfo.processInfo.operatingSystemVersion - result("\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)") - break - case "formatDate": - let date = arguments!["date"] as! Int64 - let format = arguments!["format"] as! String - let locale = PlatformUtil.getLocaleFromString(locale: arguments!["locale"] as? String) - let timezone = TimeZone.init(abbreviation: arguments!["timezone"] as? String ?? "UTC")! - result(PlatformUtil.formatDate(date: date, format: format, locale: locale, timezone: timezone)) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - static public func getLocaleFromString(locale: String?) -> Locale { - guard let locale = locale else { - return Locale.init(identifier: "en_US") - } - return Locale.init(identifier: locale) - } - - static public func getDateFromMilliseconds(date: Int64) -> Date { - return Date(timeIntervalSince1970: TimeInterval(Double(date)/1000)) - } - - static public func formatDate(date: Int64, format: String, locale: Locale, timezone: TimeZone) -> String { - let formatter = DateFormatter() - formatter.locale = locale - formatter.dateFormat = format - formatter.timeZone = timezone - return formatter.string(from: PlatformUtil.getDateFromMilliseconds(date: date)) - } - - public override func dispose() { - super.dispose() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/CallAsyncJavaScriptBelowIOS14WrapperJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/CallAsyncJavaScriptBelowIOS14WrapperJS.swift deleted file mode 100644 index f1f83db006..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/CallAsyncJavaScriptBelowIOS14WrapperJS.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// CallAsyncJavaScriptBelowIOS14WrapperJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class CallAsyncJavaScriptBelowIOS14WrapperJS { - - public static func CALL_ASYNC_JAVASCRIPT_BELOW_IOS_14_WRAPPER_JS() -> String { - return """ - (function(obj) { - (async function(\(PluginScriptsUtil.VAR_FUNCTION_ARGUMENT_NAMES) { - \(PluginScriptsUtil.VAR_FUNCTION_BODY) - })(\(PluginScriptsUtil.VAR_FUNCTION_ARGUMENT_VALUES)).then(function(value) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onCallAsyncJavaScriptResultBelowIOS14Received', { - 'value': value, - 'error': null, - 'resultUuid': '\(PluginScriptsUtil.VAR_RESULT_UUID)' - }); - }).catch(function(error) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onCallAsyncJavaScriptResultBelowIOS14Received', { - 'value': null, - 'error': error + '', - 'resultUuid': '\(PluginScriptsUtil.VAR_RESULT_UUID)' - }); - }); - return null; - })(\(PluginScriptsUtil.VAR_FUNCTION_ARGUMENTS_OBJ)); - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/ConsoleLogJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/ConsoleLogJS.swift deleted file mode 100644 index 5636ea62c8..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/ConsoleLogJS.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// ConsoleLogJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class ConsoleLogJS { - - public static let CONSOLE_LOG_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_CONSOLE_LOG_JS_PLUGIN_SCRIPT" - - // This plugin is only for main frame. - // Using it also on non-main frames could cause issues - // such as https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738 - public static func CONSOLE_LOG_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: CONSOLE_LOG_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: CONSOLE_LOG_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: true, - messageHandlerNames: []) - } - - // the message needs to be concatenated with '' in order to have the same behavior like on Android - public static func CONSOLE_LOG_JS_SOURCE() -> String { - return """ - (function(console) { - - function _callHandler(logLevel, args) { - var message = ''; - for (var i in args) { - try { - message += message === '' ? args[i] : ' ' + args[i]; - } catch(_) {} - } - try { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onConsoleMessage', {'level': logLevel, 'message': message}) - } catch(_) {} - } - - var oldLogs = { - 'consoleLog': console.log, - 'consoleDebug': console.debug, - 'consoleError': console.error, - 'consoleInfo': console.info, - 'consoleWarn': console.warn - }; - - for (var k in oldLogs) { - (function(oldLog) { - var logLevel = oldLog.replace('console', '').toLowerCase(); - console[logLevel] = function() { - oldLogs[oldLog].apply(null, arguments); - _callHandler(logLevel, arguments); - } - })(k); - } - })(window.console); - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/EnableViewportScaleJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/EnableViewportScaleJS.swift deleted file mode 100644 index efa07583a4..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/EnableViewportScaleJS.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// EnableViewportScaleJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class EnableViewportScaleJS { - - public static let ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT" - - // This plugin is only for main frame - public static func ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: ENABLE_VIEWPORT_SCALE_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: ENABLE_VIEWPORT_SCALE_JS_SOURCE, - injectionTime: .atDocumentEnd, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static let ENABLE_VIEWPORT_SCALE_JS_SOURCE = """ - (function() { - var meta = document.createElement('meta'); - meta.setAttribute('name', 'viewport'); - meta.setAttribute('content', 'width=device-width'); - document.getElementsByTagName('head')[0].appendChild(meta); - })() - """ - - public static func NOT_ENABLE_VIEWPORT_SCALE_JS_SOURCE() -> String { - return """ - (function() { - var meta = document.createElement('meta'); - meta.setAttribute('name', 'viewport'); - meta.setAttribute('content', window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._originalViewPortMetaTagContent); - document.getElementsByTagName('head')[0].appendChild(meta); - })() - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/FindElementsAtPointJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/FindElementsAtPointJS.swift deleted file mode 100644 index 26220f8a59..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/FindElementsAtPointJS.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// FindElementsAtPointJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class FindElementsAtPointJS { - public static let FIND_ELEMENTS_AT_POINT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_FIND_ELEMENTS_AT_POINT_JS_PLUGIN_SCRIPT" - - // This plugin is only for main frame - public static func FIND_ELEMENTS_AT_POINT_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: FIND_ELEMENTS_AT_POINT_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: FIND_ELEMENTS_AT_POINT_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - /** - https://developer.android.com/reference/android/webkit/WebView.HitTestResult - */ - public static func FIND_ELEMENTS_AT_POINT_JS_SOURCE() -> String { - return """ - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findElementsAtPoint = function(x, y) { - var hitTestResultType = { - UNKNOWN_TYPE: 0, - PHONE_TYPE: 2, - GEO_TYPE: 3, - EMAIL_TYPE: 4, - IMAGE_TYPE: 5, - SRC_ANCHOR_TYPE: 7, - SRC_IMAGE_ANCHOR_TYPE: 8, - EDIT_TEXT_TYPE: 9 - }; - var element = document.elementFromPoint(x, y); - var data = { - type: 0, - extra: null - }; - while (element) { - if (element.tagName === 'IMG' && element.src) { - if (element.parentNode && element.parentNode.tagName === 'A' && element.parentNode.href) { - data.type = hitTestResultType.SRC_IMAGE_ANCHOR_TYPE; - } else { - data.type = hitTestResultType.IMAGE_TYPE; - } - data.extra = element.src; - break; - } else if (element.tagName === 'A' && element.href) { - if (element.href.indexOf('mailto:') === 0) { - data.type = hitTestResultType.EMAIL_TYPE; - data.extra = element.href.replace('mailto:', ''); - } else if (element.href.indexOf('tel:') === 0) { - data.type = hitTestResultType.PHONE_TYPE; - data.extra = element.href.replace('tel:', ''); - } else if (element.href.indexOf('geo:') === 0) { - data.type = hitTestResultType.GEO_TYPE; - data.extra = element.href.replace('geo:', ''); - } else { - data.type = hitTestResultType.SRC_ANCHOR_TYPE; - data.extra = element.href; - } - break; - } else if ( - (element.tagName === 'INPUT' && ['text', 'email', 'password', 'number', 'search', 'tel', 'url'].indexOf(element.type) >= 0) || - element.tagName === 'TEXTAREA') { - data.type = hitTestResultType.EDIT_TEXT_TYPE - } - element = element.parentNode; - } - return data; - } - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/FindTextHighlightJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/FindTextHighlightJS.swift deleted file mode 100644 index 5006f04b76..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/FindTextHighlightJS.swift +++ /dev/null @@ -1,186 +0,0 @@ -// -// FindTextHighlightJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class FindTextHighlightJS { - public static let FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT" - public static func FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._searchResultCount" - } - public static func FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._currentHighlight" - } - public static func FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._isDoneCounting" - } - - // This plugin is only for main frame - public static func FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: FIND_TEXT_HIGHLIGHT_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static func FIND_TEXT_HIGHLIGHT_JS_SOURCE() -> String { - return """ - \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()) = 0; - \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE()) = 0; - \(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE()) = false; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findAllAsyncForElement = function(element, keyword) { - if (element) { - if (element.nodeType == 3) { - // Text node - - var elementTmp = element; - while (true) { - var value = elementTmp.nodeValue; // Search for keyword in text node - var idx = value.toLowerCase().indexOf(keyword); - - if (idx < 0) break; - - var span = document.createElement("span"); - var text = document.createTextNode(value.substr(idx, keyword.length)); - span.appendChild(text); - - span.setAttribute( - "id", - "\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())_SEARCH_WORD_" + \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()) - ); - span.setAttribute("class", "\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())_Highlight"); - var backgroundColor = \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()) == 0 ? "#FF9732" : "#FFFF00"; - span.setAttribute("style", "color: #000 !important; background: " + backgroundColor + " !important; padding: 0px !important; margin: 0px !important; border: 0px !important;"); - - text = document.createTextNode(value.substr(idx + keyword.length)); - element.deleteData(idx, value.length - idx); - - var next = element.nextSibling; - element.parentNode.insertBefore(span, next); - element.parentNode.insertBefore(text, next); - element = text; - - \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE())++; - elementTmp = document.createTextNode( - value.substr(idx + keyword.length) - ); - - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onFindResultReceived', { - 'findResult': { - 'activeMatchOrdinal': \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE()), - 'numberOfMatches': \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()), - 'isDoneCounting': \(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE()) - } - }); - } - } else if (element.nodeType == 1) { - // Element node - if ( - element.style.display != "none" && - element.nodeName.toLowerCase() != "select" - ) { - for (var i = element.childNodes.length - 1; i >= 0; i--) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findAllAsyncForElement( - element.childNodes[element.childNodes.length - 1 - i], - keyword - ); - } - } - } - } - } - - // the main entry point to start the search - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findAllAsync = function(keyword) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._clearMatches(); - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findAllAsyncForElement(document.body, keyword.toLowerCase()); - \(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE()) = true; - - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onFindResultReceived', { - 'findResult': { - 'activeMatchOrdinal': \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE()), - 'numberOfMatches': \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()), - 'isDoneCounting': \(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE()) - } - }); - } - - // helper function, recursively removes the highlights in elements and their children - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._clearMatchesForElement = function(element) { - if (element) { - if (element.nodeType == 1) { - if (element.getAttribute("class") == "\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())_Highlight") { - var text = element.removeChild(element.firstChild); - element.parentNode.insertBefore(text, element); - element.parentNode.removeChild(element); - return true; - } else { - var normalize = false; - for (var i = element.childNodes.length - 1; i >= 0; i--) { - if (window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._clearMatchesForElement(element.childNodes[i])) { - normalize = true; - } - } - if (normalize) { - element.normalize(); - } - } - } - } - return false; - } - - // the main entry point to remove the highlights - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._clearMatches = function() { - \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()) = 0; - \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE()) = 0; - \(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE()) = false; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._clearMatchesForElement(document.body); - } - - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._findNext = function(forward) { - if (\(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()) <= 0) return; - - var idx = \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE()) + (forward ? +1 : -1); - idx = - idx < 0 - ? \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()) - 1 - : idx >= \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()) - ? 0 - : idx; - \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE()) = idx; - - var scrollTo = document.getElementById("\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())_SEARCH_WORD_" + idx); - if (scrollTo) { - var highlights = document.getElementsByClassName("\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())_Highlight"); - for (var i = 0; i < highlights.length; i++) { - var span = highlights[i]; - span.style.backgroundColor = "#FFFF00"; - } - scrollTo.style.backgroundColor = "#FF9732"; - - scrollTo.scrollIntoView({ - behavior: "auto", - block: "center" - }); - - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onFindResultReceived', { - 'findResult': { - 'activeMatchOrdinal': \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE()), - 'numberOfMatches': \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE()), - 'isDoneCounting': \(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE()) - } - }); - } - } - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/InterceptAjaxRequestJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/InterceptAjaxRequestJS.swift deleted file mode 100644 index e8ca40c76d..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/InterceptAjaxRequestJS.swift +++ /dev/null @@ -1,294 +0,0 @@ -// -// InterceptAjaxRequestsJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class InterceptAjaxRequestJS { - - public static let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT" - - public static func FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._useShouldInterceptAjaxRequest" - } - - public static func FLAG_VARIABLE_FOR_ON_AJAX_READY_STATE_CHANGE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._useOnAjaxReadyStateChange" - } - - public static func FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._useOnAjaxProgress" - } - - public static func FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._interceptOnlyAsyncAjaxRequests" - } - - public static func INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?, forMainFrameOnly: Bool, initialUseOnAjaxReadyStateChange: Bool = false, initialUseOnAjaxProgress: Bool = false) -> PluginScript { - return PluginScript( - groupName: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: INTERCEPT_AJAX_REQUEST_JS_SOURCE(initialUseOnAjaxReadyStateChange: initialUseOnAjaxReadyStateChange, initialUseOnAjaxProgress: initialUseOnAjaxProgress), - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: true, - messageHandlerNames: []) - } - - public static func createInterceptOnlyAsyncAjaxRequestsPluginScript(onlyAsync: Bool, allowedOriginRules: [String]?, forMainFrameOnly: Bool) -> PluginScript { - return PluginScript(groupName: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: "\(FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE()) = \(onlyAsync);", - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: true, - messageHandlerNames: [] - ); - } - - public static func INTERCEPT_AJAX_REQUEST_JS_SOURCE(initialUseOnAjaxReadyStateChange: Bool, initialUseOnAjaxProgress: Bool) -> String { - return """ - \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) = true; - \(FLAG_VARIABLE_FOR_ON_AJAX_READY_STATE_CHANGE()) = \(initialUseOnAjaxReadyStateChange); - \(FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS()) = \(initialUseOnAjaxProgress); - (function(ajax) { - var send = ajax.prototype.send; - var open = ajax.prototype.open; - var setRequestHeader = ajax.prototype.setRequestHeader; - ajax.prototype._flutter_inappwebview_url = null; - ajax.prototype._flutter_inappwebview_method = null; - ajax.prototype._flutter_inappwebview_isAsync = null; - ajax.prototype._flutter_inappwebview_user = null; - ajax.prototype._flutter_inappwebview_password = null; - ajax.prototype._flutter_inappwebview_password = null; - ajax.prototype._flutter_inappwebview_already_onreadystatechange_wrapped = false; - ajax.prototype._flutter_inappwebview_request_headers = {}; - function convertRequestResponse(request, callback) { - if (request.response != null && request.responseType != null) { - switch (request.responseType) { - case 'arraybuffer': - callback(new Uint8Array(request.response)); - return; - case 'blob': - const reader = new FileReader(); - reader.addEventListener('loadend', function() { - callback(new Uint8Array(reader.result)); - }); - reader.readAsArrayBuffer(blob); - return; - case 'document': - callback(request.response.documentElement.outerHTML); - return; - case 'json': - callback(request.response); - return; - }; - } - callback(null); - }; - ajax.prototype.open = function(method, url, isAsync, user, password) { - isAsync = (isAsync != null) ? isAsync : true; - this._flutter_inappwebview_url = url; - this._flutter_inappwebview_method = method; - this._flutter_inappwebview_isAsync = isAsync; - this._flutter_inappwebview_user = user; - this._flutter_inappwebview_password = password; - this._flutter_inappwebview_request_headers = {}; - open.call(this, method, url, isAsync, user, password); - }; - ajax.prototype.setRequestHeader = function(header, value) { - this._flutter_inappwebview_request_headers[header] = value; - setRequestHeader.call(this, header, value); - }; - function handleEvent(e) { - if (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) === false || \(FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS()) == null || \(FLAG_VARIABLE_FOR_ON_AJAX_PROGRESS()) === false) { - return; - } - var self = this; - if (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) == null || \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) == true) { - var headers = this.getAllResponseHeaders(); - var responseHeaders = {}; - if (headers != null) { - var arr = headers.trim().split(/[\\r\\n]+/); - arr.forEach(function (line) { - var parts = line.split(': '); - var header = parts.shift(); - var value = parts.join(': '); - responseHeaders[header] = value; - }); - } - convertRequestResponse(this, function(response) { - var ajaxRequest = { - method: self._flutter_inappwebview_method, - url: self._flutter_inappwebview_url, - isAsync: self._flutter_inappwebview_isAsync, - user: self._flutter_inappwebview_user, - password: self._flutter_inappwebview_password, - withCredentials: self.withCredentials, - headers: self._flutter_inappwebview_request_headers, - readyState: self.readyState, - status: self.status, - responseURL: self.responseURL, - responseType: self.responseType, - response: response, - responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null, - responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null, - statusText: self.statusText, - responseHeaders, responseHeaders, - event: { - type: e.type, - loaded: e.loaded, - lengthComputable: e.lengthComputable, - total: e.total - } - }; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onAjaxProgress', ajaxRequest).then(function(result) { - if (result != null) { - switch (result) { - case 0: - self.abort(); - return; - }; - } - }); - }); - } - }; - ajax.prototype.send = function(data) { - var self = this; - var canBeIntercepted = self._flutter_inappwebview_isAsync || \(FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE()) === false; - if (canBeIntercepted && (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) == null || \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) == true)) { - if (\(FLAG_VARIABLE_FOR_ON_AJAX_READY_STATE_CHANGE()) === true && !this._flutter_inappwebview_already_onreadystatechange_wrapped) { - this._flutter_inappwebview_already_onreadystatechange_wrapped = true; - var realOnreadystatechange = this.onreadystatechange; - this.onreadystatechange = function() { - if (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) == null || \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE()) == true) { - var headers = this.getAllResponseHeaders(); - var responseHeaders = {}; - if (headers != null) { - var arr = headers.trim().split(/[\\r\\n]+/); - arr.forEach(function (line) { - var parts = line.split(': '); - var header = parts.shift(); - var value = parts.join(': '); - responseHeaders[header] = value; - }); - } - convertRequestResponse(this, function(response) { - var ajaxRequest = { - method: self._flutter_inappwebview_method, - url: self._flutter_inappwebview_url, - isAsync: self._flutter_inappwebview_isAsync, - user: self._flutter_inappwebview_user, - password: self._flutter_inappwebview_password, - withCredentials: self.withCredentials, - headers: self._flutter_inappwebview_request_headers, - readyState: self.readyState, - status: self.status, - responseURL: self.responseURL, - responseType: self.responseType, - response: response, - responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null, - responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null, - statusText: self.statusText, - responseHeaders: responseHeaders - }; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onAjaxReadyStateChange', ajaxRequest).then(function(result) { - if (result != null) { - switch (result) { - case 0: - self.abort(); - return; - }; - } - if (realOnreadystatechange != null) { - realOnreadystatechange(); - } - }); - }); - } else if (realOnreadystatechange != null) { - realOnreadystatechange(); - } - }; - } - this.addEventListener('loadstart', handleEvent); - this.addEventListener('load', handleEvent); - this.addEventListener('loadend', handleEvent); - this.addEventListener('progress', handleEvent); - this.addEventListener('error', handleEvent); - this.addEventListener('abort', handleEvent); - this.addEventListener('timeout', handleEvent); - \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).convertBodyRequest(data).then(function(data) { - var ajaxRequest = { - data: data, - method: self._flutter_inappwebview_method, - url: self._flutter_inappwebview_url, - isAsync: self._flutter_inappwebview_isAsync, - user: self._flutter_inappwebview_user, - password: self._flutter_inappwebview_password, - withCredentials: self.withCredentials, - headers: self._flutter_inappwebview_request_headers, - responseType: self.responseType - }; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('shouldInterceptAjaxRequest', ajaxRequest).then(function(result) { - if (result != null) { - switch (result) { - case 0: - self.abort(); - return; - }; - if (result.data != null && !\(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).isString(result.data) && result.data.length > 0) { - var bodyString = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).arrayBufferToString(result.data); - if (\(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).isBodyFormData(bodyString)) { - var formDataContentType = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).getFormDataContentType(bodyString); - if (result.headers != null) { - result.headers['Content-Type'] = result.headers['Content-Type'] == null ? formDataContentType : result.headers['Content-Type']; - } else { - result.headers = { 'Content-Type': formDataContentType }; - } - } - } - if (\(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).isString(result.data) || result.data == null) { - data = result.data; - } else if (result.data.length > 0) { - data = new Uint8Array(result.data); - } - self.withCredentials = result.withCredentials; - if (result.responseType != null && self._flutter_inappwebview_isAsync) { - self.responseType = result.responseType; - }; - if (result.headers != null) { - for (var header in result.headers) { - var value = result.headers[header]; - var flutter_inappwebview_value = self._flutter_inappwebview_request_headers[header]; - if (flutter_inappwebview_value == null) { - self._flutter_inappwebview_request_headers[header] = value; - } else { - self._flutter_inappwebview_request_headers[header] += ', ' + value; - } - setRequestHeader.call(self, header, value); - }; - } - if ((self._flutter_inappwebview_method != result.method && result.method != null) || - (self._flutter_inappwebview_url != result.url && result.url != null) || - (self._flutter_inappwebview_isAsync != result.isAsync && result.isAsync != null) || - (self._flutter_inappwebview_user != result.user && result.user != null) || - (self._flutter_inappwebview_password != result.password && result.password != null)) { - self.abort(); - self.open(result.method, result.url, result.isAsync, result.user, result.password); - } - } - send.call(self, data); - }); - }); - } else { - send.call(this, data); - } - }; - })(window.XMLHttpRequest); - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/InterceptFetchRequestJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/InterceptFetchRequestJS.swift deleted file mode 100644 index 953fa3aa8f..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/InterceptFetchRequestJS.swift +++ /dev/null @@ -1,163 +0,0 @@ -// -// InterceptFetchRequestsJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class InterceptFetchRequestJS { - - public static let INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT" - public static func FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._useShouldInterceptFetchRequest" - } - - public static func INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?, forMainFrameOnly: Bool) -> PluginScript { - return PluginScript( - groupName: INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: INTERCEPT_FETCH_REQUEST_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: true, - messageHandlerNames: []) - } - - public static func INTERCEPT_FETCH_REQUEST_JS_SOURCE() -> String { - return """ - \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE()) = true; - (function(fetch) { - if (fetch == null) { - return; - } - window.fetch = async function(resource, init) { - if (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE()) == null || \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE()) == true) { - var fetchRequest = { - url: null, - method: null, - headers: null, - body: null, - mode: null, - credentials: null, - cache: null, - redirect: null, - referrer: null, - referrerPolicy: null, - integrity: null, - keepalive: null - }; - if (resource instanceof Request) { - fetchRequest.url = resource.url; - fetchRequest.method = resource.method; - fetchRequest.headers = resource.headers; - fetchRequest.body = resource.body; - fetchRequest.mode = resource.mode; - fetchRequest.credentials = resource.credentials; - fetchRequest.cache = resource.cache; - fetchRequest.redirect = resource.redirect; - fetchRequest.referrer = resource.referrer; - fetchRequest.referrerPolicy = resource.referrerPolicy; - fetchRequest.integrity = resource.integrity; - fetchRequest.keepalive = resource.keepalive; - } else { - fetchRequest.url = resource != null ? resource.toString() : null; - if (init != null) { - fetchRequest.method = init.method; - fetchRequest.headers = init.headers; - fetchRequest.body = init.body; - fetchRequest.mode = init.mode; - fetchRequest.credentials = init.credentials; - fetchRequest.cache = init.cache; - fetchRequest.redirect = init.redirect; - fetchRequest.referrer = init.referrer; - fetchRequest.referrerPolicy = init.referrerPolicy; - fetchRequest.integrity = init.integrity; - fetchRequest.keepalive = init.keepalive; - } - } - if (fetchRequest.headers instanceof Headers) { - fetchRequest.headers = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).convertHeadersToJson(fetchRequest.headers); - } - fetchRequest.credentials = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).convertCredentialsToJson(fetchRequest.credentials); - return \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).convertBodyRequest(fetchRequest.body).then(function(body) { - fetchRequest.body = body; - return window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('shouldInterceptFetchRequest', fetchRequest).then(function(result) { - if (result != null) { - switch (result.action) { - case 0: - var controller = new AbortController(); - if (init != null) { - init.signal = controller.signal; - } else { - init = { - signal: controller.signal - }; - } - controller.abort(); - break; - } - if (result.body != null && !\(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).isString(result.body) && result.body.length > 0) { - var bodyString = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).arrayBufferToString(result.body); - if (\(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).isBodyFormData(bodyString)) { - var formDataContentType = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).getFormDataContentType(bodyString); - if (result.headers != null) { - result.headers['Content-Type'] = result.headers['Content-Type'] == null ? formDataContentType : result.headers['Content-Type']; - } else { - result.headers = { 'Content-Type': formDataContentType }; - } - } - } - resource = result.url; - if (init == null) { - init = {}; - } - if (result.method != null && result.method.length > 0) { - init.method = result.method; - } - if (result.headers != null && Object.keys(result.headers).length > 0) { - init.headers = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).convertJsonToHeaders(result.headers); - } - if (\(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).isString(result.body) || result.body == null) { - init.body = result.body; - } else if (result.body.length > 0) { - init.body = new Uint8Array(result.body); - } - if (result.mode != null && result.mode.length > 0) { - init.mode = result.mode; - } - if (result.credentials != null) { - init.credentials = \(JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME()).convertJsonToCredential(result.credentials); - } - if (result.cache != null && result.cache.length > 0) { - init.cache = result.cache; - } - if (result.redirect != null && result.redirect.length > 0) { - init.redirect = result.redirect; - } - if (result.referrer != null && result.referrer.length > 0) { - init.referrer = result.referrer; - } - if (result.referrerPolicy != null && result.referrerPolicy.length > 0) { - init.referrerPolicy = result.referrerPolicy; - } - if (result.integrity != null && result.integrity.length > 0) { - init.integrity = result.integrity; - } - if (result.keepalive != null) { - init.keepalive = result.keepalive; - } - return fetch(resource, init); - } - return fetch(resource, init); - }); - }); - } else { - return fetch(resource, init); - } - }; - })(window.fetch); - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/JavaScriptBridgeJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/JavaScriptBridgeJS.swift deleted file mode 100644 index 0e42a37342..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/JavaScriptBridgeJS.swift +++ /dev/null @@ -1,293 +0,0 @@ -// -// javaScriptBridgeJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class JavaScriptBridgeJS { - private static var _JAVASCRIPT_BRIDGE_NAME = "flutter_inappwebview" - public static func set_JAVASCRIPT_BRIDGE_NAME(bridgeName: String) { - _JAVASCRIPT_BRIDGE_NAME = bridgeName - } - public static func get_JAVASCRIPT_BRIDGE_NAME() -> String { - return _JAVASCRIPT_BRIDGE_NAME - } - - public static let JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT" - - public static let VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET = "$IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_BRIDGE_SECRET" - - public static func JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT(expectedBridgeSecret: String, allowedOriginRules: [String]?, forMainFrameOnly: Bool) -> PluginScript { - let source = JAVASCRIPT_BRIDGE_JS_SOURCE().replacingOccurrences(of: VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET, with: expectedBridgeSecret) - return PluginScript( - groupName: JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: source, - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: true, - messageHandlerNames: ["callHandler"]) - } - - public static func JAVASCRIPT_BRIDGE_JS_SOURCE() -> String { - return """ - window.\(get_JAVASCRIPT_BRIDGE_NAME()) = {}; - \(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME()) = {}; - (function(window) { - var bridgeSecret = '\(VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET)'; - var _JSON_stringify; - var _Array_slice; - var _setTimeout; - var _Promise; - var _UserMessageHandler; - var _postMessage; - try { - _JSON_stringify = window.JSON.stringify; - _Array_slice = window.Array.prototype.slice; - _Array_slice.call = window.Function.prototype.call; - _setTimeout = window.setTimeout; - _Promise = window.Promise; - _UserMessageHandler = window.webkit.messageHandlers['callHandler']; - _postMessage = _UserMessageHandler.postMessage; - _postMessage.call = window.Function.prototype.call; - } catch (_) { return; } - window.\(get_JAVASCRIPT_BRIDGE_NAME()).callHandler = function() { - var _windowId = \(WindowIdJS.WINDOW_ID_VARIABLE_JS_SOURCE()); - var _callHandlerID = _setTimeout(function(){}); - _postMessage.call(_UserMessageHandler, { - 'handlerName': arguments[0], - '_callHandlerID': _callHandlerID, - '_bridgeSecret': bridgeSecret, - 'args': _JSON_stringify(_Array_slice.call(arguments, 1)), - '_windowId': _windowId - }); - return new _Promise(function(resolve, reject) { - try { - (window.top === window ? window : window.top).\(get_JAVASCRIPT_BRIDGE_NAME())[_callHandlerID] = {resolve: resolve, reject: reject}; - } catch (e) { - resolve(); - } - }); - }; - })(window); - \(WebMessageListenerJS.WEB_MESSAGE_LISTENER_JS_SOURCE()) - \(UTIL_JS_SOURCE()) - """ - } - - public static let PLATFORM_READY_JS_SOURCE = "window.dispatchEvent(new Event('flutterInAppWebViewPlatformReady'));"; - - public static func JAVASCRIPT_UTIL_VAR_NAME() -> String { - return "window.\(get_JAVASCRIPT_BRIDGE_NAME())._Util" - } - - /* - https://github.com/github/fetch/blob/master/fetch.js - */ - public static func UTIL_JS_SOURCE() -> String { - return """ - \(JAVASCRIPT_UTIL_VAR_NAME()) = { - support: { - searchParams: 'URLSearchParams' in window, - iterable: 'Symbol' in window && 'iterator' in Symbol, - blob: - 'FileReader' in window && - 'Blob' in window && - (function() { - try { - new Blob(); - return true; - } catch (e) { - return false; - } - })(), - formData: 'FormData' in window, - arrayBuffer: 'ArrayBuffer' in window - }, - isDataView: function(obj) { - return obj && DataView.prototype.isPrototypeOf(obj); - }, - fileReaderReady: function(reader) { - return new Promise(function(resolve, reject) { - reader.onload = function() { - resolve(reader.result); - }; - reader.onerror = function() { - reject(reader.error); - }; - }); - }, - readBlobAsArrayBuffer: function(blob) { - var reader = new FileReader(); - var promise = \(JAVASCRIPT_UTIL_VAR_NAME()).fileReaderReady(reader); - reader.readAsArrayBuffer(blob); - return promise; - }, - convertBodyToArrayBuffer: function(body) { - var viewClasses = [ - '[object Int8Array]', - '[object Uint8Array]', - '[object Uint8ClampedArray]', - '[object Int16Array]', - '[object Uint16Array]', - '[object Int32Array]', - '[object Uint32Array]', - '[object Float32Array]', - '[object Float64Array]' - ]; - var isArrayBufferView = null; - if (\(JAVASCRIPT_UTIL_VAR_NAME()).support.arrayBuffer) { - isArrayBufferView = - ArrayBuffer.isView || - function(obj) { - return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1; - }; - } - - var bodyUsed = false; - - this._bodyInit = body; - if (!body) { - this._bodyText = ''; - } else if (typeof body === 'string') { - this._bodyText = body; - } else if (\(JAVASCRIPT_UTIL_VAR_NAME()).support.blob && Blob.prototype.isPrototypeOf(body)) { - this._bodyBlob = body; - } else if (\(JAVASCRIPT_UTIL_VAR_NAME()).support.formData && FormData.prototype.isPrototypeOf(body)) { - this._bodyFormData = body; - } else if (\(JAVASCRIPT_UTIL_VAR_NAME()).support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { - this._bodyText = body.toString(); - } else if (\(JAVASCRIPT_UTIL_VAR_NAME()).support.arrayBuffer && \(JAVASCRIPT_UTIL_VAR_NAME()).support.blob && \(JAVASCRIPT_UTIL_VAR_NAME()).isDataView(body)) { - this._bodyArrayBuffer = bufferClone(body.buffer); - this._bodyInit = new Blob([this._bodyArrayBuffer]); - } else if (\(JAVASCRIPT_UTIL_VAR_NAME()).support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) { - this._bodyArrayBuffer = bufferClone(body); - } else { - this._bodyText = body = Object.prototype.toString.call(body); - } - - this.blob = function () { - if (bodyUsed) { - return Promise.reject(new TypeError('Already read')); - } - bodyUsed = true; - if (this._bodyBlob) { - return Promise.resolve(this._bodyBlob); - } else if (this._bodyArrayBuffer) { - return Promise.resolve(new Blob([this._bodyArrayBuffer])); - } else if (this._bodyFormData) { - throw new Error('could not read FormData body as blob'); - } else { - return Promise.resolve(new Blob([this._bodyText])); - } - }; - - if (this._bodyArrayBuffer) { - if (bodyUsed) { - return Promise.reject(new TypeError('Already read')); - } - bodyUsed = true; - if (ArrayBuffer.isView(this._bodyArrayBuffer)) { - return Promise.resolve( - this._bodyArrayBuffer.buffer.slice( - this._bodyArrayBuffer.byteOffset, - this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength - ) - ); - } else { - return Promise.resolve(this._bodyArrayBuffer); - } - } - return this.blob().then(\(JAVASCRIPT_UTIL_VAR_NAME()).readBlobAsArrayBuffer); - }, - isString: function(variable) { - return typeof variable === 'string' || variable instanceof String; - }, - convertBodyRequest: function(body) { - if (body == null) { - return new Promise((resolve, reject) => resolve(null)); - } - if (\(JAVASCRIPT_UTIL_VAR_NAME()).isString(body) || (\(JAVASCRIPT_UTIL_VAR_NAME()).support.searchParams && body instanceof URLSearchParams)) { - return new Promise((resolve, reject) => resolve(body.toString())); - } - if (window.Response != null) { - return new Response(body).arrayBuffer().then(function(arrayBuffer) { - return Array.from(new Uint8Array(arrayBuffer)); - }); - } - return \(JAVASCRIPT_UTIL_VAR_NAME()).convertBodyToArrayBuffer(body).then(function(arrayBuffer) { - return Array.from(new Uint8Array(arrayBuffer)); - }); - }, - arrayBufferToString: function(arrayBuffer) { - var uint8Array = new Uint8Array(arrayBuffer); - return uint8Array.reduce(function(acc, i) { return acc += String.fromCharCode.apply(null, [i]); }, ''); - }, - isBodyFormData: function(bodyString) { - return bodyString.indexOf('------WebKitFormBoundary') >= 0; - }, - getFormDataContentType: function(bodyString) { - var boundary = bodyString.substr(2, 40); - return 'multipart/form-data; boundary=' + boundary; - }, - convertHeadersToJson: function(headers) { - var headersObj = {}; - for (var header of headers.keys()) { - var value = headers.get(header); - headersObj[header] = value; - } - return headersObj; - }, - convertJsonToHeaders: function(headersJson) { - return new Headers(headersJson); - }, - convertCredentialsToJson: function(credentials) { - var credentialsObj = {}; - if (window.FederatedCredential != null && credentials instanceof FederatedCredential) { - credentialsObj.type = credentials.type; - credentialsObj.id = credentials.id; - credentialsObj.name = credentials.name; - credentialsObj.protocol = credentials.protocol; - credentialsObj.provider = credentials.provider; - credentialsObj.iconURL = credentials.iconURL; - } else if (window.PasswordCredential != null && credentials instanceof PasswordCredential) { - credentialsObj.type = credentials.type; - credentialsObj.id = credentials.id; - credentialsObj.name = credentials.name; - credentialsObj.password = credentials.password; - credentialsObj.iconURL = credentials.iconURL; - } else { - credentialsObj.type = 'default'; - credentialsObj.value = credentials; - } - return credentialsObj; - }, - convertJsonToCredential: function(credentialsJson) { - var credentials; - if (window.FederatedCredential != null && credentialsJson.type === 'federated') { - credentials = new FederatedCredential({ - id: credentialsJson.id, - name: credentialsJson.name, - protocol: credentialsJson.protocol, - provider: credentialsJson.provider, - iconURL: credentialsJson.iconURL - }); - } else if (window.PasswordCredential != null && credentialsJson.type === 'password') { - credentials = new PasswordCredential({ - id: credentialsJson.id, - name: credentialsJson.name, - password: credentialsJson.password, - iconURL: credentialsJson.iconURL - }); - } else { - credentials = credentialsJson.value == null ? undefined : credentialsJson.value; - } - return credentials; - } - }; - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/OnLoadResourceJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/OnLoadResourceJS.swift deleted file mode 100644 index 18a5e496b4..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/OnLoadResourceJS.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// resourceObserverJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class OnLoadResourceJS { - - public static let ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT" - - public static func FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._useOnLoadResource" - } - - public static func ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?, forMainFrameOnly: Bool) -> PluginScript { - return PluginScript( - groupName: ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: ON_LOAD_RESOURCE_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static func ON_LOAD_RESOURCE_JS_SOURCE() -> String { - return """ - \(FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE()) = true; - (function() { - var observer = new PerformanceObserver(function(list) { - list.getEntries().forEach(function(entry) { - if (\(FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE()) == null || \(FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE()) == true) { - var resource = { - "url": entry.name, - "initiatorType": entry.initiatorType, - "startTime": entry.startTime, - "duration": entry.duration - }; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler("onLoadResource", resource); - } - }); - }); - observer.observe({entryTypes: ['resource']}); - })(); - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/OnScrollChangedJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/OnScrollChangedJS.swift deleted file mode 100644 index 2c6b29d24f..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/OnScrollChangedJS.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// OnScrollEvent.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/10/22. -// - -import Foundation - -public class OnScrollChangedJS { - - public static let ON_SCROLL_CHANGED_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_SCROLL_CHANGED_EVENT_JS_PLUGIN_SCRIPT" - - // This plugin is only for main frame - public static func ON_SCROLL_CHANGED_EVENT_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: ON_SCROLL_CHANGED_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: ON_SCROLL_CHANGED_EVENT_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static func ON_SCROLL_CHANGED_EVENT_JS_SOURCE() -> String { - return """ - (function(){ - document.addEventListener('scroll', function(e) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onScrollChanged', { - 'x': window.scrollX, - 'y': window.scrollY - } - ); - }); - })(); - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/OnWindowBlurEventJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/OnWindowBlurEventJS.swift deleted file mode 100644 index d9221d10e4..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/OnWindowBlurEventJS.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// OnWindowBlurEventJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class OnWindowBlurEventJS { - - public static let ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT" - - // This plugin is only for main frame - public static func ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: ON_WINDOW_BLUR_EVENT_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static func ON_WINDOW_BLUR_EVENT_JS_SOURCE() -> String { - return """ - (function(){ - window.addEventListener('blur', function(e) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onWindowBlur'); - }); - })(); - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/OnWindowFocusEventJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/OnWindowFocusEventJS.swift deleted file mode 100644 index b08bb08895..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/OnWindowFocusEventJS.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// OnWindowFocusEventJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class OnWindowFocusEventJS { - - public static let ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT" - - // This plugin is only for main frame - public static func ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: ON_WINDOW_FOCUS_EVENT_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static func ON_WINDOW_FOCUS_EVENT_JS_SOURCE() -> String { - return """ - (function(){ - window.addEventListener('focus', function(e) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onWindowFocus'); - }); - })(); - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/OriginalViewPortMetaTagContentJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/OriginalViewPortMetaTagContentJS.swift deleted file mode 100644 index d84c14ee34..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/OriginalViewPortMetaTagContentJS.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// OriginalViewPortMetaTagContentJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class OriginalViewPortMetaTagContentJS { - - public static let ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_PLUGIN_SCRIPT" - - // This plugin is only for main frame - public static func ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?) -> PluginScript { - return PluginScript( - groupName: ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_SOURCE(), - injectionTime: .atDocumentEnd, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static func ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_SOURCE() -> String { - return """ - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._originalViewPortMetaTagContent = ""; - (function() { - var metaTagNodes = document.head.getElementsByTagName('meta'); - for (var i = 0; i < metaTagNodes.length; i++) { - var metaTagNode = metaTagNodes[i]; - if (metaTagNode.name === "viewport") { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._originalViewPortMetaTagContent = metaTagNode.content; - } - } - })(); - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/PluginScriptsUtil.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/PluginScriptsUtil.swift deleted file mode 100644 index 51f9c86714..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/PluginScriptsUtil.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// PluginScripts.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class PluginScriptsUtil { - public static let VAR_PLACEHOLDER_VALUE = "$IN_APP_WEBVIEW_PLACEHOLDER_VALUE" - public static let VAR_FUNCTION_ARGUMENT_NAMES = "$IN_APP_WEBVIEW_FUNCTION_ARGUMENT_NAMES" - public static let VAR_FUNCTION_ARGUMENT_VALUES = "$IN_APP_WEBVIEW_FUNCTION_ARGUMENT_VALUES" - public static let VAR_FUNCTION_ARGUMENTS_OBJ = "$IN_APP_WEBVIEW_FUNCTION_ARGUMENTS_OBJ" - public static let VAR_FUNCTION_BODY = "$IN_APP_WEBVIEW_FUNCTION_BODY" - public static let VAR_RESULT_UUID = "$IN_APP_WEBVIEW_RESULT_UUID" - - public static let GET_SELECTED_TEXT_JS_SOURCE = """ -(function(){ - var txt; - if (window.getSelection) { - txt = window.getSelection().toString(); - } else if (window.document.getSelection) { - txt = window.document.getSelection().toString(); - } else if (window.document.selection) { - txt = window.document.selection.createRange().text; - } - return txt; -})(); -""" -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/PrintJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/PrintJS.swift deleted file mode 100644 index fbf29f50f3..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/PrintJS.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// PrintJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class PrintJS { - - public static let PRINT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_PRINT_JS_PLUGIN_SCRIPT" - - public static func PRINT_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?, forMainFrameOnly: Bool) -> PluginScript { - return PluginScript( - groupName: PRINT_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: PRINT_JS_SOURCE(), - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: true, - messageHandlerNames: []) - } - - public static func PRINT_JS_SOURCE() -> String { - return """ - window.print = function() { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler("onPrintRequest", window.location.href); - } - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/PromisePolyfillJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/PromisePolyfillJS.swift deleted file mode 100644 index 27c076be23..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/PromisePolyfillJS.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// PromisePolyfillJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation -import WebKit - -public class PromisePolyfillJS { - public static let PROMISE_POLYFILL_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_PROMISE_POLYFILL_JS_PLUGIN_SCRIPT" - - public static func PROMISE_POLYFILL_JS_PLUGIN_SCRIPT(allowedOriginRules: [String]?, forMainFrameOnly: Bool) -> PluginScript { - return PluginScript( - groupName: PROMISE_POLYFILL_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: PROMISE_POLYFILL_JS_SOURCE, - injectionTime: .atDocumentStart, - forMainFrameOnly: forMainFrameOnly, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: true, - messageHandlerNames: []) - } - - // https://github.com/tildeio/rsvp.js - public static let PROMISE_POLYFILL_JS_SOURCE = """ - if (window.Promise == null) { - !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(t.RSVP={})}(this,function(t){"use strict";function e(t){var e=t._promiseCallbacks;return e||(e=t._promiseCallbacks={}),e}var r={mixin:function(t){return t.on=this.on,t.off=this.off,t.trigger=this.trigger,t._promiseCallbacks=void 0,t},on:function(t,r){if("function"!=typeof r)throw new TypeError("Callback must be a function");var n=e(this),o=n[t];o||(o=n[t]=[]),-1===o.indexOf(r)&&o.push(r)},off:function(t,r){var n=e(this);if(r){var o=n[t],i=o.indexOf(r);-1!==i&&o.splice(i,1)}else n[t]=[]},trigger:function(t,r,n){var o=e(this)[t];if(o)for(var i=0;i2&&void 0!==arguments[2])||arguments[2],o=arguments[3];return function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,t.call(this,e,r,n,o))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,t),e.prototype._init=function(t,e){this._result={},this._enumerate(e)},e.prototype._enumerate=function(t){var e=Object.keys(t),r=e.length,n=this.promise;this._remaining=r;for(var o=void 0,i=void 0,s=0;n._state===a&&s PluginScript { - return PluginScript( - groupName: NOT_SUPPORT_ZOOM_JS_PLUGIN_SCRIPT_GROUP_NAME, - source: NOT_SUPPORT_ZOOM_JS_SOURCE, - injectionTime: .atDocumentEnd, - forMainFrameOnly: true, - allowedOriginRules: allowedOriginRules, - requiredInAllContentWorlds: false, - messageHandlerNames: []) - } - - public static let NOT_SUPPORT_ZOOM_JS_SOURCE = """ - (function() { - var meta = document.createElement('meta'); - meta.setAttribute('name', 'viewport'); - meta.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'); - document.getElementsByTagName('head')[0].appendChild(meta); - })() - """ - - public static func SUPPORT_ZOOM_JS_SOURCE() -> String { - return """ - (function() { - var meta = document.createElement('meta'); - meta.setAttribute('name', 'viewport'); - meta.setAttribute('content', window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._originalViewPortMetaTagContent); - document.getElementsByTagName('head')[0].appendChild(meta); - })() - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/WebMessageChannelJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/WebMessageChannelJS.swift deleted file mode 100644 index e41494d88e..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/WebMessageChannelJS.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// WebMessageChannelJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/03/21. -// - -import Foundation - -public class WebMessageChannelJS { - - public static func WEB_MESSAGE_CHANNELS_VARIABLE_NAME() -> String { - return "window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())._webMessageChannels" - } - -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/WebMessageListenerJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/WebMessageListenerJS.swift deleted file mode 100644 index 6740765ac5..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/WebMessageListenerJS.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// WebMessageListenerJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/03/21. -// - -import Foundation - -public class WebMessageListenerJS { - - public static func WEB_MESSAGE_LISTENER_JS_SOURCE() -> String { - return """ - function FlutterInAppWebViewWebMessageListener(jsObjectName) { - this.jsObjectName = jsObjectName; - this.listeners = []; - this.onmessage = null; - } - FlutterInAppWebViewWebMessageListener.prototype.postMessage = function(data) { - var message = { - "data": window.ArrayBuffer != null && data instanceof ArrayBuffer ? Array.from(new Uint8Array(data)) : (data != null ? data.toString() : null), - "type": window.ArrayBuffer != null && data instanceof ArrayBuffer ? 1 : 0 - }; - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onWebMessageListenerPostMessageReceived', {jsObjectName: this.jsObjectName, message: message}); - }; - FlutterInAppWebViewWebMessageListener.prototype.addEventListener = function(type, listener) { - if (listener == null) { - return; - } - this.listeners.push(listener); - }; - FlutterInAppWebViewWebMessageListener.prototype.removeEventListener = function(type, listener) { - if (listener == null) { - return; - } - var index = this.listeners.indexOf(listener); - if (index >= 0) { - this.listeners.splice(index, 1); - } - }; - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/WindowIdJS.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/WindowIdJS.swift deleted file mode 100644 index 173167416d..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PluginScriptsJS/WindowIdJS.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// WindowIdJS.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class WindowIdJS { - - public static let WINDOW_ID_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_WINDOW_ID_JS_PLUGIN_SCRIPT" - - public static func WINDOW_ID_VARIABLE_JS_SOURCE() -> String { - return "window._\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())_windowId" - } - - public static func WINDOW_ID_INITIALIZE_JS_SOURCE() -> String { - return """ - (function() { - \(WINDOW_ID_VARIABLE_JS_SOURCE()) = \(PluginScriptsUtil.VAR_PLACEHOLDER_VALUE); - return \(WINDOW_ID_VARIABLE_JS_SOURCE()); - })() - """ - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/CustomUIPrintPageRenderer.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/CustomUIPrintPageRenderer.swift deleted file mode 100644 index 214ad7de2d..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/CustomUIPrintPageRenderer.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// CustomUIPrintPageRenderer.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/05/22. -// - -import Foundation -// -//public class CustomUIPrintPageRenderer: UIPrintPageRenderer { -// private var _numberOfPages: Int? -// private var forceRenderingQuality: Int? -// -// public init(numberOfPage: Int? = nil, forceRenderingQuality: Int? = nil) { -// super.init() -// self._numberOfPages = numberOfPage -// self.forceRenderingQuality = forceRenderingQuality -// } -// -// open override var numberOfPages: Int { -// get { -// return _numberOfPages ?? super.numberOfPages -// } -// } -// -// @available(iOS 14.5, *) -// open override func currentRenderingQuality(forRequested requestedRenderingQuality: UIPrintRenderingQuality) -> UIPrintRenderingQuality { -// if let forceRenderingQuality = forceRenderingQuality, -// let quality = UIPrintRenderingQuality.init(rawValue: forceRenderingQuality) { -// return quality -// } -// return super.currentRenderingQuality(forRequested: requestedRenderingQuality) -// } -//} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintAttributes.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintAttributes.swift deleted file mode 100644 index d2888a9c23..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintAttributes.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// PrintAttributes.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/05/22. -// - -import Foundation -import AppKit - -public class PrintAttributes: NSObject { - var orientation: NSPrintInfo.PaperOrientation? - var margins: NSEdgeInsets? - var paperRect: CGRect? - var colorMode: String? - var duplex: Int? - var paperName: String? - var localizedPaperName: String? - var horizontalPagination: UInt? - var verticalPagination: UInt? - var jobDisposition: String? - var printableRect: NSRect? - var isHorizontallyCentered: Bool? - var isVerticallyCentered: Bool? - var isSelectionOnly: Bool? - var scalingFactor: CGFloat? - var jobSavingURL: String? - var detailedErrorReporting: Bool? - var faxNumber: String? - var headerAndFooter: Bool? - var mustCollate: Bool? - var pagesAcross: Int? - var pagesDown: Int? - var time: Int? - - public init(fromPrintJobController: PrintJobController) { - super.init() - if let job = fromPrintJobController.job { - let printInfo = job.printInfo - let printInfoDictionary = printInfo.dictionary() - orientation = printInfo.orientation - margins = NSEdgeInsets(top: printInfo.topMargin, - left: printInfo.leftMargin, - bottom: printInfo.bottomMargin, - right: printInfo.rightMargin) - paperRect = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: printInfo.paperSize) - colorMode = printInfo.printSettings["ColorModel"] as? String - duplex = printInfo.printSettings["com_apple_print_PrintSettings_PMDuplexing"] as? Int - paperName = printInfo.paperName?.rawValue - localizedPaperName = printInfo.localizedPaperName - horizontalPagination = printInfo.horizontalPagination.rawValue - verticalPagination = printInfo.verticalPagination.rawValue - jobDisposition = printInfo.jobDisposition.rawValue - printableRect = printInfo.imageablePageBounds - isHorizontallyCentered = printInfo.isHorizontallyCentered - isVerticallyCentered = printInfo.isVerticallyCentered - isSelectionOnly = printInfo.isSelectionOnly - scalingFactor = printInfo.scalingFactor - jobSavingURL = (printInfoDictionary[NSPrintInfo.AttributeKey.jobSavingURL] as? URL)?.absoluteString - detailedErrorReporting = printInfoDictionary[NSPrintInfo.AttributeKey.detailedErrorReporting] as? Bool - faxNumber = printInfoDictionary[NSPrintInfo.AttributeKey.faxNumber] as? String - headerAndFooter = printInfoDictionary[NSPrintInfo.AttributeKey.headerAndFooter] as? Bool - mustCollate = printInfoDictionary[NSPrintInfo.AttributeKey.mustCollate] as? Bool - pagesAcross = printInfoDictionary[NSPrintInfo.AttributeKey.pagesAcross] as? Int - pagesDown = printInfoDictionary[NSPrintInfo.AttributeKey.pagesDown] as? Int - if let timestamp = (printInfoDictionary[NSPrintInfo.AttributeKey.time] as? Date)?.timeIntervalSince1970 { - time = Int(timestamp) - } - } - } - - public func toMap () -> [String:Any?] { - return [ - "paperRect": paperRect?.toMap(), - "margins": margins?.toMap(), - "orientation": orientation?.rawValue, - "colorMode": colorMode, - "duplex": duplex, - "paperName": paperName, - "localizedPaperName": localizedPaperName, - "horizontalPagination": horizontalPagination, - "verticalPagination": verticalPagination, - "jobDisposition": jobDisposition, - "printableRect": printableRect?.toMap(), - "isHorizontallyCentered": isHorizontallyCentered, - "isVerticallyCentered": isVerticallyCentered, - "isSelectionOnly": isSelectionOnly, - "scalingFactor": scalingFactor, - "jobSavingURL": jobSavingURL, - "detailedErrorReporting": detailedErrorReporting, - "faxNumber": faxNumber, - "headerAndFooter": headerAndFooter, - "mustCollate": mustCollate, - "pagesAcross": pagesAcross, - "pagesDown": pagesDown, - "time": time - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintJobChannelDelegate.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintJobChannelDelegate.swift deleted file mode 100644 index d2000c8b18..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintJobChannelDelegate.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// PrintJobChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 09/05/22. -// - -import Foundation -import FlutterMacOS - -public class PrintJobChannelDelegate: ChannelDelegate { - private weak var printJobController: PrintJobController? - - public init(printJobController: PrintJobController, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.printJobController = printJobController - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "getInfo": - if let printJobController = printJobController { - result(printJobController.getInfo()?.toMap()) - } else { - result(false) - } - break - case "dispose": - if let printJobController = printJobController { - printJobController.dispose() - result(true) - } else { - result(false) - } - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func onComplete(completed: Bool, error: Error?) { - let arguments: [String: Any?] = [ - "completed": completed, - "error": error?.localizedDescription - ] - channel?.invokeMethod("onComplete", arguments: arguments) - } - - public override func dispose() { - super.dispose() - printJobController = nil - } - - deinit { - debugPrint("PrintJobChannelDelegate - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintJobController.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintJobController.swift deleted file mode 100644 index 400f7160d2..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintJobController.swift +++ /dev/null @@ -1,92 +0,0 @@ -// -// PrintJob.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 09/05/22. -// - -import Foundation -import FlutterMacOS - -public enum PrintJobState: Int { - case created = 1 - case started = 3 - case completed = 5 - case canceled = 7 -} - -public class PrintJobController: NSObject, Disposable { - static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_printjobcontroller_" - var id: String - var plugin: InAppWebViewFlutterPlugin? - var job: NSPrintOperation? - var settings: PrintJobSettings? - var channelDelegate: PrintJobChannelDelegate? - var state = PrintJobState.created - var creationTime = Int64(Date().timeIntervalSince1970 * 1000) - var disposeWhenDidRun = false - private var completionHandler: PrintJobController.CompletionHandler? - - public typealias CompletionHandler = (_ printOperation: NSPrintOperation, - _ success: Bool, - _ contextInfo: UnsafeMutableRawPointer?) -> Void - - public init(plugin: InAppWebViewFlutterPlugin, id: String, job: NSPrintOperation? = nil, settings: PrintJobSettings? = nil) { - self.id = id - self.plugin = plugin - super.init() - self.job = job - self.settings = settings - let channel = FlutterMethodChannel(name: PrintJobController.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: plugin.registrar.messenger) - self.channelDelegate = PrintJobChannelDelegate(printJobController: self, channel: channel) - } - - public func present(parentWindow: NSWindow? = nil, completionHandler: PrintJobController.CompletionHandler? = nil) { - guard let job = job else { - return - } - state = .started - self.completionHandler = completionHandler - if let mainWindow = parentWindow ?? NSApplication.shared.mainWindow { - job.runModal(for: mainWindow, delegate: self, didRun: #selector(printOperationDidRun), contextInfo: nil) - } - } - - @objc func printOperationDidRun(printOperation: NSPrintOperation, - success: Bool, - contextInfo: UnsafeMutableRawPointer?) { - DispatchQueue.main.async { [weak self] in - self?.state = success ? .completed : .canceled - self?.channelDelegate?.onComplete(completed: success, error: nil) - if let completionHandler = self?.completionHandler { - completionHandler(printOperation, success, contextInfo) - self?.completionHandler = nil - } - if let disposeWhenDidRun = self?.disposeWhenDidRun, disposeWhenDidRun { - self?.dispose() - } - } - } - - public func getInfo() -> PrintJobInfo? { - guard let _ = job else { - return nil - } - - return PrintJobInfo.init(fromPrintJobController: self) - } - - public func dispose() { - channelDelegate?.dispose() - channelDelegate = nil - completionHandler = nil - job = nil - plugin?.printJobManager?.jobs[id] = nil - plugin = nil - } - - deinit { - debugPrint("PrintJobController - dealloc") - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintJobInfo.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintJobInfo.swift deleted file mode 100644 index 4cfce9e8f8..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintJobInfo.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// PrintJobInfo.swift -// flutter_downloader -// -// Created by Lorenzo Pichilli on 10/05/22. -// - -import Foundation -import AppKit - -public class PrintJobInfo: NSObject { - var state: PrintJobState - var attributes: PrintAttributes - var creationTime: Int64 - var numberOfPages: Int? - var copies: Int? - var label: String? - var printer: NSPrinter? - var pageOrder: Int? - var preferredRenderingQuality: Int? - var showsProgressPanel: Bool? - var showsPrintPanel: Bool? - var canSpawnSeparateThread: Bool? - var isCopyingOperation: Bool? - var currentPage: Int? - var firstPage: Int? - var lastPage: Int? - - public init(fromPrintJobController: PrintJobController) { - state = fromPrintJobController.state - creationTime = fromPrintJobController.creationTime - attributes = PrintAttributes.init(fromPrintJobController: fromPrintJobController) - super.init() - if let job = fromPrintJobController.job { - let printInfo = job.printInfo - let printInfoDictionary = printInfo.dictionary() - printer = printInfo.printer - copies = printInfo.printSettings["com_apple_print_PrintSettings_PMCopies"] as? Int - label = job.jobTitle - firstPage = printInfoDictionary[NSPrintInfo.AttributeKey.firstPage] as? Int - lastPage = printInfoDictionary[NSPrintInfo.AttributeKey.lastPage] as? Int - if let firstPage = firstPage, let lastPage = lastPage { - numberOfPages = lastPage - firstPage + 1 - } - if numberOfPages == nil { - numberOfPages = printInfo.printSettings["com_apple_print_PrintSettings_PMLastPage"] as? Int - if numberOfPages == nil || numberOfPages! > job.pageRange.length { - numberOfPages = job.pageRange.length - } - } - pageOrder = job.pageOrder.rawValue - preferredRenderingQuality = job.preferredRenderingQuality.rawValue - showsProgressPanel = job.showsProgressPanel - showsPrintPanel = job.showsPrintPanel - canSpawnSeparateThread = job.canSpawnSeparateThread - isCopyingOperation = job.isCopyingOperation - currentPage = job.currentPage - } - } - - public func toMap () -> [String:Any?] { - return [ - "state": state.rawValue, - "attributes": attributes.toMap(), - "numberOfPages": numberOfPages, - "copies": copies, - "creationTime": creationTime, - "label": label, - "printer": printer?.toMap(), - "pageOrder": pageOrder, - "preferredRenderingQuality": preferredRenderingQuality, - "showsProgressPanel": showsProgressPanel, - "showsPrintPanel": showsPrintPanel, - "canSpawnSeparateThread": canSpawnSeparateThread, - "isCopyingOperation": isCopyingOperation, - "currentPage": currentPage, - "firstPage": firstPage, - "lastPage": lastPage - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintJobManager.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintJobManager.swift deleted file mode 100644 index cf86b1e46a..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintJobManager.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// PrintJobManager.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 09/05/22. -// - -import Foundation - -public class PrintJobManager: NSObject, Disposable { - var plugin: InAppWebViewFlutterPlugin? - var jobs: [String: PrintJobController?] = [:] - - public init(plugin: InAppWebViewFlutterPlugin?) { - super.init() - self.plugin = plugin - } - - public func dispose() { - let jobValues = jobs.values - jobValues.forEach { (job: PrintJobController?) in - job?.dispose() - } - jobs.removeAll() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintJobSettings.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintJobSettings.swift deleted file mode 100644 index a3fe36b4e0..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/PrintJob/PrintJobSettings.swift +++ /dev/null @@ -1,210 +0,0 @@ -// -// PrintJobSettings.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 09/05/22. -// - -import Foundation - -@objcMembers -public class PrintJobSettings: ISettings { - - public var handledByClient = false - public var jobName: String? - public var _orientation: NSNumber? - public var orientation: Int? { - get { - return _orientation?.intValue - } - set { - if let newValue = newValue { - _orientation = NSNumber.init(value: newValue) - } else { - _orientation = nil - } - } - } - public var _numberOfPages: NSNumber? - public var numberOfPages: Int64? { - get { - return _numberOfPages?.int64Value - } - set { - if let newValue = newValue { - _numberOfPages = NSNumber.init(value: newValue) - } else { - _numberOfPages = nil - } - } - } - public var margins: NSEdgeInsets? - public var colorMode: String? - public var showsNumberOfCopies = true - public var showsPaperOrientation = true - public var showsPaperSize = true - public var showsScaling = true - public var showsPageRange = true - public var showsPageSetupAccessory = true - public var showsPreview = true - public var showsPrintSelection = true - public var showsPrintPanel = true - public var showsProgressPanel = true - public var _scalingFactor: NSNumber? - public var scalingFactor: Double? { - get { - return _scalingFactor?.doubleValue - } - set { - if let newValue = newValue { - _scalingFactor = NSNumber.init(value: newValue) - } else { - _scalingFactor = nil - } - } - } - public var jobDisposition: String? - public var jobSavingURL: String? - public var paperName: String? - public var _horizontalPagination: NSNumber? - public var horizontalPagination: UInt? { - get { - return _horizontalPagination?.uintValue - } - set { - if let newValue = newValue { - _horizontalPagination = NSNumber.init(value: newValue) - } else { - _horizontalPagination = nil - } - } - } - public var _verticalPagination: NSNumber? - public var verticalPagination: UInt? { - get { - return _verticalPagination?.uintValue - } - set { - if let newValue = newValue { - _verticalPagination = NSNumber.init(value: newValue) - } else { - _verticalPagination = nil - } - } - } - public var isHorizontallyCentered = true - public var isVerticallyCentered = true - public var _pageOrder: NSNumber? - public var pageOrder: Int? { - get { - return _pageOrder?.intValue - } - set { - if let newValue = newValue { - _pageOrder = NSNumber.init(value: newValue) - } else { - _pageOrder = nil - } - } - } - public var canSpawnSeparateThread = true - public var copies = 1 - public var _firstPage: NSNumber? - public var firstPage: Int64? { - get { - return _firstPage?.int64Value - } - set { - if let newValue = newValue { - _firstPage = NSNumber.init(value: newValue) - } else { - _firstPage = nil - } - } - } - public var _lastPage: NSNumber? - public var lastPage: Int64? { - get { - return _lastPage?.int64Value - } - set { - if let newValue = newValue { - _lastPage = NSNumber.init(value: newValue) - } else { - _lastPage = nil - } - } - } - public var detailedErrorReporting = false - public var faxNumber: String? - public var headerAndFooter = true - public var _mustCollate: NSNumber? - public var mustCollate: Bool? { - get { - return _mustCollate?.boolValue - } - set { - if let newValue = newValue { - _mustCollate = NSNumber.init(value: newValue) - } else { - _mustCollate = nil - } - } - } - public var _pagesAcross: NSNumber? - public var pagesAcross: Int64? { - get { - return _pagesAcross?.int64Value - } - set { - if let newValue = newValue { - _pagesAcross = NSNumber.init(value: newValue) - } else { - _pagesAcross = nil - } - } - } - public var _pagesDown: NSNumber? - public var pagesDown: Int64? { - get { - return _pagesDown?.int64Value - } - set { - if let newValue = newValue { - _pagesDown = NSNumber.init(value: newValue) - } else { - _pagesDown = nil - } - } - } - public var _time: NSNumber? - public var time: Int64? { - get { - return _time?.int64Value - } - set { - if let newValue = newValue { - _time = NSNumber.init(value: newValue) - } else { - _time = nil - } - } - } - - override init(){ - super.init() - } - - override func parse(settings: [String: Any?]) -> PrintJobSettings { - let _ = super.parse(settings: settings) - if let marginsMap = settings["margins"] as? [String : Double] { - margins = NSEdgeInsets.fromMap(map: marginsMap) - } - return self - } - - override func getRealSettings(obj: PrintJobController?) -> [String: Any?] { - var realOptions: [String: Any?] = toMap() - return realOptions - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/ProxyManager.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/ProxyManager.swift deleted file mode 100644 index 082d55bf2f..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/ProxyManager.swift +++ /dev/null @@ -1,248 +0,0 @@ -// -// ProxyManager.swift -// flutter_inappwebview -// - -import Foundation -import WebKit -import FlutterMacOS - -@available(macOS 14.0, *) -public class ProxyManager: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_proxycontroller" - - private var plugin: InAppWebViewFlutterPlugin? - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: ProxyManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger)) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? [String: Any] - switch call.method { - case "setProxyOverride": - if let args = arguments?["settings"] as? [String:Any?], - let settings = ProxySettings.fromMap(map: args) { - setProxyOverride(settings) - result(true) - } else { - result(false) - } - break - case "clearProxyOverride": - clearProxyOverride() - result(true) - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func setProxyOverride(_ settings: ProxySettings) { - let proxyConfigurations = settings.toProxyConfigurations() - WKWebsiteDataStore.default().proxyConfigurations = proxyConfigurations - WKWebsiteDataStore.nonPersistent().proxyConfigurations = proxyConfigurations - } - - public func clearProxyOverride() { - WKWebsiteDataStore.default().proxyConfigurations = [] - WKWebsiteDataStore.nonPersistent().proxyConfigurations = [] - } - - public override func dispose() { - super.dispose() - plugin = nil - } - - deinit { - debugPrint("ProxyManager - dealloc") - dispose() - } -} - -@available(macOS 14.0, *) -public class ProxySettings { - var proxyRules: [ProxyRule] - - init( - proxyRules: [ProxyRule] - ) { - self.proxyRules = proxyRules - } - - public static func fromMap(map: [String:Any?]?) -> ProxySettings? { - guard let map = map else { - return nil - } - return ProxySettings( - proxyRules: (map["proxyRules"] as! [[String:Any?]]).map { ProxyRule.fromMap(map: $0)! } - ) - } - - public func toProxyConfigurations() -> [ProxyConfiguration] { - var proxyConfigurations: [ProxyConfiguration] = [] - for rule in proxyRules { - if let proxyConfiguration = rule.toProxyConfiguration() { - proxyConfigurations.append(proxyConfiguration) - } - } - return proxyConfigurations - } -} - -@available(macOS 14.0, *) -public class ProxyRule { - var url: String - var allowFailover: Bool? - var excludedDomains: [String]? - var matchDomains: [String]? - var username: String? - var password: String? - var relayHop1: ProxyRelayHop? - var relayHop2: ProxyRelayHop? - - init( - url: String, - allowFailover: Bool?, - excludedDomains: [String]?, - matchDomains: [String]?, - username: String?, - password: String?, - relayHop1: ProxyRelayHop?, - relayHop2: ProxyRelayHop? - ) { - self.url = url - self.allowFailover = allowFailover - self.excludedDomains = excludedDomains - self.matchDomains = matchDomains - self.username = username - self.password = password - self.relayHop1 = relayHop1 - self.relayHop2 = relayHop2 - } - - public static func fromMap(map: [String:Any?]?) -> ProxyRule? { - guard let map = map else { - return nil - } - return ProxyRule( - url: map["url"] as! String, - allowFailover: map["allowFailover"] as? Bool, - excludedDomains: map["excludedDomains"] as? [String], - matchDomains: map["matchDomains"] as? [String], - username: map["username"] as? String, - password: map["password"] as? String, - relayHop1: ProxyRelayHop.fromMap(map: map["relayHop1"] as? [String:Any?]), - relayHop2: ProxyRelayHop.fromMap(map: map["relayHop2"] as? [String:Any?]) - ) - } - - public func toProxyConfiguration() -> ProxyConfiguration? { - guard let endpointUrl = URL(string: url.contains("://") ? url : "http://" + url), - let port: NWEndpoint.Port = .init(rawValue: UInt16(endpointUrl.port ?? 80)), - let host = endpointUrl.host else { - return nil - } - - var endpointHost = NWEndpoint.Host(host) - if let ipv4 = IPv4Address(host) { - endpointHost = .ipv4(ipv4) - } else if let ipv6 = IPv6Address(host) { - endpointHost = .ipv6(ipv6) - } - let endpoint = NWEndpoint.hostPort(host: endpointHost, port: port) - var proxyConfiguration: ProxyConfiguration - let proxyRelayHops: [ProxyRelayHop] = [relayHop1, relayHop2].filter({ $0 != nil }).map({ $0! }) - if !proxyRelayHops.isEmpty { - proxyConfiguration = ProxyConfiguration(relayHops: proxyRelayHops.compactMap({ $0.toRelayHop() })) - } else { - proxyConfiguration = endpointUrl.scheme?.lowercased() == "socks5" ? - ProxyConfiguration(socksv5Proxy: endpoint) : - ProxyConfiguration(httpCONNECTProxy: endpoint, tlsOptions: endpointUrl.scheme?.lowercased() == "https" ? .init() : nil) - } - - if let allowFailover = allowFailover { - proxyConfiguration.allowFailover = allowFailover - } - if let excludedDomains = excludedDomains { - proxyConfiguration.excludedDomains = excludedDomains - } - if let matchDomains = matchDomains { - proxyConfiguration.matchDomains = matchDomains - } - if let username = username, let password = password { - proxyConfiguration.applyCredential(username: username, password: password) - } - return proxyConfiguration - } -} - -@available(macOS 14.0, *) -public class ProxyRelayHop { - var http3RelayEndpoint: String? - var http2RelayEndpoint: String? - var additionalHTTPHeaders: [String:String]? - - init( - http3RelayEndpoint: String, - http2RelayEndpoint: String?, - additionalHTTPHeaders: [String:String]? - ) { - self.http3RelayEndpoint = http3RelayEndpoint - self.http2RelayEndpoint = http2RelayEndpoint - self.additionalHTTPHeaders = additionalHTTPHeaders - } - - init( - http2RelayEndpoint: String, - additionalHTTPHeaders: [String:String]? - ) { - self.http2RelayEndpoint = http2RelayEndpoint - self.additionalHTTPHeaders = additionalHTTPHeaders - } - - public static func fromMap(map: [String:Any?]?) -> ProxyRelayHop? { - guard let map = map else { - return nil - } - let http3RelayEndpoint = map["http3RelayEndpoint"] as? String - let http2RelayEndpoint = map["http2RelayEndpoint"] as? String - let additionalHTTPHeaders = map["additionalHTTPHeaders"] as? [String:String] - if http3RelayEndpoint == nil, http2RelayEndpoint == nil { - return nil - } - if http3RelayEndpoint != nil { - return ProxyRelayHop( - http3RelayEndpoint: http3RelayEndpoint!, - http2RelayEndpoint: http2RelayEndpoint, - additionalHTTPHeaders: additionalHTTPHeaders - ) - } - return ProxyRelayHop( - http2RelayEndpoint: http2RelayEndpoint!, - additionalHTTPHeaders: additionalHTTPHeaders - ) - } - - public func toRelayHop() -> ProxyConfiguration.RelayHop? { - if let http3RelayEndpoint = http3RelayEndpoint, - let url = URL(string: http3RelayEndpoint) { - var http2Endpoint: NWEndpoint? = nil - if let http2RelayEndpoint = http2RelayEndpoint, - let url2 = URL(string: http2RelayEndpoint) { - http2Endpoint = NWEndpoint.url(url2) - } - return ProxyConfiguration.RelayHop(http3RelayEndpoint: NWEndpoint.url(url), - http2RelayEndpoint: http2Endpoint, - additionalHTTPHeaderFields: additionalHTTPHeaders ?? [:]) - } - if let http2RelayEndpoint = http2RelayEndpoint, - let url = URL(string: http2RelayEndpoint) { - return ProxyConfiguration.RelayHop(http2RelayEndpoint: NWEndpoint.url(url), - additionalHTTPHeaderFields: additionalHTTPHeaders ?? [:]) - } - return nil - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Resources/PrivacyInfo.xcprivacy b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Resources/PrivacyInfo.xcprivacy deleted file mode 100644 index 0eca193ea7..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Resources/PrivacyInfo.xcprivacy +++ /dev/null @@ -1,14 +0,0 @@ - - - - - NSPrivacyTrackingDomains - - NSPrivacyAccessedAPITypes - - NSPrivacyCollectedDataTypes - - NSPrivacyTracking - - - \ No newline at end of file diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/BaseCallbackResult.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/BaseCallbackResult.swift deleted file mode 100644 index aa79e499fd..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/BaseCallbackResult.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// BaseCallbackResult.swift -// shared-apple -// -// Created by Lorenzo Pichilli on 17/10/22. -// - -import Foundation - -public class BaseCallbackResult: CallbackResult { - - override init() { - super.init() - - self.success = { [weak self] (obj: Any?) in - let result: T? = self?.decodeResult(obj) - var shouldRunDefaultBehaviour = false - if let result = result { - shouldRunDefaultBehaviour = self?.nonNullSuccess(result) ?? shouldRunDefaultBehaviour - } else { - shouldRunDefaultBehaviour = self?.nullSuccess() ?? shouldRunDefaultBehaviour - } - if shouldRunDefaultBehaviour { - self?.defaultBehaviour(result) - } - } - - self.notImplemented = { [weak self] in - self?.defaultBehaviour(nil) - } - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/CGRect.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/CGRect.swift deleted file mode 100644 index 61cb7627f5..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/CGRect.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// CGRect.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/05/22. -// - -import Foundation - -extension CGRect { - public static func fromMap(map: [String: Double]) -> CGRect { - return CGRect(x: map["x"]!, y: map["y"]!, width: map["width"]!, height: map["height"]!) - } - - public func toMap () -> [String:Any?] { - return [ - "x": minX, - "y": minY, - "width": width, - "height": height - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/CallbackResult.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/CallbackResult.swift deleted file mode 100644 index 083d6880d0..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/CallbackResult.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// CallbackResult.swift -// shared-apple -// -// Created by Lorenzo Pichilli on 17/10/22. -// - -import Foundation - -public class CallbackResult: MethodChannelResult { - public var notImplemented: () -> Void = {} - public var success: (Any?) -> Void = {_ in } - public var error: (String, String?, Any?) -> Void = {_,_,_ in } - public var nonNullSuccess: (T) -> Bool = {_ in true} - public var nullSuccess: () -> Bool = {true} - public var defaultBehaviour: (T?) -> Void = {_ in } - public var decodeResult: (Any?) -> T? = {_ in nil} -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/ChannelDelegate.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/ChannelDelegate.swift deleted file mode 100644 index e56474f8e1..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/ChannelDelegate.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// ChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 04/05/22. -// - -import Foundation -import FlutterMacOS - -public class ChannelDelegate: FlutterMethodCallDelegate, Disposable { - var channel: FlutterMethodChannel? - - public init(channel: FlutterMethodChannel) { - super.init() - self.channel = channel - self.channel?.setMethodCallHandler(handle) - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - - } - - public func dispose() { - channel?.setMethodCallHandler(nil) - channel = nil - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/ClientCertChallenge.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/ClientCertChallenge.swift deleted file mode 100644 index f2381ee4a5..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/ClientCertChallenge.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// ClientCertChallenge.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 15/02/21. -// - -import Foundation - -public class ClientCertChallenge: NSObject { - var protectionSpace: URLProtectionSpace! - - public init(fromChallenge: URLAuthenticationChallenge) { - protectionSpace = fromChallenge.protectionSpace - } - - public func toMap () -> [String:Any?] { - return [ - "protectionSpace": protectionSpace.toMap(), - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/ClientCertResponse.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/ClientCertResponse.swift deleted file mode 100644 index 6273db74ba..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/ClientCertResponse.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// ClientCertResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation - -public class ClientCertResponse: NSObject { - var certificatePath: String - var certificatePassword: String? - var keyStoreType: String? - var action: Int? - - public init(certificatePath: String, certificatePassword: String? = nil, keyStoreType: String? = nil, action: Int? = nil) { - self.certificatePath = certificatePath - self.certificatePassword = certificatePassword - self.keyStoreType = keyStoreType - self.action = action - } - - public static func fromMap(map: [String:Any?]?) -> ClientCertResponse? { - guard let map = map else { - return nil - } - let certificatePath = map["certificatePath"] as! String - let certificatePassword = map["certificatePassword"] as? String - let keyStoreType = map["keyStoreType"] as? String - let action = map["action"] as? Int - return ClientCertResponse(certificatePath: certificatePath, certificatePassword: certificatePassword, keyStoreType: keyStoreType, action: action) - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/CreateWindowAction.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/CreateWindowAction.swift deleted file mode 100644 index f3b4681f6f..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/CreateWindowAction.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// CreateWindowAction.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation -import WebKit - -public class CreateWindowAction: NSObject { - var navigationAction: WKNavigationAction - var windowId: Int64 - var windowFeatures: WKWindowFeatures - var isDialog: Bool? - - public init(navigationAction: WKNavigationAction, windowId: Int64, windowFeatures: WKWindowFeatures, isDialog: Bool? = nil) { - self.navigationAction = navigationAction - self.windowId = windowId - self.windowFeatures = windowFeatures - self.isDialog = isDialog - } - - public func toMap () -> [String:Any?] { - var map = navigationAction.toMap() - map["windowId"] = windowId - map["windowFeatures"] = windowFeatures.toMap() - map["isDialog"] = isDialog - return map - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/CustomSchemeResponse.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/CustomSchemeResponse.swift deleted file mode 100644 index 53836c94da..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/CustomSchemeResponse.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// CustomSchemeResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation -import FlutterMacOS - -public class CustomSchemeResponse: NSObject { - var data: Data - var contentType: String - var contentEncoding: String - - public init(data: Data, contentType: String, contentEncoding: String) { - self.data = data - self.contentType = contentType - self.contentEncoding = contentEncoding - } - - public static func fromMap(map: [String:Any?]?) -> CustomSchemeResponse? { - guard let map = map else { - return nil - } - let data = map["data"] as! FlutterStandardTypedData - let contentType = map["contentType"] as! String - let contentEncoding = map["contentEncoding"] as! String - return CustomSchemeResponse(data: data.data, contentType: contentType, contentEncoding: contentEncoding) - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/Disposable.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/Disposable.swift deleted file mode 100644 index 0a34a94248..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/Disposable.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// Disposable.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 04/05/22. -// - -import Foundation - -public protocol Disposable { - func dispose() -> Void -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/DownloadStartRequest.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/DownloadStartRequest.swift deleted file mode 100644 index 808f9453ca..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/DownloadStartRequest.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// DownloadStartRequest.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 17/04/22. -// - -import Foundation - -public class DownloadStartRequest: NSObject { - var url: String - var userAgent: String? - var contentDisposition: String? - var mimeType: String? - var contentLength: Int64 - var suggestedFilename: String? - var textEncodingName: String? - - public init(url: String, userAgent: String?, contentDisposition: String?, - mimeType: String?, contentLength: Int64, - suggestedFilename: String?, textEncodingName: String?) { - self.url = url - self.userAgent = userAgent - self.contentDisposition = contentDisposition - self.mimeType = mimeType - self.contentLength = contentLength - self.suggestedFilename = suggestedFilename - self.textEncodingName = textEncodingName - } - - public func toMap () -> [String:Any?] { - return [ - "url": url, - "userAgent": userAgent, - "contentDisposition": contentDisposition, - "mimeType": mimeType, - "contentLength": contentLength, - "suggestedFilename": suggestedFilename, - "textEncodingName": textEncodingName - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/FindSession.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/FindSession.swift deleted file mode 100644 index 0c247004cb..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/FindSession.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// UIFindSession.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/10/22. -// - -import Foundation - -public class FindSession: NSObject { - var resultCount: Int - var highlightedResultIndex: Int - var searchResultDisplayStyle: Int - - public init(resultCount: Int, highlightedResultIndex: Int, searchResultDisplayStyle: Int) { - self.resultCount = resultCount - self.highlightedResultIndex = highlightedResultIndex - self.searchResultDisplayStyle = searchResultDisplayStyle - } - - public func toMap () -> [String:Any?] { - return [ - "resultCount": resultCount, - "highlightedResultIndex": highlightedResultIndex, - "searchResultDisplayStyle": searchResultDisplayStyle - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/FlutterMethodCallDelegate.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/FlutterMethodCallDelegate.swift deleted file mode 100755 index 0454d2f701..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/FlutterMethodCallDelegate.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// FlutterMethodCallDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 15/12/2019. -// - -import Foundation -import FlutterMacOS - -public class FlutterMethodCallDelegate: NSObject { - public override init() { - super.init() - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/FlutterMethodChannel.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/FlutterMethodChannel.swift deleted file mode 100644 index e9055b2e54..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/FlutterMethodChannel.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// FlutterMethodChannel.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 06/05/22. -// - -import Foundation -import FlutterMacOS - -extension FlutterMethodChannel { - public func invokeMethod(_ method: String, arguments: Any, callback: MethodChannelResult) { - invokeMethod(method, arguments: arguments) {(result) -> Void in - if result is FlutterError { - let error = result as! FlutterError - callback.error(error.code, error.message, error.details) - } - else if (result as? NSObject) == FlutterMethodNotImplemented { - callback.notImplemented() - } - else { - callback.success(result) - } - } - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/HitTestResult.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/HitTestResult.swift deleted file mode 100644 index 53307789f0..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/HitTestResult.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// HitTestResult.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public enum HitTestResultType: Int { - case unknownType = 0 - case phoneType = 2 - case geoType = 3 - case emailType = 4 - case imageType = 5 - case srcAnchorType = 7 - case srcImageAnchorType = 8 - case editTextType = 9 -} - -public class HitTestResult: NSObject { - var type: HitTestResultType - var extra: String? - - public init(type: HitTestResultType, extra: String?) { - self.type = type - self.extra = extra - } - - public static func fromMap(map: [String:Any?]?) -> HitTestResult? { - guard let map = map else { - return nil - } - let type = HitTestResultType.init(rawValue: map["type"] as? Int ?? HitTestResultType.unknownType.rawValue) ?? HitTestResultType.unknownType - return HitTestResult(type: type, extra: map["extra"] as? String) - } - - public func toMap () -> [String:Any?] { - return [ - "type": type.rawValue, - "extra": extra, - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/HttpAuthResponse.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/HttpAuthResponse.swift deleted file mode 100644 index f77d3ab1c1..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/HttpAuthResponse.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// HttpAuthResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation - -public class HttpAuthResponse: NSObject { - var username: String - var password: String - var permanentPersistence: Bool - var action: Int? - - public init(username: String, password: String, permanentPersistence: Bool, action: Int? = nil) { - self.username = username - self.password = password - self.permanentPersistence = permanentPersistence - self.action = action - } - - public static func fromMap(map: [String:Any?]?) -> HttpAuthResponse? { - guard let map = map else { - return nil - } - let username = map["username"] as! String - let password = map["password"] as! String - let permanentPersistence = map["permanentPersistence"] as! Bool - let action = map["action"] as? Int - return HttpAuthResponse(username: username, password: password, permanentPersistence: permanentPersistence, action: action) - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/HttpAuthenticationChallenge.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/HttpAuthenticationChallenge.swift deleted file mode 100644 index b22a009234..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/HttpAuthenticationChallenge.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// HttpAuthenticationChallenge.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 15/02/21. -// - -import Foundation - -public class HttpAuthenticationChallenge: NSObject { - var protectionSpace: URLProtectionSpace! - var previousFailureCount: Int = 0 - var failureResponse: URLResponse? - var error: Error? - var proposedCredential: URLCredential? - - public init(fromChallenge: URLAuthenticationChallenge) { - protectionSpace = fromChallenge.protectionSpace - previousFailureCount = fromChallenge.previousFailureCount - failureResponse = fromChallenge.failureResponse - error = fromChallenge.error - proposedCredential = fromChallenge.proposedCredential - } - - public func toMap () -> [String:Any?] { - return [ - "protectionSpace": protectionSpace.toMap(), - "previousFailureCount": previousFailureCount, - "failureResponse": failureResponse?.toMap(), - "error": error?.localizedDescription, - "proposedCredential": proposedCredential?.toMap() - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/InAppBrowserMenuItem.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/InAppBrowserMenuItem.swift deleted file mode 100644 index beeee48646..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/InAppBrowserMenuItem.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// InAppBrowserMenuItem.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 23/05/23. -// - -import Foundation -import FlutterMacOS - -public class InAppBrowserMenuItem: NSObject { - var id: Int64 - var title: String - var order: Int64? - var icon: NSImage? - var iconColor: NSColor? - var showAsAction = false - - public init(id: Int64, title: String, order: Int64?, icon: NSImage?, iconColor: NSColor?, showAsAction: Bool) { - self.id = id - self.title = title - self.order = order - self.icon = icon - self.iconColor = iconColor - self.showAsAction = showAsAction - if let icon = icon, let iconColor = iconColor { - self.icon = icon.tint(color: iconColor) - } - } - - public static func fromMap(map: [String:Any?]?) -> InAppBrowserMenuItem? { - guard let map = map else { - return nil - } - let id = map["id"] as! Int64 - let title = map["title"] as! String - let order = map["order"] as? Int64 - var icon = NSImage.fromMap(map: map["icon"] as? [String : Any?]) - if let data = map["icon"] as? FlutterStandardTypedData { - icon = NSImage(data: data.data) - } - var iconColor: NSColor? = nil - if let hexString = map["iconColor"] as? String { - iconColor = NSColor(hexString: hexString) - } - let showAsAction = map["showAsAction"] as! Bool - return InAppBrowserMenuItem(id: id, title: title, order: order, icon: icon, iconColor: iconColor, showAsAction: showAsAction) - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/InAppBrowserWindowType.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/InAppBrowserWindowType.swift deleted file mode 100644 index 9650e2b947..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/InAppBrowserWindowType.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// InAppBrowserWindowType.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/10/22. -// - -import Foundation - -public enum InAppBrowserWindowType: String { - case window = "WINDOW" - case child = "CHILD" - case tabbed = "TABBED" -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/JavaScriptHandlerFunctionData.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/JavaScriptHandlerFunctionData.swift deleted file mode 100644 index 5816ecffda..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/JavaScriptHandlerFunctionData.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// JavaScriptHandlerFunctionData.swift -// Pods -// -// Created by Lorenzo Pichilli on 27/10/24. -// - -import Foundation - -public class JavaScriptHandlerFunctionData: NSObject { - var args: String - var isMainFrame: Bool - var origin: String - var requestUrl: String - - public init(args: String, isMainFrame: Bool, origin: String, requestUrl: String) { - self.args = args - self.isMainFrame = isMainFrame - self.origin = origin - self.requestUrl = requestUrl - } - - public static func fromMap(map: [String:Any?]?) -> JavaScriptHandlerFunctionData? { - guard let map = map else { - return nil - } - - return JavaScriptHandlerFunctionData( - args: map["args"] as! String, - isMainFrame: map["isMainFrame"] as! Bool, - origin: map["origin"] as! String, - requestUrl: map["requestUrl"] as! String - ) - } - - public func toMap () -> [String:Any?] { - return [ - "args": args, - "isMainFrame": isMainFrame, - "origin": origin, - "requestUrl": requestUrl - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/JsAlertResponse.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/JsAlertResponse.swift deleted file mode 100644 index 3e6b3e7883..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/JsAlertResponse.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// JsAlertResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 06/05/22. -// - -import Foundation - -public class JsAlertResponse: NSObject { - var message: String - var confirmButtonTitle: String - var handledByClient: Bool - var action: Int? - - public init(message: String, confirmButtonTitle: String, handledByClient: Bool, action: Int? = nil) { - self.message = message - self.confirmButtonTitle = confirmButtonTitle - self.handledByClient = handledByClient - self.action = action - } - - public static func fromMap(map: [String:Any?]?) -> JsAlertResponse? { - guard let map = map else { - return nil - } - let message = map["message"] as! String - let confirmButtonTitle = map["confirmButtonTitle"] as! String - let handledByClient = map["handledByClient"] as! Bool - let action = map["action"] as? Int - return JsAlertResponse(message: message, confirmButtonTitle: confirmButtonTitle, handledByClient: handledByClient, action: action) - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/JsConfirmResponse.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/JsConfirmResponse.swift deleted file mode 100644 index 76bfbe20e3..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/JsConfirmResponse.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// JsConfirmResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation - -public class JsConfirmResponse: NSObject { - var message: String - var confirmButtonTitle: String - var cancelButtonTitle: String - var handledByClient: Bool - var action: Int? - - public init(message: String, confirmButtonTitle: String, cancelButtonTitle: String, handledByClient: Bool, action: Int? = nil) { - self.message = message - self.confirmButtonTitle = confirmButtonTitle - self.cancelButtonTitle = cancelButtonTitle - self.handledByClient = handledByClient - self.action = action - } - - public static func fromMap(map: [String:Any?]?) -> JsConfirmResponse? { - guard let map = map else { - return nil - } - let message = map["message"] as! String - let confirmButtonTitle = map["confirmButtonTitle"] as! String - let cancelButtonTitle = map["cancelButtonTitle"] as! String - let handledByClient = map["handledByClient"] as! Bool - let action = map["action"] as? Int - return JsConfirmResponse(message: message, confirmButtonTitle: confirmButtonTitle, cancelButtonTitle: cancelButtonTitle, handledByClient: handledByClient, action: action) - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/JsPromptResponse.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/JsPromptResponse.swift deleted file mode 100644 index 5c40b49279..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/JsPromptResponse.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// JsPromptResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation - -public class JsPromptResponse: NSObject { - var message: String - var defaultValue: String - var confirmButtonTitle: String - var cancelButtonTitle: String - var handledByClient: Bool - var value: String? - var action: Int? - - public init(message: String, defaultValue: String, confirmButtonTitle: String, cancelButtonTitle: String, handledByClient: Bool, value: String? = nil, action: Int? = nil) { - self.message = message - self.defaultValue = defaultValue - self.confirmButtonTitle = confirmButtonTitle - self.cancelButtonTitle = cancelButtonTitle - self.handledByClient = handledByClient - self.value = value - self.action = action - } - - public static func fromMap(map: [String:Any?]?) -> JsPromptResponse? { - guard let map = map else { - return nil - } - let message = map["message"] as! String - let defaultValue = map["defaultValue"] as! String - let confirmButtonTitle = map["confirmButtonTitle"] as! String - let cancelButtonTitle = map["cancelButtonTitle"] as! String - let handledByClient = map["handledByClient"] as! Bool - let value = map["value"] as? String - let action = map["action"] as? Int - return JsPromptResponse(message: message, defaultValue: defaultValue, confirmButtonTitle: confirmButtonTitle, cancelButtonTitle: cancelButtonTitle, - handledByClient: handledByClient, value: value, action: action) - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/MethodChannelResult.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/MethodChannelResult.swift deleted file mode 100644 index cba7eb241c..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/MethodChannelResult.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// MethodChannelResult.swift -// shared-apple -// -// Created by Lorenzo Pichilli on 17/10/22. -// - -import Foundation - -public protocol MethodChannelResult { - var success: (_ obj: Any?) -> Void { get set } - var error: (_ code: String, _ message: String?, _ details: Any?) -> Void { get set } - var notImplemented: () -> Void { get set } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/NSAttributedString.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/NSAttributedString.swift deleted file mode 100644 index d554c6c6aa..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/NSAttributedString.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// NSAttributedString.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 05/03/21. -// - -import Foundation -import AppKit - -extension NSAttributedString { - public static func fromMap(map: [String:Any?]?) -> NSAttributedString? { - guard let map = map, let string = map["string"] as? String else { - return nil - } - - var attributes: [NSAttributedString.Key : Any] = [:] - - if let backgroundColor = map["backgroundColor"] as? String { - attributes[.backgroundColor] = NSColor(hexString: backgroundColor) - } - if let baselineOffset = map["baselineOffset"] as? Double { - attributes[.baselineOffset] = baselineOffset - } - if let expansion = map["expansion"] as? Double { - attributes[.expansion] = expansion - } - if let foregroundColor = map["foregroundColor"] as? String { - attributes[.foregroundColor] = NSColor(hexString: foregroundColor) - } - if let kern = map["kern"] as? Double { - attributes[.kern] = kern - } - if let ligature = map["ligature"] as? Int64 { - attributes[.ligature] = ligature - } - if let obliqueness = map["obliqueness"] as? Double { - attributes[.obliqueness] = obliqueness - } - if let strikethroughColor = map["strikethroughColor"] as? String { - attributes[.strikethroughColor] = NSColor(hexString: strikethroughColor) - } - if let strikethroughStyle = map["strikethroughStyle"] as? Int64 { - attributes[.strikethroughStyle] = strikethroughStyle - } - if let strokeColor = map["strokeColor"] as? String { - attributes[.strokeColor] = NSColor(hexString: strokeColor) - } - if let strokeWidth = map["strokeWidth"] as? Double { - attributes[.strokeWidth] = strokeWidth - } - if let textEffect = map["textEffect"] as? String { - attributes[.textEffect] = textEffect - } - if let underlineColor = map["underlineColor"] as? String { - attributes[.underlineColor] = NSColor(hexString: underlineColor) - } - if let underlineStyle = map["underlineStyle"] as? Int64 { - attributes[.underlineStyle] = underlineStyle - } - - return NSAttributedString(string: string, attributes: attributes) - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/NSColor.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/NSColor.swift deleted file mode 100644 index 0596cd18ae..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/NSColor.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// NSColor.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import AppKit - -extension NSColor { - convenience init(hexString: String) { - let hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) - var int = UInt64() - Scanner(string: hex).scanHexInt64(&int) - let a, r, g, b: UInt64 - switch hex.count { - case 3: // RGB (12-bit) - (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) - case 6: // RGB (24-bit) - (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) - case 8: // ARGB (32-bit) - (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) - default: - (a, r, g, b) = (255, 0, 0, 0) - } - self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255) - } - - var hexString: String? { - guard let rgbColor = usingColorSpace(.sRGB) else { - return "#FFFFFF" - } - let red: CGFloat = rgbColor.redComponent - let green: CGFloat = rgbColor.greenComponent - let blue: CGFloat = rgbColor.blueComponent - let alpha: CGFloat = rgbColor.alphaComponent - - if alpha == 1.0 { - return String( - format: "#%02lX%02lX%02lX", - Int(red * 0xFF), - Int(green * 0xFF), - Int(blue * 0xFF) - ) - } - else { - return String( - format: "#%02lX%02lX%02lX%02lX", - Int(red * 0xFF), - Int(green * 0xFF), - Int(blue * 0xFF), - Int(alpha * 0xFF) - ) - } - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/NSEdgeInsets.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/NSEdgeInsets.swift deleted file mode 100644 index 68aadcd21d..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/NSEdgeInsets.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// UIEdgeInsets.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 11/05/22. -// - -import Foundation - -extension NSEdgeInsets { - public static func fromMap(map: [String: Double]) -> NSEdgeInsets { - return NSEdgeInsets.init(top: map["top"]!, left: map["left"]!, bottom: map["bottom"]!, right: map["right"]!) - } - - public func toMap () -> [String:Any?] { - return [ - "top": top, - "right": self.right, - "bottom": bottom, - "left": self.left - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/NSImage.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/NSImage.swift deleted file mode 100644 index 096a4ceab0..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/NSImage.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// NSImage.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 23/05/23. -// - -import Foundation -import FlutterMacOS - -extension NSImage { - public static func fromMap(map: [String:Any?]?) -> NSImage? { - guard let map = map else { - return nil - } - if let name = map["name"] as? String { - return NSImage(named: name) - } - if #available(macOS 11.0, *), let systemName = map["systemName"] as? String { - return NSImage(systemSymbolName: systemName, accessibilityDescription: nil) - } - if let data = map["data"] as? FlutterStandardTypedData { - return NSImage(data: data.data) - } - return nil - } - - func tint(color: NSColor) -> NSImage { - return NSImage(size: size, flipped: false) { (rect) -> Bool in - color.set() - rect.fill() - self.draw(in: rect, from: NSRect(origin: .zero, size: self.size), operation: .destinationIn, fraction: 1.0) - return true - } - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/NSPrinter.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/NSPrinter.swift deleted file mode 100644 index 0a41459346..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/NSPrinter.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// NSPrinter.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 17/10/22. -// - -import Foundation -import AppKit - -extension NSPrinter { - public func toMap () -> [String:Any?] { - return [ - "type": type.rawValue, - "languageLevel": languageLevel, - "name": name - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/PermissionRequest.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/PermissionRequest.swift deleted file mode 100644 index a286a3f32b..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/PermissionRequest.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// PermissionRequest.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 21/04/22. -// - -import Foundation -import WebKit - -public class PermissionRequest: NSObject { - var origin: String - var resources: [StringOrInt] - var frame: WKFrameInfo - - public init(origin: String, resources: [StringOrInt], frame: WKFrameInfo) { - self.origin = origin - self.resources = resources - self.frame = frame - } - - public func toMap () -> [String:Any?] { - return [ - "origin": origin, - "resources": resources, - "frame": frame.toMap() - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/PermissionResponse.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/PermissionResponse.swift deleted file mode 100644 index 171817bbc3..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/PermissionResponse.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// PermissionResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation - -public class PermissionResponse: NSObject { - var resources: [Any] - var action: Int? - - public init(resources: [Any], action: Int? = nil) { - self.resources = resources - self.action = action - } - - public static func fromMap(map: [String:Any?]?) -> PermissionResponse? { - guard let map = map else { - return nil - } - let resources = map["resources"] as! [Any] - let action = map["action"] as? Int - return PermissionResponse(resources: resources, action: action) - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/PluginScript.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/PluginScript.swift deleted file mode 100644 index 096f5d8832..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/PluginScript.swift +++ /dev/null @@ -1,117 +0,0 @@ -// -// PluginScript.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 17/02/21. -// - -import Foundation -import WebKit - -public class PluginScript: UserScript { - var requiredInAllContentWorlds = false - var messageHandlerNames: [String] = [] - - public override init(source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool) { - super.init(source: source, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly) - } - - public init(groupName: String, source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, allowedOriginRules: [String]?, requiredInAllContentWorlds: Bool = false, messageHandlerNames: [String] = []) { - super.init(groupName: groupName, source: source, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly, allowedOriginRules: allowedOriginRules) - self.requiredInAllContentWorlds = requiredInAllContentWorlds - self.messageHandlerNames = messageHandlerNames - } - - @available(macOS 11.0, *) - public override init(source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, in contentWorld: WKContentWorld) { - super.init(source: source, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly, in: contentWorld) - self.contentWorld = contentWorld - } - - @available(macOS 11.0, *) - public init(source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, in contentWorld: WKContentWorld, requiredInAllContentWorlds: Bool = false, messageHandlerNames: [String] = []) { - super.init(source: source, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly, in: contentWorld) - self.requiredInAllContentWorlds = requiredInAllContentWorlds - self.messageHandlerNames = messageHandlerNames - } - - @available(macOS 11.0, *) - public init(groupName: String, source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, in contentWorld: WKContentWorld, - allowedOriginRules: [String]?, requiredInAllContentWorlds: Bool = false, messageHandlerNames: [String] = []) { - super.init(groupName: groupName, source: source, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly, in: contentWorld, allowedOriginRules: allowedOriginRules) - self.requiredInAllContentWorlds = requiredInAllContentWorlds - self.messageHandlerNames = messageHandlerNames - } - - public func copyAndSet(groupName: String? = nil, - source: String? = nil, - injectionTime: WKUserScriptInjectionTime? = nil, - forMainFrameOnly: Bool? = nil, - requiredInAllContentWorlds: Bool? = nil, - allowedOriginRules: [String]? = nil, - messageHandlerNames: [String]? = nil) -> PluginScript { - if #available(macOS 11.0, *) { - return PluginScript( - groupName: groupName ?? self.groupName!, - source: source ?? self.source, - injectionTime: injectionTime ?? self.injectionTime, - forMainFrameOnly: forMainFrameOnly ?? self.isForMainFrameOnly, - in: self.contentWorld, - allowedOriginRules: allowedOriginRules ?? self.allowedOriginRules, - requiredInAllContentWorlds: requiredInAllContentWorlds ?? self.requiredInAllContentWorlds, - messageHandlerNames: messageHandlerNames ?? self.messageHandlerNames - ) - } - return PluginScript( - groupName: groupName ?? self.groupName!, - source: source ?? self.source, - injectionTime: injectionTime ?? self.injectionTime, - forMainFrameOnly: forMainFrameOnly ?? self.isForMainFrameOnly, - allowedOriginRules: allowedOriginRules ?? self.allowedOriginRules, - requiredInAllContentWorlds: requiredInAllContentWorlds ?? self.requiredInAllContentWorlds, - messageHandlerNames: messageHandlerNames ?? self.messageHandlerNames - ) - } - - @available(macOS 11.0, *) - public func copyAndSet(groupName: String? = nil, - source: String? = nil, - injectionTime: WKUserScriptInjectionTime? = nil, - forMainFrameOnly: Bool? = nil, - contentWorld: WKContentWorld? = nil, - allowedOriginRules: [String]? = nil, - requiredInAllContentWorlds: Bool? = nil, - messageHandlerNames: [String]? = nil) -> PluginScript { - return PluginScript( - groupName: groupName ?? self.groupName!, - source: source ?? self.source, - injectionTime: injectionTime ?? self.injectionTime, - forMainFrameOnly: forMainFrameOnly ?? self.isForMainFrameOnly, - in: contentWorld ?? self.contentWorld, - allowedOriginRules: allowedOriginRules ?? self.allowedOriginRules, - requiredInAllContentWorlds: requiredInAllContentWorlds ?? self.requiredInAllContentWorlds, - messageHandlerNames: messageHandlerNames ?? self.messageHandlerNames - ) - } - - static func == (lhs: PluginScript, rhs: PluginScript) -> Bool { - if #available(macOS 11.0, *) { - return lhs.groupName == rhs.groupName && - lhs.source == rhs.source && - lhs.injectionTime == rhs.injectionTime && - lhs.isForMainFrameOnly == rhs.isForMainFrameOnly && - lhs.contentWorld == rhs.contentWorld && - lhs.allowedOriginRules == rhs.allowedOriginRules && - lhs.requiredInAllContentWorlds == rhs.requiredInAllContentWorlds && - lhs.messageHandlerNames == rhs.messageHandlerNames - } else { - return lhs.groupName == rhs.groupName && - lhs.source == rhs.source && - lhs.injectionTime == rhs.injectionTime && - lhs.isForMainFrameOnly == rhs.isForMainFrameOnly && - lhs.allowedOriginRules == rhs.allowedOriginRules && - lhs.requiredInAllContentWorlds == rhs.requiredInAllContentWorlds && - lhs.messageHandlerNames == rhs.messageHandlerNames - } - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/SecCertificate.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/SecCertificate.swift deleted file mode 100644 index e7292f2272..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/SecCertificate.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// SecCertificate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation - -extension SecCertificate { - var data: Data { - let serverCertificateCFData = SecCertificateCopyData(self) - return serverCertificateCFData as Data - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/ServerTrustAuthResponse.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/ServerTrustAuthResponse.swift deleted file mode 100644 index 2a9980573f..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/ServerTrustAuthResponse.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// ServerTrustAuthResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 07/05/22. -// - -import Foundation - -public class ServerTrustAuthResponse: NSObject { - var action: Int? - - public init(action: Int? = nil) { - self.action = action - } - - public static func fromMap(map: [String:Any?]?) -> ServerTrustAuthResponse? { - guard let map = map else { - return nil - } - let action = map["action"] as? Int - return ServerTrustAuthResponse(action: action) - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/ServerTrustChallenge.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/ServerTrustChallenge.swift deleted file mode 100644 index 190c831b1d..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/ServerTrustChallenge.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// ServerTrustChallenge.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 15/02/21. -// - -import Foundation - -public class ServerTrustChallenge: NSObject { - var protectionSpace: URLProtectionSpace! - - public init(fromChallenge: URLAuthenticationChallenge) { - protectionSpace = fromChallenge.protectionSpace - } - - public func toMap () -> [String:Any?] { - return [ - "protectionSpace": protectionSpace.toMap() - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/Size2D.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/Size2D.swift deleted file mode 100644 index de13ffc21c..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/Size2D.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// Size.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 26/03/21. -// - -import Foundation - -public class Size2D: NSObject { - var width: Double - var height: Double - - public init(width: Double, height: Double) { - self.width = width - self.height = height - } - - public static func fromMap(map: [String:Any?]?) -> Size2D? { - guard let map = map else { - return nil - } - return Size2D( - width: map["width"] as? Double ?? -1.0, - height: map["height"] as? Double ?? -1.0 - ) - } - - public func toMap() -> [String:Any?] { - return [ - "width": width, - "height": height - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/SslCertificate.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/SslCertificate.swift deleted file mode 100644 index 6b9d9a17fd..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/SslCertificate.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// SslCertificate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 15/02/21. -// - -import Foundation - -public class SslCertificate: NSObject { - var x509Certificate: Data - var issuedBy: Any? - var issuedTo: Any? - var validNotAfterDate: Any? - var validNotBeforeDate: Any? - - public init(x509Certificate: Data) { - self.x509Certificate = x509Certificate - } - - public func toMap () -> [String:Any?] { - return [ - "x509Certificate": x509Certificate, - "issuedBy": issuedBy, - "issuedTo": issuedTo, - "validNotAfterDate": validNotAfterDate, - "validNotBeforeDate": validNotBeforeDate - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/SslError.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/SslError.swift deleted file mode 100644 index 58e3cf94af..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/SslError.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// SslError.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 15/02/21. -// - -import Foundation - -public class SslError: NSObject { - var errorType: SecTrustResultType? - var message: String? - - public init(errorType: SecTrustResultType?) { - self.errorType = errorType - - var sslErrorMessage: String? = nil - switch errorType { - case .deny: - sslErrorMessage = "Indicates a user-configured deny; do not proceed." - break - case .fatalTrustFailure: - sslErrorMessage = "Indicates a trust failure which cannot be overridden by the user." - break - case .invalid: - sslErrorMessage = "Indicates an invalid setting or result." - break - case .otherError: - sslErrorMessage = "Indicates a failure other than that of trust evaluation." - break - case .recoverableTrustFailure: - sslErrorMessage = "Indicates a trust policy failure which can be overridden by the user." - break - case .unspecified: - sslErrorMessage = "Indicates the evaluation succeeded and the certificate is implicitly trusted, but user intent was not explicitly specified." - break - default: - sslErrorMessage = nil - } - - self.message = sslErrorMessage - } - - public func toMap () -> [String:Any?] { - return [ - "code": errorType?.rawValue, - "message": message - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/StringOrInt.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/StringOrInt.swift deleted file mode 100644 index f7cd40c734..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/StringOrInt.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// StringOrInt.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 21/04/22. -// - -import Foundation - -public protocol StringOrInt { } - -extension Int: StringOrInt { } -extension String: StringOrInt { } diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/URLAuthenticationChallenge.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/URLAuthenticationChallenge.swift deleted file mode 100644 index 39b21fcec2..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/URLAuthenticationChallenge.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// URLAuthenticationChallenge.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation - -extension URLAuthenticationChallenge { - public func toMap () -> [String:Any?] { - return [ - "protectionSpace": protectionSpace.toMap(), - "previousFailureCount": previousFailureCount, - "failureResponse": failureResponse?.toMap(), - "error": error?.localizedDescription, - "proposedCredential": proposedCredential?.toMap(), - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/URLCredential.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/URLCredential.swift deleted file mode 100644 index 469f1e15a5..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/URLCredential.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// URLCredential.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation - -extension URLCredential { - public func toMap () -> [String:Any?] { - var x509Certificates: [Data] = [] - // certificates could be nil!!! - if certificates != nil { - for certificate in certificates { - x509Certificates.append((certificate as! SecCertificate).data) - } - } - return [ - "password": password, - "username": user, - "certificates": x509Certificates, - "persistence": persistence.rawValue - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/URLProtectionSpace.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/URLProtectionSpace.swift deleted file mode 100644 index 3d6b9022c7..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/URLProtectionSpace.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// URLProtectionSpace.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation - -extension URLProtectionSpace { - - var x509Certificate: Data? { - guard let serverTrust = serverTrust else { - return nil - } - - var secResult = SecTrustResultType.invalid - let secTrustEvaluateStatus = SecTrustEvaluate(serverTrust, &secResult); - - if secTrustEvaluateStatus == errSecSuccess, let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) { - return serverCertificate.data - } - return nil - } - - var sslCertificate: SslCertificate? { - var sslCertificate: SslCertificate? = nil - if let x509Certificate = x509Certificate { - sslCertificate = SslCertificate(x509Certificate: x509Certificate) - } - return sslCertificate - } - - var sslError: SslError? { - guard let serverTrust = serverTrust else { - return nil - } - - var secResult = SecTrustResultType.invalid - SecTrustEvaluate(serverTrust, &secResult); - - guard let sslErrorType = secResult != SecTrustResultType.proceed ? secResult : nil else { - return nil - } - - return SslError(errorType: sslErrorType) - } - - public func toMap () -> [String:Any?] { - return [ - "host": host, - "protocol": self.protocol, - "realm": realm, - "port": port, - "sslCertificate": sslCertificate?.toMap(), - "sslError": sslError?.toMap(), - "authenticationMethod": authenticationMethod, - "distinguishedNames": distinguishedNames, - "receivesCredentialSecurely": receivesCredentialSecurely, - "proxyType": proxyType - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/URLRequest.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/URLRequest.swift deleted file mode 100644 index 54a251d2da..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/URLRequest.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// URLRequest.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import FlutterMacOS - -extension URLRequest { - public init(fromPluginMap: [String:Any?]) { - if let urlString = fromPluginMap["url"] as? String, let url = URL(string: urlString) { - self.init(url: url) - } else { - self.init(url: URL(string: "about:blank")!) - } - - if let method = fromPluginMap["method"] as? String { - httpMethod = method - } - if let body = fromPluginMap["body"] as? FlutterStandardTypedData { - httpBody = body.data - } - if let headers = fromPluginMap["headers"] as? [String:String] { - for (key, value) in headers { - setValue(value, forHTTPHeaderField: key) - } - } - if let _allowsCellularAccess = fromPluginMap["allowsCellularAccess"] as? Bool { - allowsCellularAccess = _allowsCellularAccess - } - if #available(macOS 10.15, *), let _allowsConstrainedNetworkAccess = fromPluginMap["allowsConstrainedNetworkAccess"] as? Bool { - allowsConstrainedNetworkAccess = _allowsConstrainedNetworkAccess - } - if #available(macOS 10.15, *), let _allowsExpensiveNetworkAccess = fromPluginMap["allowsExpensiveNetworkAccess"] as? Bool { - allowsExpensiveNetworkAccess = _allowsExpensiveNetworkAccess - } - if let _cachePolicy = fromPluginMap["cachePolicy"] as? Int { - cachePolicy = CachePolicy.init(rawValue: UInt(_cachePolicy)) ?? .useProtocolCachePolicy - } - if let _httpShouldHandleCookies = fromPluginMap["httpShouldHandleCookies"] as? Bool { - httpShouldHandleCookies = _httpShouldHandleCookies - } - if let _httpShouldUsePipelining = fromPluginMap["httpShouldUsePipelining"] as? Bool { - httpShouldUsePipelining = _httpShouldUsePipelining - } - if let _networkServiceType = fromPluginMap["networkServiceType"] as? Int { - networkServiceType = NetworkServiceType.init(rawValue: UInt(_networkServiceType)) ?? .default - } - if let _timeoutInterval = fromPluginMap["timeoutInterval"] as? Double { - timeoutInterval = _timeoutInterval - } - if let _mainDocumentURL = fromPluginMap["mainDocumentURL"] as? String { - mainDocumentURL = URL(string: _mainDocumentURL)! - } - if #available(macOS 11.3, *), let _assumesHTTP3Capable = fromPluginMap["assumesHTTP3Capable"] as? Bool { - assumesHTTP3Capable = _assumesHTTP3Capable - } - if #available(macOS 12.0, *), let attributionRawValue = fromPluginMap["attribution"] as? UInt, - let _attribution = URLRequest.Attribution(rawValue: attributionRawValue) { - attribution = _attribution - } - } - - public func toMap () -> [String:Any?] { - var _allowsConstrainedNetworkAccess: Bool? = nil - var _allowsExpensiveNetworkAccess: Bool? = nil - if #available(macOS 10.15, *) { - _allowsConstrainedNetworkAccess = allowsConstrainedNetworkAccess - _allowsExpensiveNetworkAccess = allowsExpensiveNetworkAccess - } - var _assumesHTTP3Capable: Bool? = nil - if #available(macOS 11.3, *) { - _assumesHTTP3Capable = assumesHTTP3Capable - } - var _attribution: UInt? = nil - if #available(macOS 12.0, *) { - _attribution = attribution.rawValue - } - return [ - "url": url?.absoluteString, - "method": httpMethod, - "headers": allHTTPHeaderFields, - "body": httpBody.map(FlutterStandardTypedData.init(bytes:)), - "allowsCellularAccess": allowsCellularAccess, - "allowsConstrainedNetworkAccess": _allowsConstrainedNetworkAccess, - "allowsExpensiveNetworkAccess": _allowsExpensiveNetworkAccess, - "cachePolicy": cachePolicy.rawValue, - "httpShouldHandleCookies": httpShouldHandleCookies, - "httpShouldUsePipelining": httpShouldUsePipelining, - "networkServiceType": networkServiceType.rawValue, - "timeoutInterval": timeoutInterval, - "mainDocumentURL": mainDocumentURL?.absoluteString, - "assumesHTTP3Capable": _assumesHTTP3Capable, - "attribution": _attribution - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/URLResponse.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/URLResponse.swift deleted file mode 100644 index 0a6a483547..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/URLResponse.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// URLResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation - -extension URLResponse { - public convenience init?(fromPluginMap: [String:Any?]) { - let url = URL(string: fromPluginMap["url"] as? String ?? "about:blank")! - let mimeType = fromPluginMap["mimeType"] as? String - let expectedContentLength = fromPluginMap["expectedContentLength"] as? Int64 ?? 0 - let textEncodingName = fromPluginMap["textEncodingName"] as? String - self.init(url: url, mimeType: mimeType, expectedContentLength: Int(expectedContentLength), textEncodingName: textEncodingName) - } - - public func toMap () -> [String:Any?] { - let httpResponse: HTTPURLResponse? = self as? HTTPURLResponse - return [ - "expectedContentLength": expectedContentLength, - "mimeType": mimeType, - "suggestedFilename": suggestedFilename, - "textEncodingName": textEncodingName, - "url": url?.absoluteString, - "headers": httpResponse?.allHeaderFields, - "statusCode": httpResponse?.statusCode - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/UserScript.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/UserScript.swift deleted file mode 100644 index cd8559a1a1..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/UserScript.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// InAppWebViewUserScript.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation -import WebKit - -public class UserScript: WKUserScript { - var groupName: String? - var allowedOriginRules: [String]? - - private var contentWorldWrapper: Any? - @available(macOS 11.0, *) - var contentWorld: WKContentWorld { - get { - if let value = contentWorldWrapper as? WKContentWorld { - return value - } - return .page - } - set { contentWorldWrapper = newValue } - } - - public override init(source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool) { - super.init(source: source, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly) - } - - public init(groupName: String?, source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, allowedOriginRules: [String]?) { - super.init(source: UserScript.wrapSourceCodeAddChecks(source: source, allowedOriginRules: allowedOriginRules), injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly) - self.groupName = groupName - self.allowedOriginRules = allowedOriginRules - } - - @available(macOS 11.0, *) - public override init(source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, in contentWorld: WKContentWorld) { - super.init(source: source, injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly, in: contentWorld) - self.contentWorld = contentWorld - } - - @available(macOS 11.0, *) - public init(groupName: String?, source: String, injectionTime: WKUserScriptInjectionTime, forMainFrameOnly: Bool, in contentWorld: WKContentWorld, allowedOriginRules: [String]?) { - super.init(source: UserScript.wrapSourceCodeAddChecks(source: source, allowedOriginRules: allowedOriginRules), injectionTime: injectionTime, forMainFrameOnly: forMainFrameOnly, in: contentWorld) - self.groupName = groupName - self.contentWorld = contentWorld - self.allowedOriginRules = allowedOriginRules - } - - static private func wrapSourceCodeAddChecks(source: String, allowedOriginRules: [String]?) -> String { - var ifStatement = "if (" - if let allowedOriginRules = allowedOriginRules, !allowedOriginRules.contains("*") { - if allowedOriginRules.isEmpty { - // return empty source string if allowedOriginRules is an empty list. - // an empty list means that this UserScript is not allowed for any origin. - return "" - } - var jsRegExpArray = "[" - for allowedOriginRule in allowedOriginRules { - if jsRegExpArray.count > 1 { - jsRegExpArray += "," - } - jsRegExpArray += "new RegExp('\(allowedOriginRule.replacingOccurrences(of: "\'", with: "\\'"))')" - } - if jsRegExpArray.count > 1 { - jsRegExpArray += "]" - ifStatement += "\(jsRegExpArray).some(function(rx) { return rx.test(window.location.origin); })" - } - } - return ifStatement.count > 4 ? "\(ifStatement)) { \(source) }" : source - } - - public static func fromMap(map: [String:Any?]?, windowId: Int64?) -> UserScript? { - guard let map = map else { - return nil - } - - let contentWorldMap = map["contentWorld"] as? [String:Any?] - if #available(macOS 11.0, *), let contentWorldMap = contentWorldMap { - let contentWorld = WKContentWorld.fromMap(map: contentWorldMap, windowId: windowId)! - return UserScript( - groupName: map["groupName"] as? String, - source: map["source"] as! String, - injectionTime: WKUserScriptInjectionTime.init(rawValue: map["injectionTime"] as! Int) ?? .atDocumentStart, - forMainFrameOnly: map["forMainFrameOnly"] as! Bool, - in: contentWorld, - allowedOriginRules: map["allowedOriginRules"] as? [String] - ) - } - return UserScript( - groupName: map["groupName"] as? String, - source: map["source"] as! String, - injectionTime: WKUserScriptInjectionTime.init(rawValue: map["injectionTime"] as! Int) ?? .atDocumentStart, - forMainFrameOnly: map["forMainFrameOnly"] as! Bool, - allowedOriginRules: map["allowedOriginRules"] as? [String] - ) - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKContentWorld.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKContentWorld.swift deleted file mode 100644 index f94cc81a0c..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKContentWorld.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// WKContentWorld.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import WebKit - -@available(macOS 11.0, *) -extension WKContentWorld { - // Workaround to create stored properties in an extension: - // https://valv0.medium.com/computed-properties-and-extensions-a-pure-swift-approach-64733768112c - - private static var _windowId = [String: Int64?]() - - var windowId: Int64? { - get { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - return WKContentWorld._windowId[tmpAddress] ?? nil - } - set(newValue) { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - WKContentWorld._windowId[tmpAddress] = newValue - } - } - - public static func fromMap(map: [String:Any?]?, windowId: Int64?) -> WKContentWorld? { - guard let map = map else { - return nil - } - var name = map["name"] as! String - name = windowId != nil && name != "page" ? - WKUserContentController.WINDOW_ID_PREFIX + String(windowId!) + "-" + name : - name - let contentWorld = Util.getContentWorld(name: name) - contentWorld.windowId = name != "page" ? windowId : nil - return contentWorld - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKFrameInfo.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKFrameInfo.swift deleted file mode 100644 index b5a9620711..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKFrameInfo.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// WKFrameInfo.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import WebKit - -extension WKFrameInfo { - - public func toMap () -> [String:Any?] { - var securityOrigin: [String:Any?]? = nil - securityOrigin = self.securityOrigin.toMap() - // fix: self.request throws EXC_BREAKPOINT when coming from WKNavigationAction.sourceFrame - let request: URLRequest? = self.value(forKey: "request") as? URLRequest - return [ - "isMainFrame": isMainFrame, - "request": request?.toMap(), - "securityOrigin": securityOrigin - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKNavigationAction.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKNavigationAction.swift deleted file mode 100644 index f93080f731..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKNavigationAction.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// WKNavigationAction.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import WebKit - -extension WKNavigationAction { - public func toMap () -> [String:Any?] { - var shouldPerformDownload: Bool? = nil - if #available(macOS 11.3, *) { - shouldPerformDownload = self.shouldPerformDownload - } - return [ - "request": request.toMap(), - "isForMainFrame": targetFrame?.isMainFrame ?? false, - "hasGesture": nil, - "isRedirect": nil, - "navigationType": navigationType.rawValue, - "sourceFrame": sourceFrame.toMap(), - "targetFrame": targetFrame?.toMap(), - "shouldPerformDownload": shouldPerformDownload - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKNavigationResponse.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKNavigationResponse.swift deleted file mode 100644 index 0e6852919b..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKNavigationResponse.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// WKNavigationResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import WebKit - -extension WKNavigationResponse { - public func toMap () -> [String:Any?] { - return [ - "response": response.toMap(), - "isForMainFrame": isForMainFrame, - "canShowMIMEType": canShowMIMEType, - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKSecurityOrigin.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKSecurityOrigin.swift deleted file mode 100644 index a7e8c71439..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKSecurityOrigin.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// WKSecurityOrigin.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import WebKit - -@available(iOS 9.0, *) -extension WKSecurityOrigin { - public func toMap () -> [String:Any?] { - return [ - "host": host, - "port": port, - "protocol": self.protocol - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKUserContentController.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKUserContentController.swift deleted file mode 100644 index 3e65e35907..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKUserContentController.swift +++ /dev/null @@ -1,404 +0,0 @@ -// -// UserContentController.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 17/02/21. -// - -import Foundation -import WebKit -#if SWIFT_PACKAGE -import Collections -#else -import OrderedSet -#endif - -extension WKUserContentController { - static var WINDOW_ID_PREFIX = "WINDOW-ID-" - - // Workaround to create stored properties in an extension: - // https://valv0.medium.com/computed-properties-and-extensions-a-pure-swift-approach-64733768112c - - @available(macOS 11.0, *) - private static var _contentWorlds = [String: Set]() - @available(macOS 11.0, *) - var contentWorlds: Set { - get { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - return WKUserContentController._contentWorlds[tmpAddress] ?? [] - } - set(newValue) { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - WKUserContentController._contentWorlds[tmpAddress] = newValue - } - } - - private static var _userOnlyScripts = [String: [WKUserScriptInjectionTime:OrderedSet]]() - var userOnlyScripts: [WKUserScriptInjectionTime:OrderedSet] { - get { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - return WKUserContentController._userOnlyScripts[tmpAddress] ?? [:] - } - set(newValue) { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - WKUserContentController._userOnlyScripts[tmpAddress] = newValue - } - } - - private static var _pluginScripts = [String: [WKUserScriptInjectionTime:OrderedSet]]() - var pluginScripts: [WKUserScriptInjectionTime:OrderedSet] { - get { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - return WKUserContentController._pluginScripts[tmpAddress] ?? [:] - } - set(newValue) { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - WKUserContentController._pluginScripts[tmpAddress] = newValue - } - } - - public func initialize () { - if #available(macOS 11.0, *) { - contentWorlds = Set([WKContentWorld.page]) - } - #if SWIFT_PACKAGE - pluginScripts = [ - .atDocumentStart: [], - .atDocumentEnd: [], - ] - userOnlyScripts = [ - .atDocumentStart: [], - .atDocumentEnd: [], - ] - #else - pluginScripts = [ - .atDocumentStart: OrderedSet(sequence: []), - .atDocumentEnd: OrderedSet(sequence: []), - ] - userOnlyScripts = [ - .atDocumentStart: OrderedSet(sequence: []), - .atDocumentEnd: OrderedSet(sequence: []), - ] - #endif - } - - public func dispose (windowId: Int64?) { - if windowId == nil { - let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) - if #available(macOS 11.0, *) { - contentWorlds.removeAll() - WKUserContentController._contentWorlds.removeValue(forKey: tmpAddress) - } - pluginScripts.removeAll() - WKUserContentController._pluginScripts.removeValue(forKey: tmpAddress) - userOnlyScripts.removeAll() - WKUserContentController._userOnlyScripts.removeValue(forKey: tmpAddress) - } - else if #available(macOS 11.0, *), let windowId = windowId { - let contentWorldsToRemove = contentWorlds.filter({ $0.windowId == windowId }) - for contentWorld in contentWorldsToRemove { - contentWorlds.remove(contentWorld) - removeAllScriptMessageHandlers(from: contentWorld) - } - } - } - - public func sync(scriptMessageHandler: WKScriptMessageHandler) { - let pluginScriptsList = pluginScripts.compactMap({ $0.value }).joined() - for pluginScript in pluginScriptsList { - if !containsPluginScript(pluginScript: pluginScript) { - addUserScript(pluginScript) - for messageHandlerName in pluginScript.messageHandlerNames { - removeScriptMessageHandler(forName: messageHandlerName) - add(scriptMessageHandler, name: messageHandlerName) - } - } - if #available(macOS 11.0, *), pluginScript.requiredInAllContentWorlds { - for contentWorld in contentWorlds { - if !containsPluginScript(pluginScript: pluginScript, in: contentWorld) { - let pluginScriptWithContentWorld = pluginScript.copyAndSet(contentWorld: contentWorld) - addUserScript(pluginScriptWithContentWorld) - for messageHandlerName in pluginScriptWithContentWorld.messageHandlerNames { - removeScriptMessageHandler(forName: messageHandlerName, contentWorld: contentWorld) - add(scriptMessageHandler, contentWorld: contentWorld, name: messageHandlerName) - } - } - } - } - } - - let userOnlyScriptsList = userOnlyScripts.compactMap({ $0.value }).joined() - for userOnlyScript in userOnlyScriptsList { - if !userScripts.contains(userOnlyScript) { - addUserScript(userOnlyScript) - } - } - } - - public func addUserOnlyScript(_ userOnlyScript: UserScript) { - if #available(macOS 11.0, *) { - contentWorlds.insert(userOnlyScript.contentWorld) - } - userOnlyScripts[userOnlyScript.injectionTime]!.append(userOnlyScript) - } - - public func addUserOnlyScripts(_ userOnlyScripts: [UserScript]) { - for userOnlyScript in userOnlyScripts { - addUserOnlyScript(userOnlyScript) - } - } - - public func addPluginScript(_ pluginScript: PluginScript) { - if #available(macOS 11.0, *) { - contentWorlds.insert(pluginScript.contentWorld) - } - pluginScripts[pluginScript.injectionTime]!.append(pluginScript) - } - - public func addPluginScripts(_ pluginScripts: [PluginScript]) { - for pluginScript in pluginScripts { - addPluginScript(pluginScript) - } - } - - public func getPluginScriptsRequiredInAllContentWorlds() -> [PluginScript] { - return pluginScripts.compactMap({ $0.value }) - .joined() - .filter({ $0.injectionTime == .atDocumentStart && $0.requiredInAllContentWorlds }) - } - - @available(macOS 11.0, *) - public func generateCodeForScriptEvaluation(scriptMessageHandler: WKScriptMessageHandler, source: String, contentWorld: WKContentWorld) -> String { - let (inserted, _) = contentWorlds.insert(contentWorld) - if inserted { - var generatedCode = "" - let pluginScriptsRequired = getPluginScriptsRequiredInAllContentWorlds() - for pluginScript in pluginScriptsRequired { - generatedCode += pluginScript.source + "\n" - for messageHandlerName in pluginScript.messageHandlerNames { - removeScriptMessageHandler(forName: messageHandlerName, contentWorld: contentWorld) - add(scriptMessageHandler, contentWorld: contentWorld, name: messageHandlerName) - } - } - if let windowId = contentWorld.windowId { - generatedCode += "\(WindowIdJS.WINDOW_ID_VARIABLE_JS_SOURCE()) = \(String(windowId));\n" - } - return generatedCode + "\n" + source - } - return source - } - - public func removeUserOnlyScript(_ userOnlyScript: UserScript) { - userOnlyScripts[userOnlyScript.injectionTime]!.remove(userOnlyScript) - removeUserScript(scriptToRemove: userOnlyScript) - } - - public func removeUserOnlyScript(at index: Int, injectionTime: WKUserScriptInjectionTime) { - let scriptToRemove = userOnlyScripts[injectionTime]![index] - #if SWIFT_PACKAGE - userOnlyScripts[injectionTime]!.remove(at: index) - #else - userOnlyScripts[injectionTime]!.removeObject(at: index) - #endif - removeUserScript(scriptToRemove: scriptToRemove) - } - - public func removeAllUserOnlyScripts() { - let allUserOnlyScripts = Array(userOnlyScripts.compactMap({ $0.value }).joined()) - - #if SWIFT_PACKAGE - userOnlyScripts[.atDocumentStart]!.removeAll() - userOnlyScripts[.atDocumentEnd]!.removeAll() - #else - userOnlyScripts[.atDocumentStart]!.removeAllObjects() - userOnlyScripts[.atDocumentEnd]!.removeAllObjects() - #endif - - removeUserScripts(scriptsToRemove: allUserOnlyScripts) - } - - public func removePluginScript(_ pluginScript: PluginScript) { - pluginScripts[pluginScript.injectionTime]!.remove(pluginScript) - for messageHandlerName in pluginScript.messageHandlerNames { - removeScriptMessageHandler(forName: messageHandlerName) - if #available(macOS 11.0, *) { - for contentWorld in contentWorlds { - removeScriptMessageHandler(forName: messageHandlerName, contentWorld: contentWorld) - } - } - } - removeUserScript(scriptToRemove: pluginScript) - } - - public func removeAllPluginScripts() { - let allPluginScripts = Array(pluginScripts.compactMap({ $0.value }).joined()) - - #if SWIFT_PACKAGE - pluginScripts[.atDocumentStart]!.removeAll() - pluginScripts[.atDocumentEnd]!.removeAll() - #else - pluginScripts[.atDocumentStart]!.removeAllObjects() - pluginScripts[.atDocumentEnd]!.removeAllObjects() - #endif - - removeUserScripts(scriptsToRemove: allPluginScripts) - } - - public func removeAllPluginScriptMessageHandlers() { - let allPluginScripts = pluginScripts.compactMap({ $0.value }).joined() - for pluginScript in allPluginScripts { - for messageHandlerName in pluginScript.messageHandlerNames { - removeScriptMessageHandler(forName: messageHandlerName) - } - } - if #available(macOS 11.0, *) { - removeAllScriptMessageHandlers() - for contentWorld in contentWorlds { - removeAllScriptMessageHandlers(from: contentWorld) - } - } - } - - @available(macOS 11.0, *) - public func resetContentWorlds(windowId: Int64?) { - let allUserOnlyScripts = userOnlyScripts.compactMap({ $0.value }).joined() - let contentWorldsFiltered = contentWorlds.filter({ $0.windowId == windowId && $0 != WKContentWorld.page }) - for contentWorld in contentWorldsFiltered { - var found = false - for script in allUserOnlyScripts { - if script.contentWorld == contentWorld { - found = true - break - } - } - if !found { - contentWorlds.remove(contentWorld) - } - } - } - - private func removeUserScript(scriptToRemove: WKUserScript, shouldAddPreviousScripts: Bool = true) -> Void { - // there isn't a way to remove a specific user script using WKUserContentController, - // so we remove all the user scripts and, then, we add them again without the one that has been removed - let userScripts = useCopyOfUserScripts() - - var userScriptsUpdated: [WKUserScript] = [] - for script in userScripts { - if script != scriptToRemove { - userScriptsUpdated.append(script) - } - } - - removeAllUserScripts() - - if shouldAddPreviousScripts { - for script in userScriptsUpdated { - addUserScript(script) - } - } - } - - private func removeUserScripts(scriptsToRemove: [WKUserScript], shouldAddPreviousScripts: Bool = true) -> Void { - // there isn't a way to remove a specific user script using WKUserContentController, - // so we remove all the user scripts and, then, we add them again without the one that has been removed - let userScripts = useCopyOfUserScripts() - - var userScriptsUpdated: [WKUserScript] = [] - for script in userScripts { - if !scriptsToRemove.contains(script) { - userScriptsUpdated.append(script) - } - } - - removeAllUserScripts() - - if shouldAddPreviousScripts { - for script in userScriptsUpdated { - addUserScript(script) - } - } - } - - public func removeUserOnlyScripts(with groupName: String, shouldAddPreviousScripts: Bool = true) -> Void { - let allUserOnlyScripts = userOnlyScripts.compactMap({ $0.value }).joined() - var scriptsToRemove: [UserScript] = [] - for script in allUserOnlyScripts { - if let scriptName = script.groupName, scriptName == groupName { - scriptsToRemove.append(script) - userOnlyScripts[script.injectionTime]!.remove(script) - } - } - removeUserScripts(scriptsToRemove: scriptsToRemove, shouldAddPreviousScripts: shouldAddPreviousScripts) - } - - public func removePluginScripts(with groupName: String, shouldAddPreviousScripts: Bool = true) -> Void { - let allPluginScripts = pluginScripts.compactMap({ $0.value }).joined() - var scriptsToRemove: [PluginScript] = [] - for script in allPluginScripts { - if let scriptName = script.groupName, scriptName == groupName { - scriptsToRemove.append(script) - pluginScripts[script.injectionTime]!.remove(script) - } - } - removeUserScripts(scriptsToRemove: scriptsToRemove, shouldAddPreviousScripts: shouldAddPreviousScripts) - } - - public func containsPluginScript(pluginScript: PluginScript) -> Bool { - let userScripts = useCopyOfUserScripts() - for script in userScripts { - if let script = script as? PluginScript, script == pluginScript { - return true - } - } - return false - } - - public func containsPluginScript(with groupName: String) -> Bool { - let userScripts = useCopyOfUserScripts() - for script in userScripts { - if let script = script as? PluginScript, script.groupName == groupName { - return true - } - } - return false - } - - @available(macOS 11.0, *) - public func containsPluginScript(pluginScript: PluginScript, in contentWorld: WKContentWorld) -> Bool { - let userScripts = useCopyOfUserScripts() - for script in userScripts { - if let script = script as? PluginScript, script == pluginScript, script.contentWorld == contentWorld { - return true - } - } - return false - } - - @available(macOS 11.0, *) - public func containsPluginScript(with groupName: String, in contentWorld: WKContentWorld) -> Bool { - let userScripts = useCopyOfUserScripts() - for script in userScripts { - if let script = script as? PluginScript, script.groupName == groupName, script.contentWorld == contentWorld { - return true - } - } - return false - } - - @available(macOS 11.0, *) - public func getContentWorlds(with windowId: Int64?) -> Set { - var contentWorldsFiltered = Set([WKContentWorld.page]) - let contentWorlds = Array(self.contentWorlds) - for contentWorld in contentWorlds { - if contentWorld.windowId == windowId { - contentWorldsFiltered.insert(contentWorld) - } - } - return contentWorldsFiltered - } - - // use a copy of self.userScripts to avoid EXC_BREAKPOINT at runtime if self.userScripts gets removed when another code is looping them - private func useCopyOfUserScripts() -> [WKUserScript] { - return Array(self.userScripts) - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKWindowFeatures.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKWindowFeatures.swift deleted file mode 100644 index 469e2be1d0..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WKWindowFeatures.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// WKWindowFeatures.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/02/21. -// - -import Foundation -import WebKit - -extension WKWindowFeatures { - public func toMap () -> [String:Any?] { - return [ - "allowsResizing": allowsResizing, - "height": height, - "menuBarVisibility": menuBarVisibility, - "statusBarVisibility": statusBarVisibility, - "toolbarsVisibility": toolbarsVisibility, - "width": width, - "x": x, - "y": y - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebMessage.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebMessage.swift deleted file mode 100644 index 634c7edcc4..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebMessage.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// WebMessage.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/03/21. -// - -import Foundation -import FlutterMacOS - -public class WebMessage: NSObject, Disposable { - var data: Any? - var type: WebMessageType - var ports: [WebMessagePort]? - - var jsData: String { - var jsData: String = "null" - if let messageData = data { - if type == .arrayBuffer, let messageDataArrayBuffer = messageData as? FlutterStandardTypedData { - jsData = "new Uint8Array(\(Array(messageDataArrayBuffer.data))).buffer" - } else if let messageDataString = messageData as? String { - jsData = "'\(messageDataString.replacingOccurrences(of: "\'", with: "\\'"))'" - } - } - return jsData - } - - public init(data: Any?, type: WebMessageType, ports: [WebMessagePort]?) { - self.type = type - super.init() - self.data = data - self.ports = ports - } - - public static func fromMap(map: [String: Any?]) -> WebMessage { - let portMapList = map["ports"] as? [[String: Any?]] - var ports: [WebMessagePort]? = nil - if let portMapList = portMapList, !portMapList.isEmpty { - ports = [] - portMapList.forEach { (portMap) in - ports?.append(WebMessagePort.fromMap(map: portMap)) - } - } - - return WebMessage( - data: map["data"] as? Any, - type: WebMessageType.init(rawValue: map["type"] as! Int)!, - ports: ports) - } - - public func toMap () -> [String: Any?] { - return [ - "data": type == .arrayBuffer && data is [UInt8] ? Data(data as! [UInt8]) : data, - "type": type.rawValue - ] - } - - public func dispose() { - ports?.removeAll() - } - - deinit { - debugPrint("WebMessage - dealloc") - dispose() - } -} - -public enum WebMessageType: Int { - case string = 0 - case arrayBuffer = 1 -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebMessagePort.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebMessagePort.swift deleted file mode 100644 index 7cb2f3b58e..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebMessagePort.swift +++ /dev/null @@ -1,147 +0,0 @@ -// -// WebMessagePort.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 10/03/21. -// - -import Foundation - -public class WebMessagePort: NSObject { - var name: String - var index: Int64 - var webMessageChannelId: String - var webMessageChannel: WebMessageChannel? - var isClosed = false - var isTransferred = false - var isStarted = false - - public init(name: String, index: Int64, webMessageChannelId: String, webMessageChannel: WebMessageChannel?) { - self.name = name - self.index = index - self.webMessageChannelId = webMessageChannelId - super.init() - self.webMessageChannel = webMessageChannel - } - - public func setWebMessageCallback(completionHandler: ((Any?) -> Void)? = nil) throws { - if isClosed || isTransferred { - throw NSError(domain: "Port is already closed or transferred", code: 0) - } - self.isStarted = true - if let webMessageChannel = webMessageChannel, let webView = webMessageChannel.webView { - let index = name == "port1" ? 0 : 1 - webView.evaluateJavascript(source: """ - (function() { - var webMessageChannel = \(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())["\(webMessageChannel.id)"]; - if (webMessageChannel != null) { - webMessageChannel.\(self.name).onmessage = function (event) { - window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME()).callHandler('onWebMessagePortMessageReceived', { - "webMessageChannelId": "\(webMessageChannel.id)", - "index": \(String(index)), - "message": { - "data": window.ArrayBuffer != null && event.data instanceof ArrayBuffer ? Array.from(new Uint8Array(event.data)) : (event.data != null ? event.data.toString() : null), - "type": window.ArrayBuffer != null && event.data instanceof ArrayBuffer ? 1 : 0 - } - }); - } - } - })(); - """) { (_) in - completionHandler?(nil) - } - } else { - completionHandler?(nil) - } - } - - public func postMessage(message: WebMessage, completionHandler: ((Any?) -> Void)? = nil) throws { - if isClosed || isTransferred { - throw NSError(domain: "Port is already closed or transferred", code: 0) - } - if let webMessageChannel = webMessageChannel, let webView = webMessageChannel.webView { - var portsString = "null" - if let ports = message.ports { - var portArrayString: [String] = [] - for port in ports { - if port == self { - throw NSError(domain: "Source port cannot be transferred", code: 0) - } - if port.isStarted { - throw NSError(domain: "Port is already started", code: 0) - } - if port.isClosed || port.isTransferred { - throw NSError(domain: "Port is already closed or transferred", code: 0) - } - port.isTransferred = true - portArrayString.append("\(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())['\(port.webMessageChannel!.id)'].\(port.name)") - } - portsString = "[" + portArrayString.joined(separator: ", ") + "]" - } - - let source = """ - (function() { - var webMessageChannel = \(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())["\(webMessageChannel.id)"]; - if (webMessageChannel != null) { - webMessageChannel.\(self.name).postMessage(\(message.jsData), \(portsString)); - } - })(); - """ - webView.evaluateJavascript(source: source) { (_) in - completionHandler?(nil) - } - } else { - completionHandler?(nil) - } - message.dispose() - } - - public func close(completionHandler: ((Any?) -> Void)? = nil) throws { - if isTransferred { - throw NSError(domain: "Port is already transferred", code: 0) - } - isClosed = true - if let webMessageChannel = webMessageChannel, let webView = webMessageChannel.webView { - let source = """ - (function() { - var webMessageChannel = \(WebMessageChannelJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME())["\(webMessageChannel.id)"]; - if (webMessageChannel != null) { - webMessageChannel.\(self.name).close(); - } - })(); - """ - webView.evaluateJavascript(source: source) { (_) in - completionHandler?(nil) - } - } else { - completionHandler?(nil) - } - } - - public static func fromMap(map: [String: Any?]) -> WebMessagePort { - let index = map["index"] as! Int64 - return WebMessagePort( - name: "port\(String(index + 1))", - index: index, - webMessageChannelId: map["webMessageChannelId"] as! String, - webMessageChannel: nil) - } - - public func toMap () -> [String: Any?] { - return [ - "name": name, - "index": index, - "webMessageChannelId": webMessageChannelId - ] - } - - public func dispose() { - isClosed = true - webMessageChannel = nil - } - - deinit { - debugPrint("WebMessagePort - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebResourceError.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebResourceError.swift deleted file mode 100644 index 3183944b47..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebResourceError.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// WebResourceError.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 01/05/22. -// - -import Foundation - -public class WebResourceError: NSObject { - var type: Int - var errorDescription: String - - public init(type: Int, errorDescription: String) { - self.type = type - self.errorDescription = errorDescription - } - - public func toMap () -> [String:Any?] { - return [ - "type": type, - "description": errorDescription - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebResourceRequest.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebResourceRequest.swift deleted file mode 100644 index ad7635c496..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebResourceRequest.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// WebResourceRequest.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 01/05/22. -// - -import Foundation -import WebKit - -public class WebResourceRequest: NSObject { - var url: URL - var headers: [AnyHashable:Any]? - var isRedirect = false - var hasGesture = false - var isForMainFrame = true - var method = "GET" - - public init(url: URL, headers: [AnyHashable:Any]?) { - self.url = url - self.headers = headers - } - - public init(url: URL, headers: [AnyHashable:Any]?, isForMainFrame: Bool) { - self.url = url - self.headers = headers - self.isForMainFrame = isForMainFrame - } - - public init(fromURLRequest: URLRequest) { - self.url = fromURLRequest.url ?? URL(string: "about:blank")! - self.headers = fromURLRequest.allHTTPHeaderFields - self.method = fromURLRequest.httpMethod ?? "GET" - } - - public init(fromWKNavigationResponse: WKNavigationResponse) { - let response = fromWKNavigationResponse.response as? HTTPURLResponse - self.url = response?.url ?? URL(string: "about:blank")! - self.headers = response?.allHeaderFields - self.isForMainFrame = fromWKNavigationResponse.isForMainFrame - } - - public func toMap () -> [String:Any?] { - return [ - "url": url.absoluteString, - "headers": headers, - "isRedirect": isRedirect, - "hasGesture": hasGesture, - "isForMainFrame": isForMainFrame, - "method": method - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebResourceResponse.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebResourceResponse.swift deleted file mode 100644 index 4fcf13e750..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebResourceResponse.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// WebResourceResponse.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 01/05/22. -// - -import Foundation -import WebKit - -public class WebResourceResponse: NSObject { - var contentType: String - var contentEncoding: String - var data: Data? - var headers: [AnyHashable:Any]? - var statusCode: Int? - var reasonPhrase: String? - - public init(contentType: String, contentEncoding: String, data: Data?, - headers: [AnyHashable:Any]?, statusCode: Int?, reasonPhrase: String?) { - self.contentType = contentType - self.contentEncoding = contentEncoding - self.data = data - self.headers = headers - self.statusCode = statusCode - self.reasonPhrase = reasonPhrase - } - - public init(fromWKNavigationResponse: WKNavigationResponse) { - let response = fromWKNavigationResponse.response as? HTTPURLResponse - self.contentType = response?.mimeType ?? "" - self.contentEncoding = response?.textEncodingName ?? "" - self.headers = response?.allHeaderFields - self.statusCode = response?.statusCode - } - - public func toMap () -> [String:Any?] { - return [ - "contentType": contentType, - "contentEncoding": contentEncoding, - "data": data, - "headers": headers, - "statusCode": statusCode, - "reasonPhrase": reasonPhrase - ] - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebViewTransport.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebViewTransport.swift deleted file mode 100644 index 7e21f7e6b1..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Types/WebViewTransport.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// WebViewTransport.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 16/02/21. -// - -import Foundation - -public class WebViewTransport: NSObject { - var webView: InAppWebView - var request: URLRequest - - init(webView: InAppWebView, request: URLRequest) { - self.webView = webView - self.request = request - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Util.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Util.swift deleted file mode 100644 index bf9d91cce5..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/Util.swift +++ /dev/null @@ -1,155 +0,0 @@ -// -// Util.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 12/02/21. -// - -import Foundation -import WebKit -import FlutterMacOS - -public class Util { - public static func getUrlAsset(assetFilePath: String) throws -> URL { -// let key = SwiftFlutterPlugin.instance?.registrar?.lookupKey(forAsset: assetFilePath) - let assetFilePath = "../Frameworks/App.framework/Resources/flutter_assets/\(assetFilePath)" - guard let assetURL = Bundle.main.url(forResource: assetFilePath, withExtension: nil) else { - throw NSError(domain: assetFilePath + " asset file cannot be found!", code: 0) - } - return assetURL - } - - public static func getAbsPathAsset(assetFilePath: String) throws -> String { -// let key = SwiftFlutterPlugin.instance?.registrar?.lookupKey(forAsset: assetFilePath) - let assetFilePath = "../Frameworks/App.framework/Resources/flutter_assets/\(assetFilePath)" - guard let assetAbsPath = Bundle.main.path(forResource: assetFilePath, ofType: nil) else { - throw NSError(domain: assetFilePath + " asset file cannot be found!", code: 0) - } - return assetAbsPath - } - - public static func convertToDictionary(text: String) -> [String: Any]? { - if let data = text.data(using: .utf8) { - do { - return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] - } catch { - print(error.localizedDescription) - } - } - return nil - } - - public static func JSONStringify(value: Any, prettyPrinted: Bool = false) -> String { - let options: JSONSerialization.WritingOptions = prettyPrinted ? .prettyPrinted : .init(rawValue: 0) - if JSONSerialization.isValidJSONObject(value) { - let data = try? JSONSerialization.data(withJSONObject: value, options: options) - if data != nil { - if let string = String(data: data!, encoding: .utf8) { - return string - } - } - } - return "" - } - - @available(macOS 11.0, *) - public static func getContentWorld(name: String) -> WKContentWorld { - switch name { - case "defaultClient": - return WKContentWorld.defaultClient - case "page": - return WKContentWorld.page - default: - return WKContentWorld.world(name: name) - } - } - - public static func getNSPrintInfoJobDisposition(name: String) -> NSPrintInfo.JobDisposition { - switch name { - case "save": - return NSPrintInfo.JobDisposition.save - case "cancel": - return NSPrintInfo.JobDisposition.cancel - case "preview": - return NSPrintInfo.JobDisposition.preview - case "spool": - return NSPrintInfo.JobDisposition.spool - default: - return NSPrintInfo.JobDisposition.spool - } - } - - public static func isIPv4(address: String) -> Bool { - var sin = sockaddr_in() - return address.withCString({ cstring in inet_pton(AF_INET, cstring, &sin.sin_addr) }) == 1 - } - - public static func isIPv6(address: String) -> Bool { - var sin6 = sockaddr_in6() - return address.withCString({ cstring in inet_pton(AF_INET6, cstring, &sin6.sin6_addr) }) == 1 - } - - public static func isIpAddress(address: String) -> Bool { - return Util.isIPv6(address: address) || Util.isIPv4(address: address) - } - - public static func normalizeIPv6(address: String) throws -> String { - if !Util.isIPv6(address: address) { - throw NSError(domain: "Invalid address: \(address)", code: 0) - } - var ipString = address - // replace ipv4 address if any - let ipv4Regex = try! NSRegularExpression(pattern: "(.*:)([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$)") - if let match = ipv4Regex.firstMatch(in: address, options: [], range: NSRange(location: 0, length: address.utf16.count)) { - if let ipv6PartRange = Range(match.range(at: 1), in: address) { - ipString = String(address[ipv6PartRange]) - } - if let ipv4Range = Range(match.range(at: 2), in: address) { - let ipv4 = address[ipv4Range] - let ipv4Split = ipv4.split(separator: ".") - var ipv4Converted = Array(repeating: "0000", count: 4) - for i in 0...3 { - let byte = Int(ipv4Split[i])! - let hex = ("0" + String(byte, radix: 16)) - var offset = hex.count - 3 - offset = offset < 0 ? 0 : offset - let fromIndex = hex.index(hex.startIndex, offsetBy: offset) - let toIndex = hex.index(hex.startIndex, offsetBy: hex.count - 1) - let indexRange = Range(uncheckedBounds: (lower: fromIndex, upper: toIndex)) - ipv4Converted[i] = String(hex[indexRange]) - } - ipString += ipv4Converted[0] + ipv4Converted[1] + ":" + ipv4Converted[2] + ipv4Converted[3] - } - } - - // take care of leading and trailing :: - let regex = try! NSRegularExpression(pattern: "^:|:$") - ipString = regex.stringByReplacingMatches(in: ipString, options: [], range: NSRange(location: 0, length: ipString.count), withTemplate: "") - - let ipv6 = ipString.split(separator: ":", omittingEmptySubsequences: false) - var fullIPv6 = Array(repeating: "0000", count: ipv6.count) - - for (i, hex) in ipv6.enumerated() { - if !hex.isEmpty { - // normalize leading zeros - let hexString = String("0000" + hex) - var offset = hexString.count - 5 - offset = offset < 0 ? 0 : offset - let fromIndex = hexString.index(hexString.startIndex, offsetBy: offset) - let toIndex = hexString.index(hexString.startIndex, offsetBy: hexString.count - 1) - let indexRange = Range(uncheckedBounds: (lower: fromIndex, upper: toIndex)) - fullIPv6[i] = String(hexString[indexRange]) - } else { - // normalize grouped zeros :: - var zeros: [String] = [] - for _ in ipv6.count...8 { - zeros.append("0000") - } - fullIPv6[i] = zeros.joined(separator: ":") - } - } - - return fullIPv6.joined(separator: ":") - } - -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/WKProcessPoolManager.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/WKProcessPoolManager.swift deleted file mode 100755 index 038fb4d757..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/WKProcessPoolManager.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// WKProcessPoolManager.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 19/11/2019. -// - -import Foundation -import WebKit - -public class WKProcessPoolManager { - static let sharedProcessPool = WKProcessPool() -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/WebAuthenticationSession/WebAuthenticationSession.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/WebAuthenticationSession/WebAuthenticationSession.swift deleted file mode 100644 index c314423bf8..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/WebAuthenticationSession/WebAuthenticationSession.swift +++ /dev/null @@ -1,102 +0,0 @@ -// -// WebAuthenticationSession.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 08/05/22. -// - -import Foundation -import AuthenticationServices -import SafariServices -import FlutterMacOS - -public class WebAuthenticationSession: NSObject, ASWebAuthenticationPresentationContextProviding, Disposable { - static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_webauthenticationsession_" - var id: String - var plugin: InAppWebViewFlutterPlugin? - var url: URL - var callbackURLScheme: String? - var settings: WebAuthenticationSessionSettings - var session: Any? - var channelDelegate: WebAuthenticationSessionChannelDelegate? - private var _canStart = true - - public init(plugin: InAppWebViewFlutterPlugin, id: String, url: URL, callbackURLScheme: String?, settings: WebAuthenticationSessionSettings) { - self.id = id - self.plugin = plugin - self.url = url - self.settings = settings - super.init() - self.callbackURLScheme = callbackURLScheme - if #available(macOS 10.15, *) { - let session = ASWebAuthenticationSession(url: self.url, callbackURLScheme: self.callbackURLScheme, completionHandler: self.completionHandler) - session.presentationContextProvider = self - self.session = session - } - let channel = FlutterMethodChannel(name: WebAuthenticationSession.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: plugin.registrar.messenger) - self.channelDelegate = WebAuthenticationSessionChannelDelegate(webAuthenticationSession: self, channel: channel) - } - - public func prepare() { - if #available(macOS 10.15, *), let session = session as? ASWebAuthenticationSession { - session.prefersEphemeralWebBrowserSession = settings.prefersEphemeralWebBrowserSession - } - } - - public func completionHandler(url: URL?, error: Error?) -> Void { - channelDelegate?.onComplete(url: url, errorCode: error?._code) - } - - public func canStart() -> Bool { - guard let session = session else { - return false - } - if #available(macOS 10.15.4, *), let session = session as? ASWebAuthenticationSession { - return session.canStart - } - return _canStart - } - - public func start() -> Bool { - guard let session = session else { - return false - } - var started = false - if #available(macOS 10.15, *), let session = session as? ASWebAuthenticationSession { - started = session.start() - } - if started { - _canStart = false - } - return started - } - - public func cancel() { - guard let session = session else { - return - } - if #available(macOS 10.15, *), let session = session as? ASWebAuthenticationSession { - session.cancel() - } - } - - @available(macOS 10.15, *) - public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { - return NSApplication.shared.windows.first { $0.isKeyWindow } ?? ASPresentationAnchor() - } - - public func dispose() { - cancel() - channelDelegate?.dispose() - channelDelegate = nil - session = nil - plugin?.webAuthenticationSessionManager?.sessions[id] = nil - plugin = nil - } - - deinit { - debugPrint("WebAuthenticationSession - dealloc") - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/WebAuthenticationSession/WebAuthenticationSessionChannelDelegate.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/WebAuthenticationSession/WebAuthenticationSessionChannelDelegate.swift deleted file mode 100644 index ddd8d52846..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/WebAuthenticationSession/WebAuthenticationSessionChannelDelegate.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// WebAuthenticationSessionChannelDelegate.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 08/05/22. -// - -import Foundation -import FlutterMacOS - -public class WebAuthenticationSessionChannelDelegate: ChannelDelegate { - private weak var webAuthenticationSession: WebAuthenticationSession? - - public init(webAuthenticationSession: WebAuthenticationSession, channel: FlutterMethodChannel) { - super.init(channel: channel) - self.webAuthenticationSession = webAuthenticationSession - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - // let arguments = call.arguments as? NSDictionary - switch call.method { - case "canStart": - if let webAuthenticationSession = webAuthenticationSession { - result(webAuthenticationSession.canStart()) - } else { - result(false) - } - break - case "start": - if let webAuthenticationSession = webAuthenticationSession { - result(webAuthenticationSession.start()) - } else { - result(false) - } - break - case "cancel": - if let webAuthenticationSession = webAuthenticationSession { - webAuthenticationSession.cancel() - result(true) - } else { - result(false) - } - break - case "dispose": - if let webAuthenticationSession = webAuthenticationSession { - webAuthenticationSession.dispose() - result(true) - } else { - result(false) - } - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func onComplete(url: URL?, errorCode: Int?) { - let arguments: [String: Any?] = [ - "url": url?.absoluteString, - "errorCode": errorCode - ] - DispatchQueue.main.async { [weak self] in - self?.channel?.invokeMethod("onComplete", arguments: arguments) - } - } - - public override func dispose() { - super.dispose() - webAuthenticationSession = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/WebAuthenticationSession/WebAuthenticationSessionManager.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/WebAuthenticationSession/WebAuthenticationSessionManager.swift deleted file mode 100644 index fb153f84a7..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/WebAuthenticationSession/WebAuthenticationSessionManager.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// WebAuthenticationSessionManager.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 08/05/22. -// - -import FlutterMacOS -import AppKit -import WebKit -import Foundation -import AVFoundation -import SafariServices - -public class WebAuthenticationSessionManager: ChannelDelegate { - static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_webauthenticationsession" - var plugin: InAppWebViewFlutterPlugin? - var sessions: [String: WebAuthenticationSession?] = [:] - - init(plugin: InAppWebViewFlutterPlugin) { - super.init(channel: FlutterMethodChannel(name: WebAuthenticationSessionManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger)) - self.plugin = plugin - } - - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? NSDictionary - - switch call.method { - case "create": - let id = arguments!["id"] as! String - let url = arguments!["url"] as! String - let callbackURLScheme = arguments!["callbackURLScheme"] as? String - let initialSettings = arguments!["initialSettings"] as! [String: Any?] - create(id: id, url: url, callbackURLScheme: callbackURLScheme, settings: initialSettings, result: result) - break - case "isAvailable": - if #available(macOS 10.15, *) { - result(true) - } else { - result(false) - } - break - default: - result(FlutterMethodNotImplemented) - break - } - } - - public func create(id: String, url: String, callbackURLScheme: String?, settings: [String: Any?], result: @escaping FlutterResult) { - if #available(macOS 10.15, *), let plugin = plugin { - let sessionUrl = URL(string: url) ?? URL(string: "about:blank")! - let initialSettings = WebAuthenticationSessionSettings() - let _ = initialSettings.parse(settings: settings) - let session = WebAuthenticationSession(plugin: plugin, id: id, url: sessionUrl, callbackURLScheme: callbackURLScheme, settings: initialSettings) - session.prepare() - sessions[id] = session - result(true) - return - } - - result(FlutterError.init(code: "WebAuthenticationSessionManager", message: "WebAuthenticationSession is not available!", details: nil)) - } - - public override func dispose() { - super.dispose() - let sessionValues = sessions.values - sessionValues.forEach { (session: WebAuthenticationSession?) in - session?.cancel() - session?.dispose() - } - sessions.removeAll() - plugin = nil - } - - deinit { - dispose() - } -} diff --git a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/WebAuthenticationSession/WebAuthenticationSessionSettings.swift b/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/WebAuthenticationSession/WebAuthenticationSessionSettings.swift deleted file mode 100644 index ac262a31ff..0000000000 --- a/flutter_inappwebview_macos/macos/flutter_inappwebview_macos/Sources/flutter_inappwebview_macos/WebAuthenticationSession/WebAuthenticationSessionSettings.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// WebAuthenticationSessionSettings.swift -// flutter_inappwebview -// -// Created by Lorenzo Pichilli on 08/05/22. -// - -import Foundation -import AuthenticationServices -import SafariServices - -@objcMembers -public class WebAuthenticationSessionSettings: ISettings { - - var prefersEphemeralWebBrowserSession = false - - override init(){ - super.init() - } - - override func getRealSettings(obj: WebAuthenticationSession?) -> [String: Any?] { - var realOptions: [String: Any?] = toMap() - if #available(macOS 10.15, *), let session = obj?.session as? ASWebAuthenticationSession { - realOptions["prefersEphemeralWebBrowserSession"] = session.prefersEphemeralWebBrowserSession - } - return realOptions - } -} diff --git a/flutter_inappwebview_macos/pubspec.yaml b/flutter_inappwebview_macos/pubspec.yaml deleted file mode 100644 index d1f4c8fff7..0000000000 --- a/flutter_inappwebview_macos/pubspec.yaml +++ /dev/null @@ -1,83 +0,0 @@ -name: flutter_inappwebview_macos -description: macOS implementation of the flutter_inappwebview plugin. -version: 1.2.0-beta.3 -homepage: https://inappwebview.dev/ -repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_macos -issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues -funding: - - https://inappwebview.dev/donate/ -topics: - - html - - webview - - webview-flutter - - inappwebview - - browser - -environment: - sdk: ^3.8.0 - flutter: ">=3.32.0" - -dependencies: - flutter: - sdk: flutter - flutter_inappwebview_platform_interface: ^1.4.0-beta.3 - # path: ../flutter_inappwebview_platform_interface - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^6.0.0 - plugin_platform_interface: ^2.1.8 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - # This section identifies this Flutter project as a plugin project. - # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) - # which should be registered in the plugin registry. This is required for - # using method channels. - # The Android 'package' specifies package in which the registered class is. - # This is required for using method channels on Android. - # The 'ffiPlugin' specifies that native code should be built and bundled. - # This is required for using `dart:ffi`. - # All these are used by the tooling to maintain consistency when - # adding or updating assets for this project. - plugin: - implements: flutter_inappwebview - platforms: - macos: - pluginClass: InAppWebViewFlutterPlugin - dartPluginClass: MacOSInAppWebViewPlatform - - # To add assets to your plugin package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # To add custom fonts to your plugin package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages diff --git a/flutter_inappwebview_macos/test/flutter_inappwebview_macos_test.dart b/flutter_inappwebview_macos/test/flutter_inappwebview_macos_test.dart deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/flutter_inappwebview_platform_interface/.gitignore b/flutter_inappwebview_platform_interface/.gitignore deleted file mode 100644 index 96486fd930..0000000000 --- a/flutter_inappwebview_platform_interface/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock -**/doc/api/ -.dart_tool/ -.packages -build/ diff --git a/flutter_inappwebview_platform_interface/.metadata b/flutter_inappwebview_platform_interface/.metadata deleted file mode 100644 index 5c536bcec5..0000000000 --- a/flutter_inappwebview_platform_interface/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e" - channel: "stable" - -project_type: package diff --git a/flutter_inappwebview_platform_interface/CHANGELOG.md b/flutter_inappwebview_platform_interface/CHANGELOG.md deleted file mode 100644 index dd4ca4e534..0000000000 --- a/flutter_inappwebview_platform_interface/CHANGELOG.md +++ /dev/null @@ -1,117 +0,0 @@ -## 1.4.0-beta.3 - -- Updated `flutter_inappwebview_internal_annotations` dependency from `^1.2.0` to `^1.3.0` -- Added `isClassSupported`, `isPropertySupported`, `isMethodSupported` static methods for all main classes, such as `PlatformInAppWebViewController`, `InAppWebViewSettings`, `PlatformInAppBrowser`, etc., in order to check if a class, property, or method is supported by the platform at runtime -- Added `isSupported` method to all custom enum classes -- Added `saveState`, `restoreState`, `requestEnterFullscreen`, `requestExitFullscreen`, `setVisible`, `setTargetRefreshRate`, `getTargetRefreshRate`, `requestPointerLock`, `requestPointerUnlock`, `getScreenScale`, `setScreenScale`, `isVisible`, `getFrameId`, `getFavicon`, `showSaveAsUI`, `getMemoryUsageTargetLevel`, `setMemoryUsageTargetLevel` methods to `PlatformInAppWebViewController` class -- Added `useOnAjaxReadyStateChange`, `useOnAjaxProgress`, `useOnShowFileChooser`, `corsAllowlist`, `itpEnabled`, `darkMode`, `disableAnimations`, `fontAntialias`, `fontHintingStyle`, `fontSubpixelLayout`, `fontDPI`, `cursorBlinkTime`, `doubleClickDistance`, `doubleClickTime`, `dragThreshold`, `keyRepeatDelay`, `keyRepeatInterval`, `disableWebSecurity`, `enableWebRTC`, `webRTCUdpPortsRange`, `javaScriptCanAccessClipboard`, `allowModalDialogs`, `enableMedia`, `enableEncryptedMedia`, `enableMediaCapabilities`, `enableMockCaptureDevices`, `mediaContentTypesRequiringHardwareSupport`, `enableJavaScriptMarkup`, `enable2DCanvasAcceleration`, `allowTopNavigationToDataUrls` properties to `InAppWebViewSettings` -- Added `onShowFileChooser`, `onContentLoading`, `onDOMContentLoaded`, `onLaunchingExternalUriScheme`, `onFaviconChanged`, `onNotificationReceived`, `onSaveAsUIShowing`, `onSaveFileSecurityCheckStarting`, `onScreenCaptureStarting` WebView events -- Added `PlatformWebNotificationController` class -- Update code documentation -- Deprecated `onReceivedIcon` in favor of `onFaviconChanged` - -## 1.4.0-beta.2 - -- Updated `flutter_inappwebview_internal_annotations` dependency from `^1.1.1` to `^1.2.0` -- Updated `fromMap` static method and `toMap` method implementations -- Updated all WebView events with return type `Future` to type `FutureOr` in order to not force the usage of `async` keyword -- Added `byName`, `name`, `asNameMap` custom enum classes methods -- Added `statusBarEnabled`, `browserAcceleratorKeysEnabled`, `generalAutofillEnabled`, `passwordAutosaveEnabled`, `isPinchZoomEnabled`, `hiddenPdfToolbarItems`, `reputationCheckingRequired`, `nonClientRegionSupportEnabled`, `alpha`, `isUserInteractionEnabled`, `handleAcceleratorKeyPressed` properties to `InAppWebViewSettings` -- Added `isInterfaceSupported`, `getProcessInfos`, `getFailureReportFolderPath` methods to `PlatformWebViewEnvironment` class -- Added `isInterfaceSupported`, `setInputMethodEnabled`, `hideInputMethod`, `showInputMethod` methods to `PlatformInAppWebViewController` class -- Added `exclusiveUserDataFolderAccess`, `isCustomCrashReportingEnabled`, `enableTrackingPrevention`, `areBrowserExtensionsEnabled`, `channelSearchKind`, `releaseChannels`, `scrollbarStyle` properties to `WebViewEnvironmentSettings` -- Added `onDownloadStarting` WebView event and deprecated `onDownloadStartRequest` event -- Added `onNewBrowserVersionAvailable`, `onBrowserProcessExited`, `onProcessInfosChanged` events to `PlatformWebViewEnvironment` class -- Added `onAcceleratorKeyPressed` WebView event -- Fixed missing PrintJobOrientation android values - -## 1.4.0-beta.1 - -- Updated static `fromMap` implementation for some classes -- Updated `kJavaScriptHandlerForbiddenNames` list -- Added `PlatformInAppLocalhostServer.onData` parameter to set a custom on data server callback -- Added `javaScriptBridgeEnabled`, `javaScriptBridgeOriginAllowList`, `javaScriptBridgeForMainFrameOnly`, `pluginScriptsOriginAllowList`, `pluginScriptsForMainFrameOnly`, `javaScriptHandlersOriginAllowList`, `javaScriptHandlersForMainFrameOnly`, `scrollMultiplier` InAppWebViewSettings parameters -- Added `setJavaScriptBridgeName`, `getJavaScriptBridgeName` static WebView controller methods -- Added `onProcessFailed` WebView event -- Added `regexToAllowSyncUrlLoading` Android-specific property to `InAppWebViewSettings` -- Added `JavaScriptHandlerFunctionData` type -- Deprecated `JavaScriptHandlerCallback` type in favor of `JavaScriptHandlerFunction` type -- Deprecated `InAppWebViewSettings.forceDark` and `InAppWebViewSettings.forceDarkStrategy` Android-only properties in favor of `InAppWebViewSettings.algorithmicDarkeningAllowed` -- Fixed X509Certificate PEM base64 decoding - -## 1.3.0+1 - -- Fixed `X509Certificate.toMap` method - -## 1.3.0 - -- Added `WebViewEnvironment.customSchemeRegistrations` parameter for Windows -- Added `CustomSchemeRegistration` type -- Updated docs - -## 1.2.0 - -- Updated `Uint8List` conversion inside `fromMap` methods - -## 1.1.1 - -- Updated permission models for Windows platform - -## 1.1.0+1 - -- Updated docs and pubspec.yaml - -## 1.1.0 - -- Added `PlatformWebViewEnvironment` class -- Updates minimum supported SDK version to Flutter 3.24/Dart 3.5. -- Removed unsupported feature `WebViewFeature.SUPPRESS_ERROR_PAGE` - -## 1.0.10 - -- Merged "Added == operator and hashCode to WebUri" [#1941](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1941) (thanks to [daisukeueta](https://github.com/daisukeueta)) - -## 1.0.9 - -- Fix typos (thanks to [michalsrutek](https://github.com/michalsrutek)) - -## 1.0.8 - -- Added `PlatformCustomPathHandler` class to be able to implement custom path handlers for `WebViewAssetLoader` - -## 1.0.7 - -- Added `InAppBrowser.onMainWindowWillClose` event -- Added `WindowType.WINDOW` for `InAppBrowserSettings.windowType` - -## 1.0.6 - -- Added `InAppWebViewSettings.interceptOnlyAsyncAjaxRequests` [#1905](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1905) -- Added `PlatformInAppWebViewController.clearFormData` method -- Added `PlatformCookieManager.removeSessionCookies` method -- Updated `InAppWebViewSettings.useShouldInterceptAjaxRequest` docs -- Updated `PlatformCookieManager` methods return value - -## 1.0.5 - -- Must call super `dispose` method for `PlatformInAppBrowser` and `PlatformChromeSafariBrowser` - -## 1.0.4 - -- Expose missing `InAppBrowserSettings.menuButtonColor` option - -## 1.0.3 - -- Expose missing old `AndroidInAppWebViewOptions` and `IOSInAppWebViewOptions` classes - -## 1.0.2 - -- Added `PlatformPrintJobController.onComplete` setter - -## 1.0.1 - -- Updated README - -## 1.0.0 - -Initial release. diff --git a/flutter_inappwebview_platform_interface/LICENSE b/flutter_inappwebview_platform_interface/LICENSE deleted file mode 100644 index 6ccd8da42c..0000000000 --- a/flutter_inappwebview_platform_interface/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2023 Lorenzo Pichilli - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/flutter_inappwebview_platform_interface/README.md b/flutter_inappwebview_platform_interface/README.md deleted file mode 100644 index c7e1d40d0a..0000000000 --- a/flutter_inappwebview_platform_interface/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# flutter\_inappwebview\_platform\_interface - -A common platform interface for the [`flutter_inappwebview`](https://pub.dev/packages/flutter_inappwebview) plugin. - -This interface allows platform-specific implementations of the `flutter_inappwebview` -plugin, as well as the plugin itself, to ensure they are supporting the -same interface. - -# Usage - -To implement a new platform-specific implementation of `flutter_inappwebview`, extend -[`InAppWebViewPlatform`](lib/src/inappwebview_platform.dart) with an implementation that performs the -platform-specific behavior, and when you register your plugin, set the default -`InAppWebViewPlatform` by calling -`InAppWebViewPlatform.instance = MyPlatformWebview()`. - -# Note on breaking changes - -Strongly prefer non-breaking changes (such as adding a method to the interface) -over breaking changes for this package. - -See https://flutter.dev/go/platform-interface-breaking-changes for a discussion -on why a less-clean interface is preferable to a breaking change. \ No newline at end of file diff --git a/flutter_inappwebview_platform_interface/analysis_options.yaml b/flutter_inappwebview_platform_interface/analysis_options.yaml deleted file mode 100644 index 12f30f65de..0000000000 --- a/flutter_inappwebview_platform_interface/analysis_options.yaml +++ /dev/null @@ -1,20 +0,0 @@ -include: package:flutter_lints/flutter.yaml - -linter: - rules: - constant_identifier_names: ignore - deprecated_member_use_from_same_package: ignore - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options -analyzer: - errors: - constant_identifier_names: ignore - deprecated_member_use: ignore - deprecated_member_use_from_same_package: ignore - unnecessary_cast: ignore - unnecessary_import: ignore - unnecessary_non_null_assertion: ignore - unused_element: ignore - unused_element_parameter: ignore - dead_null_aware_expression: ignore diff --git a/flutter_inappwebview_platform_interface/build.yaml b/flutter_inappwebview_platform_interface/build.yaml deleted file mode 100644 index e2b3acf338..0000000000 --- a/flutter_inappwebview_platform_interface/build.yaml +++ /dev/null @@ -1,5 +0,0 @@ -targets: - $default: - sources: - exclude: - - example/**.dart diff --git a/flutter_inappwebview_platform_interface/lib/flutter_inappwebview_platform_interface.dart b/flutter_inappwebview_platform_interface/lib/flutter_inappwebview_platform_interface.dart deleted file mode 100644 index 2367b0f271..0000000000 --- a/flutter_inappwebview_platform_interface/lib/flutter_inappwebview_platform_interface.dart +++ /dev/null @@ -1,3 +0,0 @@ -library flutter_inappwebview_platform_interface; - -export 'src/main.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/android/chrome_custom_tabs_options.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/android/chrome_custom_tabs_options.dart deleted file mode 100755 index 1533dea00d..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/android/chrome_custom_tabs_options.dart +++ /dev/null @@ -1,162 +0,0 @@ -import 'dart:ui'; - -import '../../util.dart'; -import '../../types/main.dart'; - -import '../chrome_safari_browser_settings.dart'; -import '../platform_chrome_safari_browser.dart'; - -import '../../in_app_webview/android/in_app_webview_options.dart'; - -///This class represents all the Android-only [PlatformChromeSafariBrowser] options available. -///Use [ChromeSafariBrowserSettings] instead. -@Deprecated('Use ChromeSafariBrowserSettings instead') -class AndroidChromeCustomTabsOptions - implements ChromeSafariBrowserOptions, AndroidOptions { - ///Use [shareState] instead. - @Deprecated('Use shareState instead') - bool? addDefaultShareMenuItem; - - ///The share state that should be applied to the custom tab. The default value is [CustomTabsShareState.SHARE_STATE_DEFAULT]. - /// - ///**NOTE**: Not available in a Trusted Web Activity. - CustomTabsShareState shareState; - - ///Set to `false` if the title shouldn't be shown in the custom tab. The default value is `true`. - /// - ///**NOTE**: Not available in a Trusted Web Activity. - bool showTitle; - - ///Set the custom background color of the toolbar. - Color? toolbarBackgroundColor; - - ///Set to `true` to enable the url bar to hide as the user scrolls down on the page. The default value is `false`. - /// - ///**NOTE**: Not available in a Trusted Web Activity. - bool enableUrlBarHiding; - - ///Set to `true` to enable Instant Apps. The default value is `false`. - /// - ///**NOTE**: Not available in a Trusted Web Activity. - bool instantAppsEnabled; - - ///Set an explicit application package name that limits - ///the components this Intent will resolve to. If left to the default - ///value of null, all components in all applications will considered. - ///If non-null, the Intent can only match the components in the given - ///application package. - String? packageName; - - ///Set to `true` to enable Keep Alive. The default value is `false`. - bool keepAliveEnabled; - - ///Set to `true` to launch the Android activity in `singleInstance` mode. The default value is `false`. - bool isSingleInstance; - - ///Set to `true` to launch the Android intent with the flag `FLAG_ACTIVITY_NO_HISTORY`. The default value is `false`. - bool noHistory; - - ///Set to `true` to launch the Custom Tab as a Trusted Web Activity. The default value is `false`. - bool isTrustedWebActivity; - - ///Sets a list of additional trusted origins that the user may navigate or be redirected to from the starting uri. - /// - ///**NOTE**: Available only in a Trusted Web Activity. - List additionalTrustedOrigins; - - ///Sets a display mode of a Trusted Web Activity. - /// - ///**NOTE**: Available only in a Trusted Web Activity. - TrustedWebActivityDisplayMode? displayMode; - - ///Sets a screen orientation. This can be used e.g. to enable the locking of an orientation lock type. - /// - ///**NOTE**: Available only in a Trusted Web Activity. - TrustedWebActivityScreenOrientation screenOrientation; - - AndroidChromeCustomTabsOptions({ - @Deprecated('Use shareState instead') this.addDefaultShareMenuItem, - this.shareState = CustomTabsShareState.SHARE_STATE_DEFAULT, - this.showTitle = true, - this.toolbarBackgroundColor, - this.enableUrlBarHiding = false, - this.instantAppsEnabled = false, - this.packageName, - this.keepAliveEnabled = false, - this.isSingleInstance = false, - this.noHistory = false, - this.isTrustedWebActivity = false, - this.additionalTrustedOrigins = const [], - this.displayMode, - this.screenOrientation = TrustedWebActivityScreenOrientation.DEFAULT, - }); - - @override - Map toMap() { - return { - // ignore: deprecated_member_use_from_same_package - "addDefaultShareMenuItem": addDefaultShareMenuItem, - "shareState": shareState.toNativeValue(), - "showTitle": showTitle, - "toolbarBackgroundColor": toolbarBackgroundColor?.toHex(), - "enableUrlBarHiding": enableUrlBarHiding, - "instantAppsEnabled": instantAppsEnabled, - "packageName": packageName, - "keepAliveEnabled": keepAliveEnabled, - "isSingleInstance": isSingleInstance, - "noHistory": noHistory, - "isTrustedWebActivity": isTrustedWebActivity, - "additionalTrustedOrigins": additionalTrustedOrigins, - "displayMode": displayMode?.toMap(), - "screenOrientation": screenOrientation.toNativeValue(), - }; - } - - static AndroidChromeCustomTabsOptions fromMap(Map map) { - AndroidChromeCustomTabsOptions options = - new AndroidChromeCustomTabsOptions(); - // ignore: deprecated_member_use_from_same_package - options.addDefaultShareMenuItem = map["addDefaultShareMenuItem"]; - options.shareState = map["shareState"]; - options.showTitle = map["showTitle"]; - options.toolbarBackgroundColor = UtilColor.fromHex( - map["toolbarBackgroundColor"], - ); - options.enableUrlBarHiding = map["enableUrlBarHiding"]; - options.instantAppsEnabled = map["instantAppsEnabled"]; - options.packageName = map["packageName"]; - options.keepAliveEnabled = map["keepAliveEnabled"]; - options.isSingleInstance = map["isSingleInstance"]; - options.noHistory = map["noHistory"]; - options.isTrustedWebActivity = map["isTrustedWebActivity"]; - options.additionalTrustedOrigins = map["additionalTrustedOrigins"]; - switch (map["displayMode"]["type"]) { - case "IMMERSIVE_MODE": - options.displayMode = TrustedWebActivityImmersiveDisplayMode.fromMap( - map["displayMode"], - ); - break; - case "DEFAULT_MODE": - default: - options.displayMode = TrustedWebActivityDefaultDisplayMode(); - break; - } - options.screenOrientation = map["screenOrientation"]; - return options; - } - - @override - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } - - @override - AndroidChromeCustomTabsOptions copy() { - return AndroidChromeCustomTabsOptions.fromMap(this.toMap()); - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/android/main.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/android/main.dart deleted file mode 100644 index 484176f580..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/android/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'chrome_custom_tabs_options.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/apple/main.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/apple/main.dart deleted file mode 100644 index 88c59931fe..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/apple/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'safari_options.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/apple/safari_options.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/apple/safari_options.dart deleted file mode 100755 index 66e92c4d62..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/apple/safari_options.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'dart:ui'; - -import '../../util.dart'; -import '../../types/main.dart'; - -import '../chrome_safari_browser_settings.dart'; -import '../platform_chrome_safari_browser.dart'; - -import '../../in_app_webview/apple/in_app_webview_options.dart'; - -///This class represents all the iOS-only [PlatformChromeSafariBrowser] options available. -///Use [ChromeSafariBrowserSettings] instead. -@Deprecated('Use ChromeSafariBrowserSettings instead') -class IOSSafariOptions implements ChromeSafariBrowserOptions, IosOptions { - ///Set to `true` if Reader mode should be entered automatically when it is available for the webpage. The default value is `false`. - bool entersReaderIfAvailable; - - ///Set to `true` to enable bar collapsing. The default value is `false`. - bool barCollapsingEnabled; - - ///Set the custom style for the dismiss button. The default value is [IOSSafariDismissButtonStyle.DONE]. - /// - ///**NOTE**: available on iOS 11.0+. - IOSSafariDismissButtonStyle dismissButtonStyle; - - ///Set the custom background color of the navigation bar and the toolbar. - /// - ///**NOTE**: available on iOS 10.0+. - Color? preferredBarTintColor; - - ///Set the custom color of the control buttons on the navigation bar and the toolbar. - /// - ///**NOTE**: available on iOS 10.0+. - Color? preferredControlTintColor; - - ///Set the custom modal presentation style when presenting the WebView. The default value is [IOSUIModalPresentationStyle.FULL_SCREEN]. - IOSUIModalPresentationStyle presentationStyle; - - ///Set to the custom transition style when presenting the WebView. The default value is [IOSUIModalTransitionStyle.COVER_VERTICAL]. - IOSUIModalTransitionStyle transitionStyle; - - IOSSafariOptions({ - this.entersReaderIfAvailable = false, - this.barCollapsingEnabled = false, - this.dismissButtonStyle = IOSSafariDismissButtonStyle.DONE, - this.preferredBarTintColor, - this.preferredControlTintColor, - this.presentationStyle = IOSUIModalPresentationStyle.FULL_SCREEN, - this.transitionStyle = IOSUIModalTransitionStyle.COVER_VERTICAL, - }); - - @override - Map toMap() { - return { - "entersReaderIfAvailable": entersReaderIfAvailable, - "barCollapsingEnabled": barCollapsingEnabled, - "dismissButtonStyle": dismissButtonStyle.toNativeValue(), - "preferredBarTintColor": preferredBarTintColor?.toHex(), - "preferredControlTintColor": preferredControlTintColor?.toHex(), - "presentationStyle": presentationStyle.toNativeValue(), - "transitionStyle": transitionStyle.toNativeValue(), - }; - } - - static IOSSafariOptions fromMap(Map map) { - IOSSafariOptions options = IOSSafariOptions(); - options.entersReaderIfAvailable = map["entersReaderIfAvailable"]; - options.barCollapsingEnabled = map["barCollapsingEnabled"]; - options.dismissButtonStyle = IOSSafariDismissButtonStyle.fromNativeValue( - map["dismissButtonStyle"], - )!; - options.preferredBarTintColor = UtilColor.fromHex( - map["preferredBarTintColor"], - ); - options.preferredControlTintColor = UtilColor.fromHex( - map["preferredControlTintColor"], - ); - options.presentationStyle = IOSUIModalPresentationStyle.fromNativeValue( - map["presentationStyle"], - )!; - options.transitionStyle = IOSUIModalTransitionStyle.fromNativeValue( - map["transitionStyle"], - )!; - return options; - } - - @override - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } - - @override - IOSSafariOptions copy() { - return IOSSafariOptions.fromMap(this.toMap()); - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_action_button.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_action_button.dart deleted file mode 100644 index 5b51ea7a19..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_action_button.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'dart:typed_data'; - -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; - -import 'platform_chrome_safari_browser.dart'; -import 'chrome_safari_browser_menu_item.dart'; -import '../web_uri.dart'; -import '../types/enum_method.dart'; - -part 'chrome_safari_action_button.g.dart'; - -///Class that represents a custom action button for a [PlatformChromeSafariBrowser] instance. -@SupportedPlatforms( - platforms: [ - AndroidPlatform(note: 'Not available in an Android Trusted Web Activity.'), - ], -) -@ExchangeableObject() -class ChromeSafariBrowserActionButton_ { - ///The action button id. It should be different from the [ChromeSafariBrowserMenuItem.id]. - int id; - - ///The icon byte data. - Uint8List icon; - - ///The description for the button. To be used for accessibility. - String description; - - ///Whether the action button should be tinted. - bool shouldTint; - - ///Use onClick instead. - @Deprecated("Use onClick instead") - void Function(String url, String title)? action; - - ///Callback function to be invoked when the action button is clicked - void Function(WebUri? url, String title)? onClick; - - @ExchangeableObjectConstructor() - ChromeSafariBrowserActionButton_({ - required this.id, - required this.icon, - required this.description, - @Deprecated("Use onClick instead") this.action, - this.onClick, - this.shouldTint = false, - }); -} diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_action_button.g.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_action_button.g.dart deleted file mode 100644 index 4d7e291e38..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_action_button.g.dart +++ /dev/null @@ -1,85 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'chrome_safari_action_button.dart'; - -// ************************************************************************** -// ExchangeableObjectGenerator -// ************************************************************************** - -///Class that represents a custom action button for a [PlatformChromeSafariBrowser] instance. -/// -///**Officially Supported Platforms/Implementations**: -///- Android WebView: -/// - Not available in an Android Trusted Web Activity. -class ChromeSafariBrowserActionButton { - ///Use onClick instead. - @Deprecated('Use onClick instead') - void Function(String, String)? action; - - ///The description for the button. To be used for accessibility. - String description; - - ///The icon byte data. - Uint8List icon; - - ///The action button id. It should be different from the [ChromeSafariBrowserMenuItem.id]. - int id; - - ///Callback function to be invoked when the action button is clicked - void Function(WebUri?, String)? onClick; - - ///Whether the action button should be tinted. - bool shouldTint; - - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView: - /// - Not available in an Android Trusted Web Activity. - ChromeSafariBrowserActionButton({ - required this.id, - required this.icon, - required this.description, - @Deprecated("Use onClick instead") this.action, - this.onClick, - this.shouldTint = false, - }); - - ///Gets a possible [ChromeSafariBrowserActionButton] instance from a [Map] value. - static ChromeSafariBrowserActionButton? fromMap( - Map? map, { - EnumMethod? enumMethod, - }) { - if (map == null) { - return null; - } - final instance = ChromeSafariBrowserActionButton( - description: map['description'], - icon: Uint8List.fromList(map['icon'].cast()), - id: map['id'], - ); - if (map['shouldTint'] != null) { - instance.shouldTint = map['shouldTint']; - } - return instance; - } - - ///Converts instance to a map. - Map toMap({EnumMethod? enumMethod}) { - return { - "description": description, - "icon": icon, - "id": id, - "shouldTint": shouldTint, - }; - } - - ///Converts instance to a map. - Map toJson() { - return toMap(); - } - - @override - String toString() { - return 'ChromeSafariBrowserActionButton{description: $description, icon: $icon, id: $id, shouldTint: $shouldTint}'; - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_menu_item.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_menu_item.dart deleted file mode 100644 index 0a676ee18b..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_menu_item.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; - -import '../types/ui_image.dart'; -import 'platform_chrome_safari_browser.dart'; -import '../web_uri.dart'; -import '../types/enum_method.dart'; - -part 'chrome_safari_browser_menu_item.g.dart'; - -///Class that represents a custom menu item for a [PlatformChromeSafariBrowser] instance. -@SupportedPlatforms( - platforms: [ - AndroidPlatform(note: 'Not available in an Android Trusted Web Activity.'), - IOSPlatform(), - ], -) -@ExchangeableObject() -class ChromeSafariBrowserMenuItem_ { - ///The menu item id. It should be different from [ChromeSafariBrowserActionButton.id]. - int id; - - ///The label of the menu item. - String label; - - ///Item image. - UIImage_? image; - - ///Use onClick instead. - @Deprecated("Use onClick instead") - void Function(String url, String title)? action; - - ///Callback function to be invoked when the menu item is clicked - void Function(WebUri? url, String title)? onClick; - - @ExchangeableObjectConstructor() - ChromeSafariBrowserMenuItem_({ - required this.id, - required this.label, - this.image, - @Deprecated("Use onClick instead") this.action, - this.onClick, - }); -} diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_menu_item.g.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_menu_item.g.dart deleted file mode 100644 index bb75ec113a..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_menu_item.g.dart +++ /dev/null @@ -1,82 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'chrome_safari_browser_menu_item.dart'; - -// ************************************************************************** -// ExchangeableObjectGenerator -// ************************************************************************** - -///Class that represents a custom menu item for a [PlatformChromeSafariBrowser] instance. -/// -///**Officially Supported Platforms/Implementations**: -///- Android WebView: -/// - Not available in an Android Trusted Web Activity. -///- iOS WKWebView -class ChromeSafariBrowserMenuItem { - ///Use onClick instead. - @Deprecated('Use onClick instead') - void Function(String, String)? action; - - ///The menu item id. It should be different from [ChromeSafariBrowserActionButton.id]. - int id; - - ///Item image. - UIImage? image; - - ///The label of the menu item. - String label; - - ///Callback function to be invoked when the menu item is clicked - void Function(WebUri?, String)? onClick; - - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView: - /// - Not available in an Android Trusted Web Activity. - ///- iOS WKWebView - ChromeSafariBrowserMenuItem({ - required this.id, - required this.label, - this.image, - @Deprecated("Use onClick instead") this.action, - this.onClick, - }); - - ///Gets a possible [ChromeSafariBrowserMenuItem] instance from a [Map] value. - static ChromeSafariBrowserMenuItem? fromMap( - Map? map, { - EnumMethod? enumMethod, - }) { - if (map == null) { - return null; - } - final instance = ChromeSafariBrowserMenuItem( - id: map['id'], - image: UIImage.fromMap( - map['image']?.cast(), - enumMethod: enumMethod, - ), - label: map['label'], - ); - return instance; - } - - ///Converts instance to a map. - Map toMap({EnumMethod? enumMethod}) { - return { - "id": id, - "image": image?.toMap(enumMethod: enumMethod), - "label": label, - }; - } - - ///Converts instance to a map. - Map toJson() { - return toMap(); - } - - @override - String toString() { - return 'ChromeSafariBrowserMenuItem{id: $id, image: $image, label: $label}'; - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.dart deleted file mode 100644 index 5c05c7ad8e..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; - -import '../types/android_resource.dart'; -import '../web_uri.dart'; -import 'platform_chrome_safari_browser.dart'; -import '../types/enum_method.dart'; - -part 'chrome_safari_browser_secondary_toolbar.g.dart'; - -///Class that represents the [RemoteViews](https://developer.android.com/reference/android/widget/RemoteViews.html) -///that will be shown on the secondary toolbar of a custom tab. -/// -///This class describes a view hierarchy that can be displayed in another process. -///The hierarchy is inflated from an Android layout resource file. -/// -///RemoteViews has limited to support to Android layouts. -///Check the [RemoteViews Official API](https://developer.android.com/reference/android/widget/RemoteViews.html) for more details. -@SupportedPlatforms( - platforms: [ - AndroidPlatform(note: 'Not available in an Android Trusted Web Activity.'), - ], -) -@ExchangeableObject() -class ChromeSafariBrowserSecondaryToolbar_ { - ///The android layout resource. - AndroidResource_ layout; - - ///The IDs of clickable views. The `onClick` event of these views will be handled by custom tabs. - List clickableIDs; - - ChromeSafariBrowserSecondaryToolbar_({ - required this.layout, - this.clickableIDs = const [], - }); -} - -///Class that represents a clickable ID item of the secondary toolbar for a [PlatformChromeSafariBrowser] instance. -@SupportedPlatforms( - platforms: [ - AndroidPlatform(note: 'Not available in an Android Trusted Web Activity.'), - ], -) -@ExchangeableObject() -class ChromeSafariBrowserSecondaryToolbarClickableID_ { - ///The android id resource - AndroidResource_ id; - - ///Callback function to be invoked when the item is clicked - void Function(WebUri? url)? onClick; - - ChromeSafariBrowserSecondaryToolbarClickableID_({ - required this.id, - this.onClick, - }); -} diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.g.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.g.dart deleted file mode 100644 index e09633b93d..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.g.dart +++ /dev/null @@ -1,138 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'chrome_safari_browser_secondary_toolbar.dart'; - -// ************************************************************************** -// ExchangeableObjectGenerator -// ************************************************************************** - -///Class that represents the [RemoteViews](https://developer.android.com/reference/android/widget/RemoteViews.html) -///that will be shown on the secondary toolbar of a custom tab. -/// -///This class describes a view hierarchy that can be displayed in another process. -///The hierarchy is inflated from an Android layout resource file. -/// -///RemoteViews has limited to support to Android layouts. -///Check the [RemoteViews Official API](https://developer.android.com/reference/android/widget/RemoteViews.html) for more details. -/// -///**Officially Supported Platforms/Implementations**: -///- Android WebView: -/// - Not available in an Android Trusted Web Activity. -class ChromeSafariBrowserSecondaryToolbar { - ///The IDs of clickable views. The `onClick` event of these views will be handled by custom tabs. - List clickableIDs; - - ///The android layout resource. - AndroidResource layout; - - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView: - /// - Not available in an Android Trusted Web Activity. - ChromeSafariBrowserSecondaryToolbar({ - this.clickableIDs = const [], - required this.layout, - }); - - ///Gets a possible [ChromeSafariBrowserSecondaryToolbar] instance from a [Map] value. - static ChromeSafariBrowserSecondaryToolbar? fromMap( - Map? map, { - EnumMethod? enumMethod, - }) { - if (map == null) { - return null; - } - final instance = ChromeSafariBrowserSecondaryToolbar( - layout: AndroidResource.fromMap( - map['layout']?.cast(), - enumMethod: enumMethod, - )!, - ); - if (map['clickableIDs'] != null) { - instance.clickableIDs = - List.from( - map['clickableIDs'].map( - (e) => ChromeSafariBrowserSecondaryToolbarClickableID.fromMap( - e?.cast(), - enumMethod: enumMethod, - )!, - ), - ); - } - return instance; - } - - ///Converts instance to a map. - Map toMap({EnumMethod? enumMethod}) { - return { - "clickableIDs": clickableIDs - .map((e) => e.toMap(enumMethod: enumMethod)) - .toList(), - "layout": layout.toMap(enumMethod: enumMethod), - }; - } - - ///Converts instance to a map. - Map toJson() { - return toMap(); - } - - @override - String toString() { - return 'ChromeSafariBrowserSecondaryToolbar{clickableIDs: $clickableIDs, layout: $layout}'; - } -} - -///Class that represents a clickable ID item of the secondary toolbar for a [PlatformChromeSafariBrowser] instance. -/// -///**Officially Supported Platforms/Implementations**: -///- Android WebView: -/// - Not available in an Android Trusted Web Activity. -class ChromeSafariBrowserSecondaryToolbarClickableID { - ///The android id resource - AndroidResource id; - - ///Callback function to be invoked when the item is clicked - void Function(WebUri?)? onClick; - - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView: - /// - Not available in an Android Trusted Web Activity. - ChromeSafariBrowserSecondaryToolbarClickableID({ - required this.id, - this.onClick, - }); - - ///Gets a possible [ChromeSafariBrowserSecondaryToolbarClickableID] instance from a [Map] value. - static ChromeSafariBrowserSecondaryToolbarClickableID? fromMap( - Map? map, { - EnumMethod? enumMethod, - }) { - if (map == null) { - return null; - } - final instance = ChromeSafariBrowserSecondaryToolbarClickableID( - id: AndroidResource.fromMap( - map['id']?.cast(), - enumMethod: enumMethod, - )!, - ); - return instance; - } - - ///Converts instance to a map. - Map toMap({EnumMethod? enumMethod}) { - return {"id": id.toMap(enumMethod: enumMethod)}; - } - - ///Converts instance to a map. - Map toJson() { - return toMap(); - } - - @override - String toString() { - return 'ChromeSafariBrowserSecondaryToolbarClickableID{id: $id}'; - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_settings.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_settings.dart deleted file mode 100755 index 35a3055544..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_settings.dart +++ /dev/null @@ -1,337 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; - -import '../types/activity_button.dart'; -import '../types/android_resource.dart'; -import '../types/custom_tabs_share_state.dart'; -import '../types/dismiss_button_style.dart'; -import '../types/main.dart'; -import '../types/modal_presentation_style.dart'; -import '../types/modal_transition_style.dart'; -import '../types/trusted_web_activity_display_mode.dart'; -import '../types/trusted_web_activity_screen_orientation.dart'; -import '../types/ui_event_attribution.dart'; -import '../util.dart'; -import 'android/chrome_custom_tabs_options.dart'; -import 'apple/safari_options.dart'; - -part 'chrome_safari_browser_settings.g.dart'; - -TrustedWebActivityDisplayMode? _deserializeDisplayMode( - Map? displayMode, { - EnumMethod? enumMethod, -}) { - if (displayMode == null) { - return null; - } - switch (displayMode["type"]) { - case "IMMERSIVE_MODE": - return TrustedWebActivityImmersiveDisplayMode.fromMap( - displayMode, - enumMethod: enumMethod, - ); - case "DEFAULT_MODE": - default: - return TrustedWebActivityDefaultDisplayMode(); - } -} - -class ChromeSafariBrowserOptions { - Map toMap() { - return {}; - } - - static ChromeSafariBrowserOptions fromMap(Map map) { - return new ChromeSafariBrowserOptions(); - } - - ChromeSafariBrowserOptions copy() { - return ChromeSafariBrowserOptions.fromMap(this.toMap()); - } - - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } -} - -///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings} -///Class that represents the settings that can be used for an [ChromeSafariBrowser] window. -///{@endtemplate} -/// -///{@macro flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.supported_platforms} -@SupportedPlatforms( - platforms: [ - AndroidPlatform(name: 'Android Chrome Custom Tabs'), - IOSPlatform(name: 'iOS SFSafariViewController'), - ], -) -@ExchangeableObject(copyMethod: true) -class ChromeSafariBrowserSettings_ implements ChromeSafariBrowserOptions { - ///The share state that should be applied to the custom tab. The default value is [CustomTabsShareState.SHARE_STATE_DEFAULT]. - @SupportedPlatforms( - platforms: [ - AndroidPlatform(note: 'Not available in a Trusted Web Activity.'), - ], - ) - CustomTabsShareState_? shareState; - - ///Set to `false` if the title shouldn't be shown in the custom tab. The default value is `true`. - @SupportedPlatforms( - platforms: [ - AndroidPlatform(note: 'Not available in a Trusted Web Activity.'), - ], - ) - bool? showTitle; - - ///Set the custom background color of the toolbar. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - Color_? toolbarBackgroundColor; - - ///Sets the navigation bar color. Has no effect on Android API versions below L. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - Color_? navigationBarColor; - - ///Sets the navigation bar divider color. Has no effect on Android API versions below P. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - Color_? navigationBarDividerColor; - - ///Sets the color of the secondary toolbar. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - Color_? secondaryToolbarColor; - - ///Set to `true` to enable the url bar to hide as the user scrolls down on the page. The default value is `false`. - @SupportedPlatforms( - platforms: [ - AndroidPlatform(note: 'Not available in a Trusted Web Activity.'), - ], - ) - bool? enableUrlBarHiding; - - ///Set to `true` to enable Instant Apps. The default value is `false`. - @SupportedPlatforms( - platforms: [ - AndroidPlatform(note: 'Not available in a Trusted Web Activity.'), - ], - ) - bool? instantAppsEnabled; - - ///Set an explicit application package name that limits - ///the components this Intent will resolve to. If left to the default - ///value of null, all components in all applications will considered. - ///If non-null, the Intent can only match the components in the given - ///application package. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - String? packageName; - - ///Set to `true` to enable Keep Alive. The default value is `false`. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - bool? keepAliveEnabled; - - ///Set to `true` to launch the Android activity in `singleInstance` mode. The default value is `false`. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - bool? isSingleInstance; - - ///Set to `true` to launch the Android intent with the flag `FLAG_ACTIVITY_NO_HISTORY`. The default value is `false`. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - bool? noHistory; - - ///Set to `true` to launch the Custom Tab as a Trusted Web Activity. The default value is `false`. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - bool? isTrustedWebActivity; - - ///Sets a list of additional trusted origins that the user may navigate or be redirected to from the starting uri. - @SupportedPlatforms( - platforms: [ - AndroidPlatform(note: 'Not available in a Trusted Web Activity.'), - ], - ) - List? additionalTrustedOrigins; - - ///Sets a display mode of a Trusted Web Activity. - @SupportedPlatforms( - platforms: [ - AndroidPlatform(note: 'Not available in a Trusted Web Activity.'), - ], - ) - @ExchangeableObjectProperty(deserializer: _deserializeDisplayMode) - TrustedWebActivityDisplayMode_? displayMode; - - ///Sets a screen orientation. This can be used e.g. to enable the locking of an orientation lock type. - @SupportedPlatforms( - platforms: [ - AndroidPlatform(note: 'Not available in a Trusted Web Activity.'), - ], - ) - TrustedWebActivityScreenOrientation_? screenOrientation; - - ///Sets the start animations. - ///It must contain 2 [AndroidResource], where the first one represents the "enter" animation for the browser - ///and the second one represents the "exit" animation for the application. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - List? startAnimations; - - ///Sets the exit animations. - ///It must contain 2 [AndroidResource], where the first one represents the "enter" animation for the application - ///and the second one represents the "exit" animation for the browser. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - List? exitAnimations; - - ///Adds the necessary flags and extras to signal any browser supporting custom tabs to use the browser UI - ///at all times and avoid showing custom tab like UI. - ///Calling this with an intent will override any custom tabs related customizations. - ///The default value is `false`. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - bool? alwaysUseBrowserUI; - - ///Set to `true` if Reader mode should be entered automatically when it is available for the webpage. The default value is `false`. - @SupportedPlatforms(platforms: [IOSPlatform()]) - bool? entersReaderIfAvailable; - - ///Set to `true` to enable bar collapsing. The default value is `false`. - @SupportedPlatforms(platforms: [IOSPlatform()]) - bool? barCollapsingEnabled; - - ///Set the custom style for the dismiss button. The default value is [DismissButtonStyle.DONE]. - @SupportedPlatforms(platforms: [IOSPlatform(available: '11.0')]) - DismissButtonStyle_? dismissButtonStyle; - - ///Set the custom background color of the navigation bar and the toolbar. - @SupportedPlatforms(platforms: [IOSPlatform(available: '10.0')]) - Color_? preferredBarTintColor; - - ///Set the custom color of the control buttons on the navigation bar and the toolbar. - @SupportedPlatforms(platforms: [IOSPlatform(available: '10.0')]) - Color_? preferredControlTintColor; - - ///Set the custom modal presentation style when presenting the WebView. The default value is [ModalPresentationStyle.FULL_SCREEN]. - @SupportedPlatforms(platforms: [IOSPlatform()]) - ModalPresentationStyle_? presentationStyle; - - ///Set to the custom transition style when presenting the WebView. The default value is [ModalTransitionStyle.COVER_VERTICAL]. - @SupportedPlatforms(platforms: [IOSPlatform()]) - ModalTransitionStyle_? transitionStyle; - - ///An additional button to be shown in `SFSafariViewController`'s toolbar. - ///This allows the user to access powerful functionality from your extension without needing to first show the `UIActivityViewController`. - @SupportedPlatforms(platforms: [IOSPlatform(available: '15.0')]) - ActivityButton_? activityButton; - - ///An event attribution associated with a click that caused this `SFSafariViewController` to be opened. - ///This attribute is ignored if the `SFSafariViewController` url has a scheme of 'http'. - @SupportedPlatforms(platforms: [IOSPlatform(available: '15.2')]) - UIEventAttribution_? eventAttribution; - - @ExchangeableObjectConstructor() - ChromeSafariBrowserSettings_({ - this.shareState = CustomTabsShareState_.SHARE_STATE_DEFAULT, - this.showTitle = true, - this.toolbarBackgroundColor, - this.navigationBarColor, - this.navigationBarDividerColor, - this.secondaryToolbarColor, - this.enableUrlBarHiding = false, - this.instantAppsEnabled = false, - this.packageName, - this.keepAliveEnabled = false, - this.isSingleInstance = false, - this.noHistory = false, - this.isTrustedWebActivity = false, - this.additionalTrustedOrigins = const [], - this.displayMode, - this.screenOrientation = TrustedWebActivityScreenOrientation_.DEFAULT, - this.startAnimations, - this.exitAnimations, - this.alwaysUseBrowserUI = false, - this.entersReaderIfAvailable = false, - this.barCollapsingEnabled = false, - this.dismissButtonStyle = DismissButtonStyle_.DONE, - this.preferredBarTintColor, - this.preferredControlTintColor, - this.presentationStyle = ModalPresentationStyle_.FULL_SCREEN, - this.transitionStyle = ModalTransitionStyle_.COVER_VERTICAL, - this.activityButton, - this.eventAttribution, - }) { - if (startAnimations != null) { - assert( - startAnimations!.length == 2, - "start animations must be have 2 android resources", - ); - } - if (exitAnimations != null) { - assert( - exitAnimations!.length == 2, - "exit animations must be have 2 android resources", - ); - } - } - - @override - @ExchangeableObjectMethod(ignore: true) - ChromeSafariBrowserSettings_ copy() { - throw UnimplementedError(); - } - - @override - @ExchangeableObjectMethod(ignore: true) - Map toJson() { - throw UnimplementedError(); - } - - @override - @ExchangeableObjectMethod(ignore: true) - Map toMap() { - throw UnimplementedError(); - } - - ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. - static bool isPropertySupported( - ChromeSafariBrowserSettingsProperty property, { - TargetPlatform? platform, - }) => _ChromeSafariBrowserSettingsPropertySupported.isPropertySupported( - property, - platform: platform, - ); -} - -///Class that represents the options that can be used for an [ChromeSafariBrowser] window. -///Use [ChromeSafariBrowserSettings] instead. -@Deprecated('Use ChromeSafariBrowserSettings instead') -class ChromeSafariBrowserClassOptions { - ///Android-specific options. - AndroidChromeCustomTabsOptions? android; - - ///iOS-specific options. - IOSSafariOptions? ios; - - ChromeSafariBrowserClassOptions({this.android, this.ios}) { - this.android = this.android ?? AndroidChromeCustomTabsOptions(); - this.ios = this.ios ?? IOSSafariOptions(); - } - - Map toMap() { - Map options = {}; - if (Util.isAndroid) - options.addAll(this.android?.toMap() ?? {}); - else if (Util.isIOS) - options.addAll(this.ios?.toMap() ?? {}); - - return options; - } - - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_settings.g.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_settings.g.dart deleted file mode 100644 index 04aeb3bdf9..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_settings.g.dart +++ /dev/null @@ -1,918 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'chrome_safari_browser_settings.dart'; - -// ************************************************************************** -// ExchangeableObjectGenerator -// ************************************************************************** - -///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings} -///Class that represents the settings that can be used for an [ChromeSafariBrowser] window. -///{@endtemplate} -/// -///{@macro flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.supported_platforms} -/// -///**Officially Supported Platforms/Implementations**: -///- Android Chrome Custom Tabs -///- iOS SFSafariViewController -class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions { - ///An additional button to be shown in `SFSafariViewController`'s toolbar. - ///This allows the user to access powerful functionality from your extension without needing to first show the `UIActivityViewController`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController 15.0+ - ActivityButton? activityButton; - - ///Sets a list of additional trusted origins that the user may navigate or be redirected to from the starting uri. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - List? additionalTrustedOrigins; - - ///Adds the necessary flags and extras to signal any browser supporting custom tabs to use the browser UI - ///at all times and avoid showing custom tab like UI. - ///Calling this with an intent will override any custom tabs related customizations. - ///The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - bool? alwaysUseBrowserUI; - - ///Set to `true` to enable bar collapsing. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController - bool? barCollapsingEnabled; - - ///Set the custom style for the dismiss button. The default value is [DismissButtonStyle.DONE]. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController 11.0+ - DismissButtonStyle? dismissButtonStyle; - - ///Sets a display mode of a Trusted Web Activity. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - TrustedWebActivityDisplayMode? displayMode; - - ///Set to `true` to enable the url bar to hide as the user scrolls down on the page. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - bool? enableUrlBarHiding; - - ///Set to `true` if Reader mode should be entered automatically when it is available for the webpage. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController - bool? entersReaderIfAvailable; - - ///An event attribution associated with a click that caused this `SFSafariViewController` to be opened. - ///This attribute is ignored if the `SFSafariViewController` url has a scheme of 'http'. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController 15.2+ - UIEventAttribution? eventAttribution; - - ///Sets the exit animations. - ///It must contain 2 [AndroidResource], where the first one represents the "enter" animation for the application - ///and the second one represents the "exit" animation for the browser. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - List? exitAnimations; - - ///Set to `true` to enable Instant Apps. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - bool? instantAppsEnabled; - - ///Set to `true` to launch the Android activity in `singleInstance` mode. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - bool? isSingleInstance; - - ///Set to `true` to launch the Custom Tab as a Trusted Web Activity. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - bool? isTrustedWebActivity; - - ///Set to `true` to enable Keep Alive. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - bool? keepAliveEnabled; - - ///Sets the navigation bar color. Has no effect on Android API versions below L. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - Color? navigationBarColor; - - ///Sets the navigation bar divider color. Has no effect on Android API versions below P. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - Color? navigationBarDividerColor; - - ///Set to `true` to launch the Android intent with the flag `FLAG_ACTIVITY_NO_HISTORY`. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - bool? noHistory; - - ///Set an explicit application package name that limits - ///the components this Intent will resolve to. If left to the default - ///value of null, all components in all applications will considered. - ///If non-null, the Intent can only match the components in the given - ///application package. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - String? packageName; - - ///Set the custom background color of the navigation bar and the toolbar. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController 10.0+ - Color? preferredBarTintColor; - - ///Set the custom color of the control buttons on the navigation bar and the toolbar. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController 10.0+ - Color? preferredControlTintColor; - - ///Set the custom modal presentation style when presenting the WebView. The default value is [ModalPresentationStyle.FULL_SCREEN]. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController - ModalPresentationStyle? presentationStyle; - - ///Sets a screen orientation. This can be used e.g. to enable the locking of an orientation lock type. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - TrustedWebActivityScreenOrientation? screenOrientation; - - ///Sets the color of the secondary toolbar. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - Color? secondaryToolbarColor; - - ///The share state that should be applied to the custom tab. The default value is [CustomTabsShareState.SHARE_STATE_DEFAULT]. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - CustomTabsShareState? shareState; - - ///Set to `false` if the title shouldn't be shown in the custom tab. The default value is `true`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - bool? showTitle; - - ///Sets the start animations. - ///It must contain 2 [AndroidResource], where the first one represents the "enter" animation for the browser - ///and the second one represents the "exit" animation for the application. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - List? startAnimations; - - ///Set the custom background color of the toolbar. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - Color? toolbarBackgroundColor; - - ///Set to the custom transition style when presenting the WebView. The default value is [ModalTransitionStyle.COVER_VERTICAL]. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController - ModalTransitionStyle? transitionStyle; - - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - ///- iOS SFSafariViewController - ChromeSafariBrowserSettings({ - this.shareState = CustomTabsShareState.SHARE_STATE_DEFAULT, - this.showTitle = true, - this.toolbarBackgroundColor, - this.navigationBarColor, - this.navigationBarDividerColor, - this.secondaryToolbarColor, - this.enableUrlBarHiding = false, - this.instantAppsEnabled = false, - this.packageName, - this.keepAliveEnabled = false, - this.isSingleInstance = false, - this.noHistory = false, - this.isTrustedWebActivity = false, - this.additionalTrustedOrigins = const [], - this.displayMode, - this.screenOrientation = TrustedWebActivityScreenOrientation.DEFAULT, - this.startAnimations, - this.exitAnimations, - this.alwaysUseBrowserUI = false, - this.entersReaderIfAvailable = false, - this.barCollapsingEnabled = false, - this.dismissButtonStyle = DismissButtonStyle.DONE, - this.preferredBarTintColor, - this.preferredControlTintColor, - this.presentationStyle = ModalPresentationStyle.FULL_SCREEN, - this.transitionStyle = ModalTransitionStyle.COVER_VERTICAL, - this.activityButton, - this.eventAttribution, - }) { - if (startAnimations != null) { - assert( - startAnimations!.length == 2, - "start animations must be have 2 android resources", - ); - } - if (exitAnimations != null) { - assert( - exitAnimations!.length == 2, - "exit animations must be have 2 android resources", - ); - } - } - - ///Gets a possible [ChromeSafariBrowserSettings] instance from a [Map] value. - static ChromeSafariBrowserSettings? fromMap( - Map? map, { - EnumMethod? enumMethod, - }) { - if (map == null) { - return null; - } - final instance = ChromeSafariBrowserSettings( - activityButton: ActivityButton.fromMap( - map['activityButton']?.cast(), - enumMethod: enumMethod, - ), - displayMode: _deserializeDisplayMode( - map['displayMode'], - enumMethod: enumMethod, - ), - eventAttribution: UIEventAttribution.fromMap( - map['eventAttribution']?.cast(), - enumMethod: enumMethod, - ), - exitAnimations: map['exitAnimations'] != null - ? List.from( - map['exitAnimations'].map( - (e) => AndroidResource.fromMap( - e?.cast(), - enumMethod: enumMethod, - )!, - ), - ) - : null, - navigationBarColor: map['navigationBarColor'] != null - ? UtilColor.fromStringRepresentation(map['navigationBarColor']) - : null, - navigationBarDividerColor: map['navigationBarDividerColor'] != null - ? UtilColor.fromStringRepresentation(map['navigationBarDividerColor']) - : null, - packageName: map['packageName'], - preferredBarTintColor: map['preferredBarTintColor'] != null - ? UtilColor.fromStringRepresentation(map['preferredBarTintColor']) - : null, - preferredControlTintColor: map['preferredControlTintColor'] != null - ? UtilColor.fromStringRepresentation(map['preferredControlTintColor']) - : null, - secondaryToolbarColor: map['secondaryToolbarColor'] != null - ? UtilColor.fromStringRepresentation(map['secondaryToolbarColor']) - : null, - startAnimations: map['startAnimations'] != null - ? List.from( - map['startAnimations'].map( - (e) => AndroidResource.fromMap( - e?.cast(), - enumMethod: enumMethod, - )!, - ), - ) - : null, - toolbarBackgroundColor: map['toolbarBackgroundColor'] != null - ? UtilColor.fromStringRepresentation(map['toolbarBackgroundColor']) - : null, - ); - instance.additionalTrustedOrigins = map['additionalTrustedOrigins'] != null - ? List.from(map['additionalTrustedOrigins']!.cast()) - : null; - instance.alwaysUseBrowserUI = map['alwaysUseBrowserUI']; - instance.barCollapsingEnabled = map['barCollapsingEnabled']; - instance.dismissButtonStyle = switch (enumMethod ?? - EnumMethod.nativeValue) { - EnumMethod.nativeValue => DismissButtonStyle.fromNativeValue( - map['dismissButtonStyle'], - ), - EnumMethod.value => DismissButtonStyle.fromValue( - map['dismissButtonStyle'], - ), - EnumMethod.name => DismissButtonStyle.byName(map['dismissButtonStyle']), - }; - instance.enableUrlBarHiding = map['enableUrlBarHiding']; - instance.entersReaderIfAvailable = map['entersReaderIfAvailable']; - instance.instantAppsEnabled = map['instantAppsEnabled']; - instance.isSingleInstance = map['isSingleInstance']; - instance.isTrustedWebActivity = map['isTrustedWebActivity']; - instance.keepAliveEnabled = map['keepAliveEnabled']; - instance.noHistory = map['noHistory']; - instance.presentationStyle = switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => ModalPresentationStyle.fromNativeValue( - map['presentationStyle'], - ), - EnumMethod.value => ModalPresentationStyle.fromValue( - map['presentationStyle'], - ), - EnumMethod.name => ModalPresentationStyle.byName( - map['presentationStyle'], - ), - }; - instance.screenOrientation = switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => - TrustedWebActivityScreenOrientation.fromNativeValue( - map['screenOrientation'], - ), - EnumMethod.value => TrustedWebActivityScreenOrientation.fromValue( - map['screenOrientation'], - ), - EnumMethod.name => TrustedWebActivityScreenOrientation.byName( - map['screenOrientation'], - ), - }; - instance.shareState = switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => CustomTabsShareState.fromNativeValue( - map['shareState'], - ), - EnumMethod.value => CustomTabsShareState.fromValue(map['shareState']), - EnumMethod.name => CustomTabsShareState.byName(map['shareState']), - }; - instance.showTitle = map['showTitle']; - instance.transitionStyle = switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => ModalTransitionStyle.fromNativeValue( - map['transitionStyle'], - ), - EnumMethod.value => ModalTransitionStyle.fromValue( - map['transitionStyle'], - ), - EnumMethod.name => ModalTransitionStyle.byName(map['transitionStyle']), - }; - return instance; - } - - ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. - static bool isPropertySupported( - ChromeSafariBrowserSettingsProperty property, { - TargetPlatform? platform, - }) => _ChromeSafariBrowserSettingsPropertySupported.isPropertySupported( - property, - platform: platform, - ); - - ///Converts instance to a map. - Map toMap({EnumMethod? enumMethod}) { - return { - "activityButton": activityButton?.toMap(enumMethod: enumMethod), - "additionalTrustedOrigins": additionalTrustedOrigins, - "alwaysUseBrowserUI": alwaysUseBrowserUI, - "barCollapsingEnabled": barCollapsingEnabled, - "dismissButtonStyle": switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => dismissButtonStyle?.toNativeValue(), - EnumMethod.value => dismissButtonStyle?.toValue(), - EnumMethod.name => dismissButtonStyle?.name(), - }, - "displayMode": displayMode?.toMap(enumMethod: enumMethod), - "enableUrlBarHiding": enableUrlBarHiding, - "entersReaderIfAvailable": entersReaderIfAvailable, - "eventAttribution": eventAttribution?.toMap(enumMethod: enumMethod), - "exitAnimations": exitAnimations - ?.map((e) => e.toMap(enumMethod: enumMethod)) - .toList(), - "instantAppsEnabled": instantAppsEnabled, - "isSingleInstance": isSingleInstance, - "isTrustedWebActivity": isTrustedWebActivity, - "keepAliveEnabled": keepAliveEnabled, - "navigationBarColor": navigationBarColor?.toHex(), - "navigationBarDividerColor": navigationBarDividerColor?.toHex(), - "noHistory": noHistory, - "packageName": packageName, - "preferredBarTintColor": preferredBarTintColor?.toHex(), - "preferredControlTintColor": preferredControlTintColor?.toHex(), - "presentationStyle": switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => presentationStyle?.toNativeValue(), - EnumMethod.value => presentationStyle?.toValue(), - EnumMethod.name => presentationStyle?.name(), - }, - "screenOrientation": switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => screenOrientation?.toNativeValue(), - EnumMethod.value => screenOrientation?.toValue(), - EnumMethod.name => screenOrientation?.name(), - }, - "secondaryToolbarColor": secondaryToolbarColor?.toHex(), - "shareState": switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => shareState?.toNativeValue(), - EnumMethod.value => shareState?.toValue(), - EnumMethod.name => shareState?.name(), - }, - "showTitle": showTitle, - "startAnimations": startAnimations - ?.map((e) => e.toMap(enumMethod: enumMethod)) - .toList(), - "toolbarBackgroundColor": toolbarBackgroundColor?.toHex(), - "transitionStyle": switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => transitionStyle?.toNativeValue(), - EnumMethod.value => transitionStyle?.toValue(), - EnumMethod.name => transitionStyle?.name(), - }, - }; - } - - ///Converts instance to a map. - Map toJson() { - return toMap(); - } - - ///Returns a copy of ChromeSafariBrowserSettings. - ChromeSafariBrowserSettings copy() { - return ChromeSafariBrowserSettings.fromMap(toMap()) ?? - ChromeSafariBrowserSettings(); - } - - @override - String toString() { - return 'ChromeSafariBrowserSettings{activityButton: $activityButton, additionalTrustedOrigins: $additionalTrustedOrigins, alwaysUseBrowserUI: $alwaysUseBrowserUI, barCollapsingEnabled: $barCollapsingEnabled, dismissButtonStyle: $dismissButtonStyle, displayMode: $displayMode, enableUrlBarHiding: $enableUrlBarHiding, entersReaderIfAvailable: $entersReaderIfAvailable, eventAttribution: $eventAttribution, exitAnimations: $exitAnimations, instantAppsEnabled: $instantAppsEnabled, isSingleInstance: $isSingleInstance, isTrustedWebActivity: $isTrustedWebActivity, keepAliveEnabled: $keepAliveEnabled, navigationBarColor: $navigationBarColor, navigationBarDividerColor: $navigationBarDividerColor, noHistory: $noHistory, packageName: $packageName, preferredBarTintColor: $preferredBarTintColor, preferredControlTintColor: $preferredControlTintColor, presentationStyle: $presentationStyle, screenOrientation: $screenOrientation, secondaryToolbarColor: $secondaryToolbarColor, shareState: $shareState, showTitle: $showTitle, startAnimations: $startAnimations, toolbarBackgroundColor: $toolbarBackgroundColor, transitionStyle: $transitionStyle}'; - } -} - -// ************************************************************************** -// SupportedPlatformsGenerator -// ************************************************************************** - -///List of [ChromeSafariBrowserSettings]'s properties that can be used to check i they are supported or not by the current platform. -enum ChromeSafariBrowserSettingsProperty { - ///Can be used to check if the [ChromeSafariBrowserSettings.activityButton] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.activityButton.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController 15.0+ - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - activityButton, - - ///Can be used to check if the [ChromeSafariBrowserSettings.additionalTrustedOrigins] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.additionalTrustedOrigins.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - additionalTrustedOrigins, - - ///Can be used to check if the [ChromeSafariBrowserSettings.alwaysUseBrowserUI] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.alwaysUseBrowserUI.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - alwaysUseBrowserUI, - - ///Can be used to check if the [ChromeSafariBrowserSettings.barCollapsingEnabled] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.barCollapsingEnabled.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - barCollapsingEnabled, - - ///Can be used to check if the [ChromeSafariBrowserSettings.dismissButtonStyle] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.dismissButtonStyle.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController 11.0+ - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - dismissButtonStyle, - - ///Can be used to check if the [ChromeSafariBrowserSettings.displayMode] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.displayMode.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - displayMode, - - ///Can be used to check if the [ChromeSafariBrowserSettings.enableUrlBarHiding] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.enableUrlBarHiding.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - enableUrlBarHiding, - - ///Can be used to check if the [ChromeSafariBrowserSettings.entersReaderIfAvailable] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.entersReaderIfAvailable.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - entersReaderIfAvailable, - - ///Can be used to check if the [ChromeSafariBrowserSettings.eventAttribution] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.eventAttribution.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController 15.2+ - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - eventAttribution, - - ///Can be used to check if the [ChromeSafariBrowserSettings.exitAnimations] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.exitAnimations.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - exitAnimations, - - ///Can be used to check if the [ChromeSafariBrowserSettings.instantAppsEnabled] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.instantAppsEnabled.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - instantAppsEnabled, - - ///Can be used to check if the [ChromeSafariBrowserSettings.isSingleInstance] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.isSingleInstance.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - isSingleInstance, - - ///Can be used to check if the [ChromeSafariBrowserSettings.isTrustedWebActivity] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.isTrustedWebActivity.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - isTrustedWebActivity, - - ///Can be used to check if the [ChromeSafariBrowserSettings.keepAliveEnabled] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.keepAliveEnabled.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - keepAliveEnabled, - - ///Can be used to check if the [ChromeSafariBrowserSettings.navigationBarColor] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.navigationBarColor.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - navigationBarColor, - - ///Can be used to check if the [ChromeSafariBrowserSettings.navigationBarDividerColor] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.navigationBarDividerColor.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - navigationBarDividerColor, - - ///Can be used to check if the [ChromeSafariBrowserSettings.noHistory] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.noHistory.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - noHistory, - - ///Can be used to check if the [ChromeSafariBrowserSettings.packageName] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.packageName.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - packageName, - - ///Can be used to check if the [ChromeSafariBrowserSettings.preferredBarTintColor] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.preferredBarTintColor.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController 10.0+ - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - preferredBarTintColor, - - ///Can be used to check if the [ChromeSafariBrowserSettings.preferredControlTintColor] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.preferredControlTintColor.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController 10.0+ - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - preferredControlTintColor, - - ///Can be used to check if the [ChromeSafariBrowserSettings.presentationStyle] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.presentationStyle.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - presentationStyle, - - ///Can be used to check if the [ChromeSafariBrowserSettings.screenOrientation] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.screenOrientation.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - screenOrientation, - - ///Can be used to check if the [ChromeSafariBrowserSettings.secondaryToolbarColor] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.secondaryToolbarColor.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - secondaryToolbarColor, - - ///Can be used to check if the [ChromeSafariBrowserSettings.shareState] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.shareState.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - shareState, - - ///Can be used to check if the [ChromeSafariBrowserSettings.showTitle] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.showTitle.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - showTitle, - - ///Can be used to check if the [ChromeSafariBrowserSettings.startAnimations] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.startAnimations.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - startAnimations, - - ///Can be used to check if the [ChromeSafariBrowserSettings.toolbarBackgroundColor] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.toolbarBackgroundColor.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - toolbarBackgroundColor, - - ///Can be used to check if the [ChromeSafariBrowserSettings.transitionStyle] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.ChromeSafariBrowserSettings.transitionStyle.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController - /// - ///Use the [ChromeSafariBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - transitionStyle, -} - -extension _ChromeSafariBrowserSettingsPropertySupported - on ChromeSafariBrowserSettings { - static bool isPropertySupported( - ChromeSafariBrowserSettingsProperty property, { - TargetPlatform? platform, - }) { - switch (property) { - case ChromeSafariBrowserSettingsProperty.activityButton: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.additionalTrustedOrigins: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.alwaysUseBrowserUI: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.barCollapsingEnabled: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.dismissButtonStyle: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.displayMode: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.enableUrlBarHiding: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.entersReaderIfAvailable: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.eventAttribution: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.exitAnimations: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.instantAppsEnabled: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.isSingleInstance: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.isTrustedWebActivity: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.keepAliveEnabled: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.navigationBarColor: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.navigationBarDividerColor: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.noHistory: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.packageName: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.preferredBarTintColor: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.preferredControlTintColor: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.presentationStyle: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.screenOrientation: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.secondaryToolbarColor: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.shareState: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.showTitle: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.startAnimations: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.toolbarBackgroundColor: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case ChromeSafariBrowserSettingsProperty.transitionStyle: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - } - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/main.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/main.dart deleted file mode 100644 index a2c764ce03..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/main.dart +++ /dev/null @@ -1,14 +0,0 @@ -export 'platform_chrome_safari_browser.dart'; -export 'chrome_safari_browser_settings.dart' - show - ChromeSafariBrowserOptions, - ChromeSafariBrowserSettings, - ChromeSafariBrowserClassOptions; -export 'android/main.dart'; -export 'apple/main.dart'; -export 'chrome_safari_action_button.dart' show ChromeSafariBrowserActionButton; -export 'chrome_safari_browser_menu_item.dart' show ChromeSafariBrowserMenuItem; -export 'chrome_safari_browser_secondary_toolbar.dart' - show - ChromeSafariBrowserSecondaryToolbar, - ChromeSafariBrowserSecondaryToolbarClickableID; diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/platform_chrome_safari_browser.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/platform_chrome_safari_browser.dart deleted file mode 100755 index 3e7f44aa83..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/platform_chrome_safari_browser.dart +++ /dev/null @@ -1,883 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; - -part 'platform_chrome_safari_browser.g.dart'; - -/// Object specifying creation parameters for creating a [PlatformChromeSafariBrowser]. -/// -/// Platform specific implementations can add additional fields by extending -/// this class. -@immutable -class PlatformChromeSafariBrowserCreationParams { - /// Used by the platform implementation to create a new [PlatformChromeSafariBrowser]. - const PlatformChromeSafariBrowserCreationParams(); -} - -///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser} -///Class that provides a visible standard interface for browsing the web. -///It presents a self-contained web interface inside your app. -/// -///If you need to customize or interact with the web content, use the `InAppWebView` widget. -///{@endtemplate} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.supported_platforms} -@SupportedPlatforms( - platforms: [ - AndroidPlatform( - note: - """This class uses native [Chrome Custom Tabs](https://developer.android.com/reference/android/support/customtabs/package-summary). -If you want to use the `ChromeSafariBrowser` class on Android 11+ you need to specify your app querying for -`android.support.customtabs.action.CustomTabsService` in your `AndroidManifest.xml` -(you can read more about it here: https://developers.google.com/web/android/custom-tabs/best-practices#applications_targeting_android_11_api_level_30_or_above).""", - name: 'Android Chrome Custom Tabs', - ), - IOSPlatform( - note: - 'This class uses native [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller)', - name: 'iOS SFSafariViewController', - ), - ], -) -abstract class PlatformChromeSafariBrowser extends PlatformInterface - implements Disposable { - ///Debug settings. - static DebugLoggingSettings debugLoggingSettings = DebugLoggingSettings(); - - /// Event handler object that handles the [PlatformChromeSafariBrowser] events. - PlatformChromeSafariBrowserEvents? eventHandler; - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.id} - ///View ID used internally. - ///{@endtemplate} - String get id { - throw UnimplementedError('id is not implemented on the current platform'); - } - - /// Creates a new [PlatformChromeSafariBrowser] - factory PlatformChromeSafariBrowser( - PlatformChromeSafariBrowserCreationParams params, - ) { - assert( - InAppWebViewPlatform.instance != null, - 'A platform implementation for `flutter_inappwebview` has not been set. Please ' - 'ensure that an implementation of `InAppWebViewPlatform` has been set to ' - '`InAppWebViewPlatform.instance` before use. For unit testing, ' - '`InAppWebViewPlatform.instance` can be set with your own test implementation.', - ); - final PlatformChromeSafariBrowser chromeSafariBrowser = InAppWebViewPlatform - .instance! - .createPlatformChromeSafariBrowser(params); - PlatformInterface.verify(chromeSafariBrowser, _token); - return chromeSafariBrowser; - } - - /// Creates a new [PlatformChromeSafariBrowser] to access static methods. - factory PlatformChromeSafariBrowser.static() { - assert( - InAppWebViewPlatform.instance != null, - 'A platform implementation for `flutter_inappwebview` has not been set. Please ' - 'ensure that an implementation of `InAppWebViewPlatform` has been set to ' - '`InAppWebViewPlatform.instance` before use. For unit testing, ' - '`InAppWebViewPlatform.instance` can be set with your own test implementation.', - ); - final PlatformChromeSafariBrowser chromeSafariBrowserStatic = - InAppWebViewPlatform.instance! - .createPlatformChromeSafariBrowserStatic(); - PlatformInterface.verify(chromeSafariBrowserStatic, _token); - return chromeSafariBrowserStatic; - } - - /// Used by the platform implementation to create a new [PlatformChromeSafariBrowser]. - /// - /// Should only be used by platform implementations because they can't extend - /// a class that only contains a factory constructor. - @protected - PlatformChromeSafariBrowser.implementation(this.params) - : super(token: _token); - - static final Object _token = Object(); - - /// The parameters used to initialize the [PlatformChromeSafariBrowser]. - final PlatformChromeSafariBrowserCreationParams params; - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.open} - ///Opens the [PlatformChromeSafariBrowser] instance with an [url]. - /// - ///[url] - The [url] to load. On iOS, the [url] is required and must use the `http` or `https` scheme. - /// - ///[headers] - [whitelisted](https://fetch.spec.whatwg.org/#cors-safelisted-request-header) cross-origin request headers. - ///It is possible to attach non-whitelisted headers to cross-origin requests, when the server and client are related using a - ///[digital asset link](https://developers.google.com/digital-asset-links/v1/getting-started). - /// - ///[otherLikelyURLs] - Other likely destinations, sorted in decreasing likelihood order. - /// - ///[referrer] - referrer header. - /// - ///[options] - Deprecated. Use `settings` instead. - /// - ///[settings] - Settings for the [PlatformChromeSafariBrowser]. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.open.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform(), IOSPlatform()]) - Future open({ - WebUri? url, - @SupportedPlatforms(platforms: [AndroidPlatform()]) - Map? headers, - @SupportedPlatforms(platforms: [AndroidPlatform()]) - List? otherLikelyURLs, - @SupportedPlatforms(platforms: [AndroidPlatform()]) WebUri? referrer, - @Deprecated('Use settings instead') - // ignore: deprecated_member_use_from_same_package - ChromeSafariBrowserClassOptions? options, - ChromeSafariBrowserSettings? settings, - }) { - throw UnimplementedError('open is not implemented on the current platform'); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.launchUrl} - ///Tells the browser to launch with [url]. - /// - ///[url] - initial url. - /// - ///[headers] - [whitelisted](https://fetch.spec.whatwg.org/#cors-safelisted-request-header) cross-origin request headers. - ///It is possible to attach non-whitelisted headers to cross-origin requests, when the server and client are related using a - ///[digital asset link](https://developers.google.com/digital-asset-links/v1/getting-started). - /// - ///[otherLikelyURLs] - Other likely destinations, sorted in decreasing likelihood order. - /// - ///[referrer] - referrer header. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.launchUrl.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - Future launchUrl({ - required WebUri url, - Map? headers, - List? otherLikelyURLs, - WebUri? referrer, - }) { - throw UnimplementedError( - 'launchUrl is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.mayLaunchUrl} - ///Tells the browser of a likely future navigation to a URL. - ///The most likely URL has to be specified first. - ///Optionally, a list of other likely URLs can be provided. - ///They are treated as less likely than the first one, and have to be sorted in decreasing priority order. - ///These additional URLs may be ignored. All previous calls to this method will be deprioritized. - /// - ///[url] - Most likely URL, may be null if otherLikelyBundles is provided. - /// - ///[otherLikelyURLs] - Other likely destinations, sorted in decreasing likelihood order. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.mayLaunchUrl.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'CustomTabsSession.mayLaunchUrl', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsSession#mayLaunchUrl(android.net.Uri,android.os.Bundle,java.util.List%3Candroid.os.Bundle%3E)', - ), - ], - ) - Future mayLaunchUrl({WebUri? url, List? otherLikelyURLs}) { - throw UnimplementedError( - 'mayLaunchUrl is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.validateRelationship} - ///Requests to validate a relationship between the application and an origin. - /// - ///See [here](https://developers.google.com/digital-asset-links/v1/getting-started) for documentation about Digital Asset Links. - ///This methods requests the browser to verify a relation with the calling application, to grant the associated rights. - /// - ///If this method returns `true`, the validation result will be provided through [PlatformChromeSafariBrowserEvents.onRelationshipValidationResult]. - ///Otherwise the request didn't succeed. - /// - ///[relation] – Relation to check, must be one of the [CustomTabsRelationType] constants. - /// - ///[origin] – Origin. - /// - ///[extras] – Reserved for future use. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.validateRelationship.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'CustomTabsSession.validateRelationship', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsSession#validateRelationship(int,android.net.Uri,android.os.Bundle)', - ), - ], - ) - Future validateRelationship({ - required CustomTabsRelationType relation, - required WebUri origin, - }) { - throw UnimplementedError( - 'validateRelationship is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.close} - ///Closes the [PlatformChromeSafariBrowser] instance. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.close.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform(), IOSPlatform()]) - Future close() { - throw UnimplementedError( - 'close is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.setActionButton} - ///Set a custom action button. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.setActionButton.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'CustomTabsSession.setActionButton', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsIntent.Builder#setActionButton(android.graphics.Bitmap,%20java.lang.String,%20android.app.PendingIntent,%20boolean)', - note: 'Not available in a Trusted Web Activity.', - ), - ], - ) - void setActionButton(ChromeSafariBrowserActionButton actionButton) { - throw UnimplementedError( - 'setActionButton is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.updateActionButton} - ///Updates the [ChromeSafariBrowserActionButton.icon] and [ChromeSafariBrowserActionButton.description]. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.updateActionButton.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'CustomTabsSession.setActionButton', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsIntent.Builder#setActionButton(android.graphics.Bitmap,%20java.lang.String,%20android.app.PendingIntent,%20boolean)', - note: 'Not available in a Trusted Web Activity.', - ), - ], - ) - Future updateActionButton({ - required Uint8List icon, - required String description, - }) { - throw UnimplementedError( - 'updateActionButton is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.setSecondaryToolbar} - ///Sets the remote views displayed in the secondary toolbar in a custom tab. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.setSecondaryToolbar.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'CustomTabsIntent.Builder.setSecondaryToolbarViews', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsIntent.Builder#setSecondaryToolbarViews(android.widget.RemoteViews,int[],android.app.PendingIntent)', - note: 'Not available in a Trusted Web Activity.', - ), - ], - ) - void setSecondaryToolbar( - ChromeSafariBrowserSecondaryToolbar secondaryToolbar, - ) { - throw UnimplementedError( - 'setSecondaryToolbar is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.updateSecondaryToolbar} - ///Sets or updates (if already present) the Remote Views of the secondary toolbar in an existing custom tab session. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.updateSecondaryToolbar.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'CustomTabsIntent.Builder.setSecondaryToolbarViews', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsIntent.Builder#setSecondaryToolbarViews(android.widget.RemoteViews,int[],android.app.PendingIntent)', - note: 'Not available in a Trusted Web Activity.', - ), - ], - ) - Future updateSecondaryToolbar( - ChromeSafariBrowserSecondaryToolbar secondaryToolbar, - ) { - throw UnimplementedError( - 'updateSecondaryToolbar is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.addMenuItem} - ///Adds a [ChromeSafariBrowserMenuItem] to the menu. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.addMenuItem.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(note: 'Not available in a Trusted Web Activity.'), - IOSPlatform(), - ], - ) - void addMenuItem(ChromeSafariBrowserMenuItem menuItem) { - throw UnimplementedError( - 'addMenuItem is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.addMenuItems} - ///Adds a list of [ChromeSafariBrowserMenuItem] to the menu. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.addMenuItems.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(note: 'Not available in a Trusted Web Activity.'), - IOSPlatform(), - ], - ) - void addMenuItems(List menuItems) { - throw UnimplementedError( - 'addMenuItems is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.requestPostMessageChannel} - ///Sends a request to create a two way postMessage channel between the client - ///and the browser. - ///If you want to specifying the target origin to communicate with, set the [targetOrigin]. - /// - ///[sourceOrigin] - A origin that the client is requesting to be - ///identified as during the postMessage communication. - ///It has to either start with http or https. - /// - ///[targetOrigin] - The target Origin to establish the postMessage communication with. - ///This can be the app's package name, it has to either start with http or https. - /// - ///Returns whether the implementation accepted the request. - ///Note that returning true here doesn't mean an origin has already been - ///assigned as the validation is asynchronous. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.requestPostMessageChannel.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'CustomTabsSession.requestPostMessageChannel', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsSession#requestPostMessageChannel(android.net.Uri,android.net.Uri,android.os.Bundle)', - ), - ], - ) - Future requestPostMessageChannel({ - required WebUri sourceOrigin, - WebUri? targetOrigin, - }) { - throw UnimplementedError( - 'requestPostMessageChannel is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.postMessage} - ///Sends a postMessage request using the origin communicated via [requestPostMessageChannel]. - ///Fails when called before [PlatformChromeSafariBrowserEvents.onMessageChannelReady] event. - /// - ///[message] – The message that is being sent. - /// - ///Returns an integer constant about the postMessage request result. - ///Will return [CustomTabsPostMessageResultType.SUCCESS] if successful. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.postMessage.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'CustomTabsSession.postMessage', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsSession#postMessage(java.lang.String,android.os.Bundle)', - ), - ], - ) - Future postMessage(String message) { - throw UnimplementedError( - 'postMessage is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isEngagementSignalsApiAvailable} - ///Returns whether the Engagement Signals API is available. - ///The availability of the Engagement Signals API may change at runtime. - ///If an EngagementSignalsCallback has been set, an [PlatformChromeSafariBrowserEvents.onSessionEnded] - ///signal will be sent if the API becomes unavailable later. - /// - ///Returns whether the Engagement Signals API is available. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isEngagementSignalsApiAvailable.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'CustomTabsSession.isEngagementSignalsApiAvailable', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsSession#isEngagementSignalsApiAvailable(android.os.Bundle)', - ), - ], - ) - Future isEngagementSignalsApiAvailable() { - throw UnimplementedError( - 'isEngagementSignalsApiAvailable is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isOpened} - ///Returns `true` if the [PlatformChromeSafariBrowser] instance is opened, otherwise `false`. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isOpened.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform(), IOSPlatform()]) - bool isOpened() { - throw UnimplementedError( - 'isOpened is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isAvailable} - ///On Android, returns `true` if Chrome Custom Tabs is available. - ///On iOS, returns `true` if SFSafariViewController is available. - ///Otherwise returns `false`. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isAvailable.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform(), IOSPlatform()]) - Future isAvailable() { - throw UnimplementedError( - 'isAvailable is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.getMaxToolbarItems} - ///The maximum number of allowed secondary toolbar items. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.getMaxToolbarItems.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - Future getMaxToolbarItems() { - throw UnimplementedError( - 'getMaxToolbarItems is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.getPackageName} - ///Returns the preferred package to use for Custom Tabs. - ///The preferred package name is the default VIEW intent handler as long as it supports Custom Tabs. - ///To modify this preferred behavior, set [ignoreDefault] to `true` and give a - ///non empty list of package names in packages. - ///This method queries the `PackageManager` to determine which packages support the Custom Tabs API. - ///On apps that target Android 11 and above, this requires adding the following - ///package visibility elements to your manifest. - /// - ///[packages] – Ordered list of packages to test for Custom Tabs support, in decreasing order of priority. - /// - ///[ignoreDefault] – If set, the default VIEW handler won't get priority over other browsers. - /// - ///Returns the preferred package name for handling Custom Tabs, or `null`. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.getPackageName.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'CustomTabsClient.getPackageName', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsClient#getPackageName(android.content.Context,java.util.List%3Cjava.lang.String%3E,boolean)', - ), - ], - ) - Future getPackageName({ - List? packages, - bool ignoreDefault = false, - }) { - throw UnimplementedError( - 'getPackageName is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.clearWebsiteData} - ///Clear associated website data accrued from browsing activity within your app. - ///This includes all local storage, cached resources, and cookies. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.clearWebsiteData.supported_platforms} - @SupportedPlatforms( - platforms: [ - IOSPlatform( - apiName: 'SFSafariViewController.DataStore.clearWebsiteData', - apiUrl: - 'https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller/datastore/3981117-clearwebsitedata', - available: '16.0', - ), - ], - ) - Future clearWebsiteData() { - throw UnimplementedError( - 'clearWebsiteData is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.prewarmConnections} - ///Prewarms a connection to each URL. SFSafariViewController will automatically use a - ///prewarmed connection if possible when loading its initial URL. - /// - ///Returns a token object that corresponds to the requested URLs. You must keep a strong - ///reference to this token as long as you expect the prewarmed connections to remain open. If the same - ///server is requested in multiple calls to this method, all of the corresponding tokens must be - ///invalidated or released to end the prewarmed connection to that server. - /// - ///This method uses a best-effort approach to prewarming connections, but may delay - ///or drop requests based on the volume of requests made by your app. Use this method when you expect - ///to present the browser soon. Many HTTP servers time out connections after a few minutes. - ///After a timeout, prewarming delivers less performance benefit. - /// - ///[URLs] - the URLs of servers that the browser should prewarm connections to. - ///Only supports URLs with `http://` or `https://` schemes. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.prewarmConnections.supported_platforms} - @SupportedPlatforms( - platforms: [ - IOSPlatform( - apiName: 'SFSafariViewController.prewarmConnections', - apiUrl: - 'https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller/3752133-prewarmconnections', - available: '15.0', - ), - ], - ) - Future prewarmConnections(List URLs) { - throw UnimplementedError( - 'prewarmConnections is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.invalidatePrewarmingToken} - ///Ends all prewarmed connections associated with the token, except for connections that are also kept alive by other tokens. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.invalidatePrewarmingToken.supported_platforms} - @SupportedPlatforms( - platforms: [ - IOSPlatform( - apiName: 'SFSafariViewController.PrewarmingToken.invalidate', - apiUrl: - 'https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller/prewarmingtoken/invalidate()', - available: '15.0', - ), - ], - ) - Future invalidatePrewarmingToken(PrewarmingToken prewarmingToken) { - throw UnimplementedError( - 'invalidatePrewarmingToken is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.dispose} - ///Disposes the channel and event handler. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.dispose.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform(), IOSPlatform()]) - @override - @mustCallSuper - void dispose() { - eventHandler = null; - } - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isClassSupported} - ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. - ///{@endtemplate} - bool isClassSupported({TargetPlatform? platform}) => - _PlatformChromeSafariBrowserClassSupported.isClassSupported( - platform: platform, - ); - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isMethodSupported} - ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. - ///{@endtemplate} - bool isMethodSupported( - PlatformChromeSafariBrowserMethod method, { - TargetPlatform? platform, - }) => _PlatformChromeSafariBrowserMethodSupported.isMethodSupported( - method, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.isMethodSupported} - bool isEventMethodSupported( - PlatformChromeSafariBrowserEventsMethod method, { - TargetPlatform? platform, - }) => PlatformChromeSafariBrowserEvents.isMethodSupported( - method, - platform: platform, - ); -} - -@SupportedPlatforms(platforms: [AndroidPlatform(), IOSPlatform()]) -abstract class PlatformChromeSafariBrowserEvents { - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onServiceConnected} - ///Event fired when the when connecting from Android Custom Tabs Service. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onServiceConnected.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - void onServiceConnected() {} - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onOpened} - ///Event fired when the [PlatformChromeSafariBrowser] is opened. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onOpened.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform(), IOSPlatform()]) - void onOpened() {} - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onCompletedInitialLoad} - ///Event fired when the initial URL load is complete. - /// - ///[didLoadSuccessfully] - `true` if loading completed successfully; otherwise, `false`. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onCompletedInitialLoad.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform( - apiName: 'SFSafariViewControllerDelegate.safariViewController', - apiUrl: - 'https://developer.apple.com/documentation/safariservices/sfsafariviewcontrollerdelegate/1621215-safariviewcontroller', - ), - ], - ) - void onCompletedInitialLoad( - @SupportedPlatforms(platforms: [IOSPlatform()]) bool? didLoadSuccessfully, - ) {} - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onInitialLoadDidRedirect} - ///Event fired when the initial URL load is complete. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onInitialLoadDidRedirect.supported_platforms} - @SupportedPlatforms( - platforms: [ - IOSPlatform( - apiName: 'SFSafariViewControllerDelegate.safariViewController', - apiUrl: - 'https://developer.apple.com/documentation/safariservices/sfsafariviewcontrollerdelegate/2923545-safariviewcontroller', - ), - ], - ) - void onInitialLoadDidRedirect(WebUri? url) {} - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onNavigationEvent} - ///Event fired when a navigation event happens. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onNavigationEvent.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'CustomTabsCallback.onNavigationEvent', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsCallback#onNavigationEvent(int,android.os.Bundle)', - ), - ], - ) - void onNavigationEvent(CustomTabsNavigationEventType? navigationEvent) {} - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onRelationshipValidationResult} - ///Event fired when a relationship validation result is available. - /// - ///[relation] - Relation for which the result is available. Value previously passed to [PlatformChromeSafariBrowser.validateRelationship]. - /// - ///[requestedOrigin] - Origin requested. Value previously passed to [PlatformChromeSafariBrowser.validateRelationship]. - /// - ///[result] - Whether the relation was validated. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onRelationshipValidationResult.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'CustomTabsCallback.onRelationshipValidationResult', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsCallback#onRelationshipValidationResult(int,android.net.Uri,boolean,android.os.Bundle)', - ), - ], - ) - void onRelationshipValidationResult( - CustomTabsRelationType? relation, - WebUri? requestedOrigin, - bool result, - ) {} - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onWillOpenInBrowser} - ///Event fired when the user opens the current page in the default browser by tapping the toolbar button. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onWillOpenInBrowser.supported_platforms} - @SupportedPlatforms( - platforms: [ - IOSPlatform( - apiName: - 'SFSafariViewControllerDelegate.safariViewControllerWillOpenInBrowser', - apiUrl: - 'https://developer.apple.com/documentation/safariservices/sfsafariviewcontrollerdelegate/3650426-safariviewcontrollerwillopeninbr', - available: '14.0', - ), - ], - ) - void onWillOpenInBrowser() {} - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onMessageChannelReady} - ///Called when the [PlatformChromeSafariBrowser] has requested a postMessage channel through - ///[PlatformChromeSafariBrowser.requestPostMessageChannel] and the channel is ready for sending and receiving messages on both ends. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onMessageChannelReady.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'CustomTabsCallback.onMessageChannelReady', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsCallback#onMessageChannelReady(android.os.Bundle)', - ), - ], - ) - void onMessageChannelReady() {} - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onPostMessage} - ///Called when a tab controlled by this [PlatformChromeSafariBrowser] has sent a postMessage. - ///If [PlatformChromeSafariBrowser.postMessage] is called from a single thread, then the messages will be posted in the same order. - ///When received on the client side, it is the client's responsibility to preserve the ordering further. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onPostMessage.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'CustomTabsCallback.onPostMessage', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsCallback#onPostMessage(java.lang.String,android.os.Bundle)', - ), - ], - ) - void onPostMessage(String message) {} - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onVerticalScrollEvent} - ///Called when a user scrolls the tab. - /// - ///[isDirectionUp] - `false` when the user scrolls farther down the page, - ///and `true` when the user scrolls back up toward the top of the page. - /// - ///**NOTE**: available only if [PlatformChromeSafariBrowser.isEngagementSignalsApiAvailable] returns `true`. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onVerticalScrollEvent.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'EngagementSignalsCallback.onVerticalScrollEvent', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/EngagementSignalsCallback#onVerticalScrollEvent(boolean,android.os.Bundle)', - ), - ], - ) - void onVerticalScrollEvent(bool isDirectionUp) {} - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onGreatestScrollPercentageIncreased} - ///Called when a user has reached a greater scroll percentage on the page. The greatest scroll - ///percentage is reset if the user navigates to a different page. If the current page's total - ///height changes, this method will be called again only if the scroll progress reaches a - ///higher percentage based on the new and current height of the page. - /// - ///[scrollPercentage] - An integer indicating the percent of scrollable progress - ///the user hasmade down the current page. - /// - ///**NOTE**: available only if [PlatformChromeSafariBrowser.isEngagementSignalsApiAvailable] returns `true`. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onGreatestScrollPercentageIncreased.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: - 'EngagementSignalsCallback.onGreatestScrollPercentageIncreased', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/EngagementSignalsCallback#onGreatestScrollPercentageIncreased(int,android.os.Bundle)', - ), - ], - ) - void onGreatestScrollPercentageIncreased(int scrollPercentage) {} - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onSessionEnded} - ///Called when a `CustomTabsSession` is ending or when no further Engagement Signals - ///callbacks are expected to report whether any user action has occurred during the session. - /// - ///[didUserInteract] - Whether the user has interacted with the page in any way, e.g. scrolling. - /// - ///**NOTE**: available only if [PlatformChromeSafariBrowser.isEngagementSignalsApiAvailable] returns `true`. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onSessionEnded.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'EngagementSignalsCallback.onSessionEnded', - apiUrl: - 'https://developer.android.com/reference/androidx/browser/customtabs/EngagementSignalsCallback#onSessionEnded(boolean,android.os.Bundle)', - ), - ], - ) - void onSessionEnded(bool didUserInteract) {} - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onClosed} - ///Event fired when the [PlatformChromeSafariBrowser] is closed. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onClosed.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform(), IOSPlatform()]) - void onClosed() {} - - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.isMethodSupported} - ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. - ///{@endtemplate} - static bool isMethodSupported( - PlatformChromeSafariBrowserEventsMethod method, { - TargetPlatform? platform, - }) => _PlatformChromeSafariBrowserEventsMethodSupported.isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/platform_chrome_safari_browser.g.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/platform_chrome_safari_browser.g.dart deleted file mode 100644 index decb03966a..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/platform_chrome_safari_browser.g.dart +++ /dev/null @@ -1,721 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'platform_chrome_safari_browser.dart'; - -// ************************************************************************** -// SupportedPlatformsGenerator -// ************************************************************************** - -extension _PlatformChromeSafariBrowserClassSupported - on PlatformChromeSafariBrowser { - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - This class uses native [Chrome Custom Tabs](https://developer.android.com/reference/android/support/customtabs/package-summary). If you want to use the `ChromeSafariBrowser` class on Android 11+ you need to specify your app querying for `android.support.customtabs.action.CustomTabsService` in your `AndroidManifest.xml` (you can read more about it here: https://developers.google.com/web/android/custom-tabs/best-practices#applications_targeting_android_11_api_level_30_or_above). - ///- iOS SFSafariViewController: - /// - This class uses native [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) - /// - ///Use the [PlatformChromeSafariBrowser.isClassSupported] method to check if this class is supported at runtime. - ///{@endtemplate} - static bool isClassSupported({TargetPlatform? platform}) { - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - } -} - -///List of [PlatformChromeSafariBrowser]'s methods that can be used to check if they are supported or not by the current platform. -enum PlatformChromeSafariBrowserMethod { - ///Can be used to check if the [PlatformChromeSafariBrowser.addMenuItem] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.addMenuItem.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - ///- iOS SFSafariViewController - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [menuItem]: all platforms - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - addMenuItem, - - ///Can be used to check if the [PlatformChromeSafariBrowser.addMenuItems] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.addMenuItems.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs: - /// - Not available in a Trusted Web Activity. - ///- iOS SFSafariViewController - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [menuItems]: all platforms - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - addMenuItems, - - ///Can be used to check if the [PlatformChromeSafariBrowser.clearWebsiteData] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.clearWebsiteData.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController 16.0+ ([Official API - SFSafariViewController.DataStore.clearWebsiteData](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller/datastore/3981117-clearwebsitedata)) - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - clearWebsiteData, - - ///Can be used to check if the [PlatformChromeSafariBrowser.close] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.close.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - ///- iOS SFSafariViewController - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - close, - - ///Can be used to check if the [PlatformChromeSafariBrowser.dispose] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.dispose.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - ///- iOS SFSafariViewController - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - dispose, - - ///Can be used to check if the [PlatformChromeSafariBrowser.getMaxToolbarItems] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.getMaxToolbarItems.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - getMaxToolbarItems, - - ///Can be used to check if the [PlatformChromeSafariBrowser.getPackageName] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.getPackageName.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs ([Official API - CustomTabsClient.getPackageName](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsClient#getPackageName(android.content.Context,java.util.List%3Cjava.lang.String%3E,boolean))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [packages]: all platforms - ///- [ignoreDefault]: all platforms - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - getPackageName, - - ///Can be used to check if the [PlatformChromeSafariBrowser.invalidatePrewarmingToken] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.invalidatePrewarmingToken.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController 15.0+ ([Official API - SFSafariViewController.PrewarmingToken.invalidate](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller/prewarmingtoken/invalidate())) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [prewarmingToken]: all platforms - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - invalidatePrewarmingToken, - - ///Can be used to check if the [PlatformChromeSafariBrowser.isAvailable] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isAvailable.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - ///- iOS SFSafariViewController - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - isAvailable, - - ///Can be used to check if the [PlatformChromeSafariBrowser.isEngagementSignalsApiAvailable] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isEngagementSignalsApiAvailable.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs ([Official API - CustomTabsSession.isEngagementSignalsApiAvailable](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsSession#isEngagementSignalsApiAvailable(android.os.Bundle))) - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - isEngagementSignalsApiAvailable, - - ///Can be used to check if the [PlatformChromeSafariBrowser.isOpened] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.isOpened.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - ///- iOS SFSafariViewController - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - isOpened, - - ///Can be used to check if the [PlatformChromeSafariBrowser.launchUrl] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.launchUrl.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - ///- [headers]: all platforms - ///- [otherLikelyURLs]: all platforms - ///- [referrer]: all platforms - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - launchUrl, - - ///Can be used to check if the [PlatformChromeSafariBrowser.mayLaunchUrl] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.mayLaunchUrl.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs ([Official API - CustomTabsSession.mayLaunchUrl](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsSession#mayLaunchUrl(android.net.Uri,android.os.Bundle,java.util.List%3Candroid.os.Bundle%3E))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - ///- [otherLikelyURLs]: all platforms - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - mayLaunchUrl, - - ///Can be used to check if the [PlatformChromeSafariBrowser.open] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.open.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs - ///- iOS SFSafariViewController - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - ///- [headers]: - /// - Android Chrome Custom Tabs - ///- [otherLikelyURLs]: - /// - Android Chrome Custom Tabs - ///- [referrer]: - /// - Android Chrome Custom Tabs - ///- [settings]: all platforms - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - open, - - ///Can be used to check if the [PlatformChromeSafariBrowser.postMessage] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.postMessage.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs ([Official API - CustomTabsSession.postMessage](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsSession#postMessage(java.lang.String,android.os.Bundle))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [message]: all platforms - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - postMessage, - - ///Can be used to check if the [PlatformChromeSafariBrowser.prewarmConnections] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.prewarmConnections.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS SFSafariViewController 15.0+ ([Official API - SFSafariViewController.prewarmConnections](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller/3752133-prewarmconnections)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [URLs]: all platforms - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - prewarmConnections, - - ///Can be used to check if the [PlatformChromeSafariBrowser.requestPostMessageChannel] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.requestPostMessageChannel.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs ([Official API - CustomTabsSession.requestPostMessageChannel](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsSession#requestPostMessageChannel(android.net.Uri,android.net.Uri,android.os.Bundle))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [sourceOrigin]: all platforms - ///- [targetOrigin]: all platforms - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - requestPostMessageChannel, - - ///Can be used to check if the [PlatformChromeSafariBrowser.setActionButton] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.setActionButton.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs ([Official API - CustomTabsSession.setActionButton](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsIntent.Builder#setActionButton(android.graphics.Bitmap,%20java.lang.String,%20android.app.PendingIntent,%20boolean))): - /// - Not available in a Trusted Web Activity. - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [actionButton]: all platforms - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - setActionButton, - - ///Can be used to check if the [PlatformChromeSafariBrowser.setSecondaryToolbar] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.setSecondaryToolbar.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs ([Official API - CustomTabsIntent.Builder.setSecondaryToolbarViews](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsIntent.Builder#setSecondaryToolbarViews(android.widget.RemoteViews,int[],android.app.PendingIntent))): - /// - Not available in a Trusted Web Activity. - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [secondaryToolbar]: all platforms - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - setSecondaryToolbar, - - ///Can be used to check if the [PlatformChromeSafariBrowser.updateActionButton] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.updateActionButton.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs ([Official API - CustomTabsSession.setActionButton](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsIntent.Builder#setActionButton(android.graphics.Bitmap,%20java.lang.String,%20android.app.PendingIntent,%20boolean))): - /// - Not available in a Trusted Web Activity. - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [icon]: all platforms - ///- [description]: all platforms - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - updateActionButton, - - ///Can be used to check if the [PlatformChromeSafariBrowser.updateSecondaryToolbar] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.updateSecondaryToolbar.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs ([Official API - CustomTabsIntent.Builder.setSecondaryToolbarViews](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsIntent.Builder#setSecondaryToolbarViews(android.widget.RemoteViews,int[],android.app.PendingIntent))): - /// - Not available in a Trusted Web Activity. - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [secondaryToolbar]: all platforms - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - updateSecondaryToolbar, - - ///Can be used to check if the [PlatformChromeSafariBrowser.validateRelationship] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowser.validateRelationship.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android Chrome Custom Tabs ([Official API - CustomTabsSession.validateRelationship](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsSession#validateRelationship(int,android.net.Uri,android.os.Bundle))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [relation]: all platforms - ///- [origin]: all platforms - /// - ///Use the [PlatformChromeSafariBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - validateRelationship, -} - -extension _PlatformChromeSafariBrowserMethodSupported - on PlatformChromeSafariBrowser { - static bool isMethodSupported( - PlatformChromeSafariBrowserMethod method, { - TargetPlatform? platform, - }) { - switch (method) { - case PlatformChromeSafariBrowserMethod.addMenuItem: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.addMenuItems: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.clearWebsiteData: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.close: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.dispose: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.getMaxToolbarItems: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.getPackageName: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.invalidatePrewarmingToken: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.isAvailable: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.isEngagementSignalsApiAvailable: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.isOpened: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.launchUrl: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.mayLaunchUrl: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.open: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.postMessage: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.prewarmConnections: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.requestPostMessageChannel: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.setActionButton: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.setSecondaryToolbar: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.updateActionButton: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.updateSecondaryToolbar: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserMethod.validateRelationship: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - } - } -} - -///List of [PlatformChromeSafariBrowserEvents]'s methods that can be used to check if they are supported or not by the current platform. -enum PlatformChromeSafariBrowserEventsMethod { - ///Can be used to check if the [PlatformChromeSafariBrowserEvents.onClosed] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onClosed.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - /// - ///Use the [PlatformChromeSafariBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onClosed, - - ///Can be used to check if the [PlatformChromeSafariBrowserEvents.onCompletedInitialLoad] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onCompletedInitialLoad.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView ([Official API - SFSafariViewControllerDelegate.safariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontrollerdelegate/1621215-safariviewcontroller)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [didLoadSuccessfully]: - /// - iOS WKWebView - /// - ///Use the [PlatformChromeSafariBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onCompletedInitialLoad, - - ///Can be used to check if the [PlatformChromeSafariBrowserEvents.onGreatestScrollPercentageIncreased] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onGreatestScrollPercentageIncreased.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - EngagementSignalsCallback.onGreatestScrollPercentageIncreased](https://developer.android.com/reference/androidx/browser/customtabs/EngagementSignalsCallback#onGreatestScrollPercentageIncreased(int,android.os.Bundle))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [scrollPercentage]: all platforms - /// - ///Use the [PlatformChromeSafariBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onGreatestScrollPercentageIncreased, - - ///Can be used to check if the [PlatformChromeSafariBrowserEvents.onInitialLoadDidRedirect] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onInitialLoadDidRedirect.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView ([Official API - SFSafariViewControllerDelegate.safariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontrollerdelegate/2923545-safariviewcontroller)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformChromeSafariBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onInitialLoadDidRedirect, - - ///Can be used to check if the [PlatformChromeSafariBrowserEvents.onMessageChannelReady] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onMessageChannelReady.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - CustomTabsCallback.onMessageChannelReady](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsCallback#onMessageChannelReady(android.os.Bundle))) - /// - ///Use the [PlatformChromeSafariBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onMessageChannelReady, - - ///Can be used to check if the [PlatformChromeSafariBrowserEvents.onNavigationEvent] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onNavigationEvent.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - CustomTabsCallback.onNavigationEvent](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsCallback#onNavigationEvent(int,android.os.Bundle))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [navigationEvent]: all platforms - /// - ///Use the [PlatformChromeSafariBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onNavigationEvent, - - ///Can be used to check if the [PlatformChromeSafariBrowserEvents.onOpened] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onOpened.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - /// - ///Use the [PlatformChromeSafariBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onOpened, - - ///Can be used to check if the [PlatformChromeSafariBrowserEvents.onPostMessage] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onPostMessage.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - CustomTabsCallback.onPostMessage](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsCallback#onPostMessage(java.lang.String,android.os.Bundle))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [message]: all platforms - /// - ///Use the [PlatformChromeSafariBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onPostMessage, - - ///Can be used to check if the [PlatformChromeSafariBrowserEvents.onRelationshipValidationResult] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onRelationshipValidationResult.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - CustomTabsCallback.onRelationshipValidationResult](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsCallback#onRelationshipValidationResult(int,android.net.Uri,boolean,android.os.Bundle))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [relation]: all platforms - ///- [requestedOrigin]: all platforms - ///- [result]: all platforms - /// - ///Use the [PlatformChromeSafariBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onRelationshipValidationResult, - - ///Can be used to check if the [PlatformChromeSafariBrowserEvents.onServiceConnected] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onServiceConnected.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///Use the [PlatformChromeSafariBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onServiceConnected, - - ///Can be used to check if the [PlatformChromeSafariBrowserEvents.onSessionEnded] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onSessionEnded.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - EngagementSignalsCallback.onSessionEnded](https://developer.android.com/reference/androidx/browser/customtabs/EngagementSignalsCallback#onSessionEnded(boolean,android.os.Bundle))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [didUserInteract]: all platforms - /// - ///Use the [PlatformChromeSafariBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onSessionEnded, - - ///Can be used to check if the [PlatformChromeSafariBrowserEvents.onVerticalScrollEvent] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onVerticalScrollEvent.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - EngagementSignalsCallback.onVerticalScrollEvent](https://developer.android.com/reference/androidx/browser/customtabs/EngagementSignalsCallback#onVerticalScrollEvent(boolean,android.os.Bundle))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [isDirectionUp]: all platforms - /// - ///Use the [PlatformChromeSafariBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onVerticalScrollEvent, - - ///Can be used to check if the [PlatformChromeSafariBrowserEvents.onWillOpenInBrowser] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformChromeSafariBrowserEvents.onWillOpenInBrowser.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView 14.0+ ([Official API - SFSafariViewControllerDelegate.safariViewControllerWillOpenInBrowser](https://developer.apple.com/documentation/safariservices/sfsafariviewcontrollerdelegate/3650426-safariviewcontrollerwillopeninbr)) - /// - ///Use the [PlatformChromeSafariBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onWillOpenInBrowser, -} - -extension _PlatformChromeSafariBrowserEventsMethodSupported - on PlatformChromeSafariBrowserEvents { - static bool isMethodSupported( - PlatformChromeSafariBrowserEventsMethod method, { - TargetPlatform? platform, - }) { - switch (method) { - case PlatformChromeSafariBrowserEventsMethod.onClosed: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserEventsMethod.onCompletedInitialLoad: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserEventsMethod - .onGreatestScrollPercentageIncreased: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserEventsMethod.onInitialLoadDidRedirect: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserEventsMethod.onMessageChannelReady: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserEventsMethod.onNavigationEvent: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserEventsMethod.onOpened: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserEventsMethod.onPostMessage: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserEventsMethod - .onRelationshipValidationResult: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserEventsMethod.onServiceConnected: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserEventsMethod.onSessionEnded: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserEventsMethod.onVerticalScrollEvent: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformChromeSafariBrowserEventsMethod.onWillOpenInBrowser: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - } - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/content_blocker.dart b/flutter_inappwebview_platform_interface/lib/src/content_blocker.dart deleted file mode 100755 index 36f47a36a6..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/content_blocker.dart +++ /dev/null @@ -1,365 +0,0 @@ -import 'types/main.dart'; - -///Class that represents a set of rules to use block content in the browser window. -/// -///On iOS and MacOS, it uses [WKContentRuleListStore](https://developer.apple.com/documentation/webkit/wkcontentruleliststore). -///On Android, it uses a custom implementation because such functionality doesn't exist. -/// -///In general, this [article](https://developer.apple.com/documentation/safariservices/creating_a_content_blocker) can be used to get an overview about this functionality -///but on Android there are two types of [action] that are unavailable: `block-cookies` and `ignore-previous-rules`. -class ContentBlocker { - ///Trigger of the content blocker. The trigger tells to the WebView when to perform the corresponding action. - ContentBlockerTrigger trigger; - - ///Action associated to the trigger. The action tells to the WebView what to do when the trigger is matched. - ContentBlockerAction action; - - ContentBlocker({required this.trigger, required this.action}); - - Map> toMap({EnumMethod? enumMethod}) { - return { - "trigger": trigger.toMap(enumMethod: enumMethod), - "action": action.toMap(enumMethod: enumMethod), - }; - } - - static ContentBlocker fromMap( - Map> map, { - EnumMethod? enumMethod, - }) { - return ContentBlocker( - trigger: ContentBlockerTrigger.fromMap( - Map.from(map["trigger"]!), - enumMethod: enumMethod, - ), - action: ContentBlockerAction.fromMap( - Map.from(map["action"]!), - enumMethod: enumMethod, - ), - ); - } - - @override - String toString() { - return 'ContentBlocker{trigger: $trigger, action: $action}'; - } -} - -///Trigger of the content blocker. The trigger tells to the WebView when to perform the corresponding action. -///A trigger dictionary must include an [ContentBlockerTrigger.urlFilter], which specifies a pattern to match the URL against. -///The remaining properties are optional and modify the behavior of the trigger. -///For example, you can limit the trigger to specific domains or have it not apply when a match is found on a specific domain. -class ContentBlockerTrigger { - ///A regular expression pattern to match the URL against. - String urlFilter; - - ///A list of regular expressions to match iframes URL against. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS - List ifFrameUrl; - - ///A Boolean value indicating if the URL matching should be case-sensitive. - ///The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - bool urlFilterIsCaseSensitive; - - ///A list of [ContentBlockerTriggerResourceType] representing the resource types - ///(how the browser intends to use the resource) that the rule should match. - ///If not specified, the rule matches all resource types. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - List resourceType; - - ///A list of strings matched to a URL's domain; limits action to a list of specific domains. - ///Values must be lowercase ASCII, or punycode for non-ASCII. - ///Add * in front to match domain and subdomains. Can't be used with [ContentBlockerTrigger.unlessDomain]. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - List ifDomain; - - ///A list of strings matched to a URL's domain; acts on any site except domains in a provided list. - ///Values must be lowercase ASCII, or punycode for non-ASCII. - ///Add * in front to match domain and subdomains. Can't be used with [ContentBlockerTrigger.ifDomain]. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - List unlessDomain; - - ///A list of [ContentBlockerTriggerLoadType] that can include one of two mutually exclusive values. - ///If not specified, the rule matches all load types. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - List loadType; - - ///A list of strings matched to the entire main document URL; limits the action to a specific list of URL patterns. - ///Values must be lowercase ASCII, or punycode for non-ASCII. Can't be used with [ContentBlockerTrigger.unlessTopUrl]. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - List ifTopUrl; - - ///An array of strings matched to the entire main document URL; acts on any site except URL patterns in provided list. - ///Values must be lowercase ASCII, or punycode for non-ASCII. Can't be used with [ContentBlockerTrigger.ifTopUrl]. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - List unlessTopUrl; - - ///An array of strings that specify loading contexts. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS - List loadContext; - - ContentBlockerTrigger({ - required this.urlFilter, - this.ifFrameUrl = const [], - this.urlFilterIsCaseSensitive = false, - this.resourceType = const [], - this.ifDomain = const [], - this.unlessDomain = const [], - this.loadType = const [], - this.ifTopUrl = const [], - this.unlessTopUrl = const [], - this.loadContext = const [], - }) { - assert(!(this.ifDomain.isEmpty || this.unlessDomain.isEmpty) == false); - assert(this.loadType.length <= 2); - assert(!(this.ifTopUrl.isEmpty || this.unlessTopUrl.isEmpty) == false); - } - - Map toMap({EnumMethod? enumMethod}) { - List resourceTypeStringList = []; - resourceType.forEach((type) { - switch (enumMethod ?? EnumMethod.nativeValue) { - case EnumMethod.nativeValue: - if (type.isSupported()) { - resourceTypeStringList.add(type.toNativeValue()!); - } - break; - case EnumMethod.value: - resourceTypeStringList.add(type.toValue()); - break; - case EnumMethod.name: - resourceTypeStringList.add(type.name()); - break; - } - }); - List loadTypeStringList = []; - loadType.forEach((type) { - switch (enumMethod ?? EnumMethod.nativeValue) { - case EnumMethod.nativeValue: - if (type.isSupported()) { - loadTypeStringList.add(type.toNativeValue()!); - } - break; - case EnumMethod.value: - loadTypeStringList.add(type.toValue()); - break; - case EnumMethod.name: - loadTypeStringList.add(type.name()); - break; - } - }); - List loadContextStringList = []; - loadContext.forEach((type) { - switch (enumMethod ?? EnumMethod.nativeValue) { - case EnumMethod.nativeValue: - if (type.isSupported()) { - loadContextStringList.add(type.toNativeValue()!); - } - break; - case EnumMethod.value: - loadContextStringList.add(type.toValue()); - break; - case EnumMethod.name: - loadContextStringList.add(type.name()); - break; - } - }); - - Map map = { - "url-filter": urlFilter, - "if-frame-url": ifFrameUrl, - "url-filter-is-case-sensitive": urlFilterIsCaseSensitive, - "if-domain": ifDomain, - "unless-domain": unlessDomain, - "resource-type": resourceTypeStringList, - "load-type": loadTypeStringList, - "if-top-url": ifTopUrl, - "unless-top-url": unlessTopUrl, - "load-context": loadContextStringList, - }; - - map.keys - .where( - (key) => - map[key] == null || - (map[key] is List && (map[key] as List).length == 0), - ) // filter keys - .toList() // create a copy to avoid concurrent modifications - .forEach(map.remove); - - return map; - } - - static ContentBlockerTrigger fromMap( - Map map, { - EnumMethod? enumMethod, - }) { - List resourceType = []; - List loadType = []; - List loadContext = []; - - List resourceTypeStringList = List.from( - map["resource-type"] ?? [], - ); - resourceTypeStringList.forEach((typeValue) { - var type = switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => - ContentBlockerTriggerResourceType.fromNativeValue(typeValue), - EnumMethod.value => ContentBlockerTriggerResourceType.fromValue( - typeValue, - ), - EnumMethod.name => ContentBlockerTriggerResourceType.byName(typeValue), - }; - if (type != null) { - resourceType.add(type); - } - }); - - List loadTypeStringList = List.from(map["load-type"] ?? []); - loadTypeStringList.forEach((typeValue) { - var type = switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => ContentBlockerTriggerLoadType.fromNativeValue( - typeValue, - ), - EnumMethod.value => ContentBlockerTriggerLoadType.fromValue(typeValue), - EnumMethod.name => ContentBlockerTriggerLoadType.byName(typeValue), - }; - if (type != null) { - loadType.add(type); - } - }); - - List loadContextStringList = List.from( - map["load-context"] ?? [], - ); - loadContextStringList.forEach((typeValue) { - var context = switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => - ContentBlockerTriggerLoadContext.fromNativeValue(typeValue), - EnumMethod.value => ContentBlockerTriggerLoadContext.fromValue( - typeValue, - ), - EnumMethod.name => ContentBlockerTriggerLoadContext.byName(typeValue), - }; - if (context != null) { - loadContext.add(context); - } - }); - - return ContentBlockerTrigger( - urlFilter: map["url-filter"], - ifFrameUrl: List.from(map["if-frame-url"] ?? []), - urlFilterIsCaseSensitive: map["url-filter-is-case-sensitive"], - ifDomain: List.from(map["if-domain"] ?? []), - unlessDomain: List.from(map["unless-domain"] ?? []), - resourceType: resourceType, - loadType: loadType, - ifTopUrl: List.from(map["if-top-url"] ?? []), - unlessTopUrl: List.from(map["unless-top-url"] ?? []), - loadContext: loadContext, - ); - } - - @override - String toString() { - return 'ContentBlockerTrigger{urlFilter: $urlFilter, ifFrameUrl: $ifFrameUrl, urlFilterIsCaseSensitive: $urlFilterIsCaseSensitive, resourceType: $resourceType, ifDomain: $ifDomain, unlessDomain: $unlessDomain, loadType: $loadType, ifTopUrl: $ifTopUrl, unlessTopUrl: $unlessTopUrl, loadContext: $loadContext}'; - } -} - -///Action associated to the trigger. The action tells to the WebView what to do when the trigger is matched. -///When a trigger matches a resource, the browser queues the associated action for execution. -///The WebView evaluates all the triggers, it executes the actions in order. -///When a domain matches a trigger, all rules after the triggered rule that specify the same action are skipped. -///Group the rules with similar actions together to improve performance. -class ContentBlockerAction { - ///Type of the action. - ContentBlockerActionType type; - - ///If the action type is [ContentBlockerActionType.CSS_DISPLAY_NONE], then also the [selector] property is required, otherwise it is ignored. - ///It specify a string that defines a selector list. Use CSS identifiers as the individual selector values, separated by commas. - String? selector; - - ContentBlockerAction({required this.type, this.selector}) { - if (this.type == ContentBlockerActionType.CSS_DISPLAY_NONE) { - assert(this.selector != null); - } - } - - Map toMap({EnumMethod? enumMethod}) { - Map map = { - "type": switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => type.toNativeValue(), - EnumMethod.value => type.toValue(), - EnumMethod.name => type.name(), - }, - "selector": selector, - }; - - map.keys - .where( - (key) => - map[key] == null || - (map[key] is List && (map[key] as List).length == 0), - ) // filter keys - .toList() // create a copy to avoid concurrent modifications - .forEach(map.remove); - - return map; - } - - static ContentBlockerAction fromMap( - Map map, { - EnumMethod? enumMethod, - }) { - return ContentBlockerAction( - type: switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => ContentBlockerActionType.fromNativeValue( - map["type"], - ), - EnumMethod.value => ContentBlockerActionType.fromValue(map["type"]), - EnumMethod.name => ContentBlockerActionType.byName(map["type"]), - }!, - selector: map["selector"], - ); - } - - @override - String toString() { - return 'ContentBlockerAction{type: $type, selector: $selector}'; - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.dart b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.dart deleted file mode 100644 index 1957bac0bc..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; - -import '../in_app_webview/platform_webview.dart'; -import '../types/in_app_webview_hit_test_result.dart'; -import 'context_menu_item.dart'; -import 'context_menu_settings.dart'; -import '../types/enum_method.dart'; - -part 'context_menu.g.dart'; - -///Class that represents the WebView context menu. It used by [PlatformWebViewCreationParams.contextMenu]. -@SupportedPlatforms( - platforms: [ - AndroidPlatform( - note: - 'To make it work properly on Android, JavaScript should be enabled!', - ), - IOSPlatform(), - ], -) -@ExchangeableObject() -class ContextMenu_ { - ///Event fired when the context menu for this WebView is being built. - /// - ///[hitTestResult] represents the hit result for hitting an HTML elements. - final void Function(InAppWebViewHitTestResult_ hitTestResult)? - onCreateContextMenu; - - ///Event fired when the context menu for this WebView is being hidden. - final void Function()? onHideContextMenu; - - ///Event fired when a context menu item has been clicked. - /// - ///[contextMenuItemClicked] represents the [ContextMenuItem] clicked. - final void Function(ContextMenuItem_ contextMenuItemClicked)? - onContextMenuActionItemClicked; - - ///Use [settings] instead - @Deprecated("Use settings instead") - final ContextMenuOptions_? options; - - ///Context menu settings. - final ContextMenuSettings_? settings; - - ///List of the custom [ContextMenuItem]. - final List menuItems; - - @ExchangeableObjectConstructor() - ContextMenu_({ - this.menuItems = const [], - this.onCreateContextMenu, - this.onHideContextMenu, - @Deprecated("Use settings instead") this.options, - this.settings, - this.onContextMenuActionItemClicked, - }); - - @ExchangeableObjectMethod(toMapMergeWith: true) - // ignore: unused_element - Map _toMapMergeWith({EnumMethod? enumMethod}) { - return { - "settings": - (settings as ContextMenuSettings?)?.toMap(enumMethod: enumMethod) ?? - (options as ContextMenuOptions?)?.toMap(enumMethod: enumMethod), - }; - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.g.dart b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.g.dart deleted file mode 100644 index 8b55ff4535..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.g.dart +++ /dev/null @@ -1,111 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'context_menu.dart'; - -// ************************************************************************** -// ExchangeableObjectGenerator -// ************************************************************************** - -///Class that represents the WebView context menu. It used by [PlatformWebViewCreationParams.contextMenu]. -/// -///**Officially Supported Platforms/Implementations**: -///- Android WebView: -/// - To make it work properly on Android, JavaScript should be enabled! -///- iOS WKWebView -class ContextMenu { - ///List of the custom [ContextMenuItem]. - final List menuItems; - - ///Event fired when a context menu item has been clicked. - /// - ///[contextMenuItemClicked] represents the [ContextMenuItem] clicked. - final void Function(ContextMenuItem)? onContextMenuActionItemClicked; - - ///Event fired when the context menu for this WebView is being built. - /// - ///[hitTestResult] represents the hit result for hitting an HTML elements. - final void Function(InAppWebViewHitTestResult)? onCreateContextMenu; - - ///Event fired when the context menu for this WebView is being hidden. - final void Function()? onHideContextMenu; - - ///Use [settings] instead - @Deprecated('Use settings instead') - final ContextMenuOptions? options; - - ///Context menu settings. - final ContextMenuSettings? settings; - - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView: - /// - To make it work properly on Android, JavaScript should be enabled! - ///- iOS WKWebView - ContextMenu({ - this.menuItems = const [], - this.onCreateContextMenu, - this.onHideContextMenu, - @Deprecated("Use settings instead") this.options, - this.settings, - this.onContextMenuActionItemClicked, - }); - - ///Gets a possible [ContextMenu] instance from a [Map] value. - static ContextMenu? fromMap( - Map? map, { - EnumMethod? enumMethod, - }) { - if (map == null) { - return null; - } - final instance = ContextMenu( - menuItems: List.from( - map['menuItems'].map( - (e) => ContextMenuItem.fromMap( - e?.cast(), - enumMethod: enumMethod, - )!, - ), - ), - options: ContextMenuOptions.fromMap( - map['settings']?.cast(), - enumMethod: enumMethod, - ), - settings: ContextMenuSettings.fromMap( - map['settings']?.cast(), - enumMethod: enumMethod, - ), - ); - return instance; - } - - @ExchangeableObjectMethod(toMapMergeWith: true) - Map _toMapMergeWith({EnumMethod? enumMethod}) { - return { - "settings": - (settings as ContextMenuSettings?)?.toMap(enumMethod: enumMethod) ?? - (options as ContextMenuOptions?)?.toMap(enumMethod: enumMethod), - }; - } - - ///Converts instance to a map. - Map toMap({EnumMethod? enumMethod}) { - return { - "menuItems": menuItems - .map((e) => e.toMap(enumMethod: enumMethod)) - .toList(), - "settings": settings?.toMap(enumMethod: enumMethod), - ..._toMapMergeWith(enumMethod: enumMethod), - }; - } - - ///Converts instance to a map. - Map toJson() { - return toMap(); - } - - @override - String toString() { - return 'ContextMenu{menuItems: $menuItems, settings: $settings}'; - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_item.dart b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_item.dart deleted file mode 100644 index d7c7e5b146..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_item.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; - -import 'context_menu.dart'; -import '../util.dart'; -import '../types/enum_method.dart'; - -part 'context_menu_item.g.dart'; - -///Class that represent an item of the [ContextMenu]. -@ExchangeableObject() -class ContextMenuItem_ { - ///Use [id] instead. - @Deprecated("Use id instead") - int? androidId; - - ///Use [id] instead. - @Deprecated("Use id instead") - String? iosId; - - ///Menu item ID. It cannot be `null` and it can be a [String] or an [int]. - /// - ///**NOTE for Android**: it must be an [int] value. - dynamic id; - - ///Menu item title. - String title; - - ///Menu item action that will be called when an user clicks on it. - Function()? action; - - @ExchangeableObjectConstructor() - ContextMenuItem_({ - this.id, - @Deprecated("Use id instead") this.androidId, - @Deprecated("Use id instead") this.iosId, - required this.title, - this.action, - }) { - if (Util.isAndroid) { - // ignore: deprecated_member_use_from_same_package - this.id = this.id ?? this.androidId; - assert(this.id is int); - } else if (Util.isIOS) { - // ignore: deprecated_member_use_from_same_package - this.id = this.id ?? this.iosId; - } - assert(this.id != null && (this.id is int || this.id is String)); - } - - @ExchangeableObjectMethod(toMapMergeWith: true) - // ignore: unused_element - Map _toMapMergeWith({EnumMethod? enumMethod}) { - return {"androidId": androidId, "iosId": iosId}; - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_item.g.dart b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_item.g.dart deleted file mode 100644 index f07e7a5f0a..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_item.g.dart +++ /dev/null @@ -1,85 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'context_menu_item.dart'; - -// ************************************************************************** -// ExchangeableObjectGenerator -// ************************************************************************** - -///Class that represent an item of the [ContextMenu]. -class ContextMenuItem { - ///Menu item action that will be called when an user clicks on it. - dynamic Function()? action; - - ///Use [id] instead. - @Deprecated('Use id instead') - int? androidId; - - ///Menu item ID. It cannot be `null` and it can be a [String] or an [int]. - /// - ///**NOTE for Android**: it must be an [int] value. - dynamic id; - - ///Use [id] instead. - @Deprecated('Use id instead') - String? iosId; - - ///Menu item title. - String title; - ContextMenuItem({ - this.id, - @Deprecated("Use id instead") this.androidId, - @Deprecated("Use id instead") this.iosId, - required this.title, - this.action, - }) { - if (Util.isAndroid) { - this.id = this.id ?? this.androidId; - assert(this.id is int); - } else if (Util.isIOS) { - this.id = this.id ?? this.iosId; - } - assert(this.id != null && (this.id is int || this.id is String)); - } - - ///Gets a possible [ContextMenuItem] instance from a [Map] value. - static ContextMenuItem? fromMap( - Map? map, { - EnumMethod? enumMethod, - }) { - if (map == null) { - return null; - } - final instance = ContextMenuItem( - androidId: map['id'], - id: map['id'], - iosId: map['id'], - title: map['title'], - ); - return instance; - } - - @ExchangeableObjectMethod(toMapMergeWith: true) - Map _toMapMergeWith({EnumMethod? enumMethod}) { - return {"androidId": androidId, "iosId": iosId}; - } - - ///Converts instance to a map. - Map toMap({EnumMethod? enumMethod}) { - return { - "id": id, - "title": title, - ..._toMapMergeWith(enumMethod: enumMethod), - }; - } - - ///Converts instance to a map. - Map toJson() { - return toMap(); - } - - @override - String toString() { - return 'ContextMenuItem{id: $id, title: $title}'; - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.dart b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.dart deleted file mode 100644 index f90b3409f5..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; - -import 'context_menu.dart'; -import '../types/enum_method.dart'; - -part 'context_menu_settings.g.dart'; - -///Class that represents available settings used by [ContextMenu]. -@ExchangeableObject(copyMethod: true) -class ContextMenuSettings_ { - ///Whether all the default system context menu items should be hidden or not. The default value is `false`. - bool hideDefaultSystemContextMenuItems; - - ContextMenuSettings_({this.hideDefaultSystemContextMenuItems = false}); -} - -///Use [ContextMenuSettings] instead. -@Deprecated("Use ContextMenuSettings instead") -@ExchangeableObject(copyMethod: true) -class ContextMenuOptions_ { - ///Whether all the default system context menu items should be hidden or not. The default value is `false`. - bool hideDefaultSystemContextMenuItems; - - ContextMenuOptions_({this.hideDefaultSystemContextMenuItems = false}); -} diff --git a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.g.dart b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.g.dart deleted file mode 100644 index d4a0c227fc..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.g.dart +++ /dev/null @@ -1,98 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'context_menu_settings.dart'; - -// ************************************************************************** -// ExchangeableObjectGenerator -// ************************************************************************** - -///Class that represents available settings used by [ContextMenu]. -class ContextMenuSettings { - ///Whether all the default system context menu items should be hidden or not. The default value is `false`. - bool hideDefaultSystemContextMenuItems; - ContextMenuSettings({this.hideDefaultSystemContextMenuItems = false}); - - ///Gets a possible [ContextMenuSettings] instance from a [Map] value. - static ContextMenuSettings? fromMap( - Map? map, { - EnumMethod? enumMethod, - }) { - if (map == null) { - return null; - } - final instance = ContextMenuSettings(); - if (map['hideDefaultSystemContextMenuItems'] != null) { - instance.hideDefaultSystemContextMenuItems = - map['hideDefaultSystemContextMenuItems']; - } - return instance; - } - - ///Converts instance to a map. - Map toMap({EnumMethod? enumMethod}) { - return { - "hideDefaultSystemContextMenuItems": hideDefaultSystemContextMenuItems, - }; - } - - ///Converts instance to a map. - Map toJson() { - return toMap(); - } - - ///Returns a copy of ContextMenuSettings. - ContextMenuSettings copy() { - return ContextMenuSettings.fromMap(toMap()) ?? ContextMenuSettings(); - } - - @override - String toString() { - return 'ContextMenuSettings{hideDefaultSystemContextMenuItems: $hideDefaultSystemContextMenuItems}'; - } -} - -///Use [ContextMenuSettings] instead. -@Deprecated('Use ContextMenuSettings instead') -class ContextMenuOptions { - ///Whether all the default system context menu items should be hidden or not. The default value is `false`. - bool hideDefaultSystemContextMenuItems; - ContextMenuOptions({this.hideDefaultSystemContextMenuItems = false}); - - ///Gets a possible [ContextMenuOptions] instance from a [Map] value. - static ContextMenuOptions? fromMap( - Map? map, { - EnumMethod? enumMethod, - }) { - if (map == null) { - return null; - } - final instance = ContextMenuOptions(); - if (map['hideDefaultSystemContextMenuItems'] != null) { - instance.hideDefaultSystemContextMenuItems = - map['hideDefaultSystemContextMenuItems']; - } - return instance; - } - - ///Converts instance to a map. - Map toMap({EnumMethod? enumMethod}) { - return { - "hideDefaultSystemContextMenuItems": hideDefaultSystemContextMenuItems, - }; - } - - ///Converts instance to a map. - Map toJson() { - return toMap(); - } - - ///Returns a copy of ContextMenuOptions. - ContextMenuOptions copy() { - return ContextMenuOptions.fromMap(toMap()) ?? ContextMenuOptions(); - } - - @override - String toString() { - return 'ContextMenuOptions{hideDefaultSystemContextMenuItems: $hideDefaultSystemContextMenuItems}'; - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/context_menu/main.dart b/flutter_inappwebview_platform_interface/lib/src/context_menu/main.dart deleted file mode 100644 index 5ff9f3f227..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/context_menu/main.dart +++ /dev/null @@ -1,4 +0,0 @@ -export 'context_menu.dart' show ContextMenu; -export 'context_menu_item.dart' show ContextMenuItem; -export 'context_menu_settings.dart' - show ContextMenuSettings, ContextMenuOptions; diff --git a/flutter_inappwebview_platform_interface/lib/src/debug_logging_settings.dart b/flutter_inappwebview_platform_interface/lib/src/debug_logging_settings.dart deleted file mode 100644 index 49cb182600..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/debug_logging_settings.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:flutter/foundation.dart'; - -///Class that represents the debug logging settings. -class DebugLoggingSettings { - ///Enables debug logging info. - /// - ///The default value is the same value of [kDebugMode], - ///so it is enabled by default when the application is compiled in debug mode - ///and disabled when it is not. - bool enabled; - - ///Filters used to exclude some logs from logging. - List excludeFilter; - - ///Max length of the log message. - ///Set to `-1` to indicate that the log message needs to display the full content. - /// - ///The default value is `-1`. - int maxLogMessageLength; - - ///Use [print] instead of `developer.log` to log messages. - bool usePrint; - - DebugLoggingSettings({ - this.enabled = kDebugMode, - this.excludeFilter = const [], - this.maxLogMessageLength = -1, - this.usePrint = false, - }); -} diff --git a/flutter_inappwebview_platform_interface/lib/src/find_interaction/main.dart b/flutter_inappwebview_platform_interface/lib/src/find_interaction/main.dart deleted file mode 100644 index 59ad6cde43..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/find_interaction/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'platform_find_interaction_controller.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/find_interaction/platform_find_interaction_controller.dart b/flutter_inappwebview_platform_interface/lib/src/find_interaction/platform_find_interaction_controller.dart deleted file mode 100644 index 83e51717c4..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/find_interaction/platform_find_interaction_controller.dart +++ /dev/null @@ -1,536 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; -import 'package:flutter_inappwebview_platform_interface/src/types/disposable.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import '../in_app_webview/in_app_webview_settings.dart'; -import '../debug_logging_settings.dart'; -import '../inappwebview_platform.dart'; -import '../types/main.dart'; - -part 'platform_find_interaction_controller.g.dart'; - -///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionControllerCreationParams} -/// Object specifying creation parameters for creating a [PlatformFindInteractionController]. -/// -/// Platform specific implementations can add additional fields by extending -/// this class. -///{@endtemplate} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionControllerCreationParams.supported_platforms} -@SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - LinuxPlatform(), - WindowsPlatform(), - ], -) -@immutable -class PlatformFindInteractionControllerCreationParams { - /// Used by the platform implementation to create a new [PlatformFindInteractionController]. - const PlatformFindInteractionControllerCreationParams({ - this.onFindResultReceived, - }); - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionControllerCreationParams.onFindResultReceived} - ///Event fired as find-on-page operations progress. - ///The listener may be notified multiple times while the operation is underway, and the [numberOfMatches] value should not be considered final unless [isDoneCounting] is true. - /// - ///[activeMatchOrdinal] represents the zero-based ordinal of the currently selected match. - /// - ///[numberOfMatches] represents how many matches have been found. - /// - ///[isDoneCounting] whether the find operation has actually completed. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionControllerCreationParams.onFindResultReceived.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebView.FindListener.onFindResultReceived', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebView.FindListener#onFindResultReceived(int,%20int,%20boolean)', - ), - IOSPlatform( - note: - 'If [InAppWebViewSettings.isFindInteractionEnabled] is `true`, this event will not be called.', - ), - MacOSPlatform(), - LinuxPlatform( - apiName: 'WebKitFindController::counted-matches', - apiUrl: - 'https://wpewebkit.org/reference/stable/wpe-webkit-2.0/signal.FindController.counted-matches.html', - ), - WindowsPlatform( - apiName: 'ICoreWebView2Find.ActiveMatchIndexChanged/MatchCountChanged', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2find', - ), - ], - ) - final void Function( - PlatformFindInteractionController controller, - int activeMatchOrdinal, - int numberOfMatches, - bool isDoneCounting, - )? - onFindResultReceived; - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionControllerCreationParams.isClassSupported} - ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. - ///{@endtemplate} - bool isClassSupported({TargetPlatform? platform}) => - _PlatformFindInteractionControllerCreationParamsClassSupported.isClassSupported( - platform: platform, - ); - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionControllerCreationParams.isPropertySupported} - ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. - ///{@endtemplate} - bool isPropertySupported( - PlatformFindInteractionControllerCreationParamsProperty property, { - TargetPlatform? platform, - }) => - _PlatformFindInteractionControllerCreationParamsPropertySupported.isPropertySupported( - property, - platform: platform, - ); -} - -///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController} -///This class represents the controller used by the `WebView` to add -///text-finding capabilities, such as the "Find on page" feature. -///{@endtemplate} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.supported_platforms} -@SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - LinuxPlatform(), - WindowsPlatform(), - ], -) -abstract class PlatformFindInteractionController extends PlatformInterface - implements Disposable { - ///Debug settings. - static DebugLoggingSettings debugLoggingSettings = DebugLoggingSettings(); - - /// Creates a new [PlatformFindInteractionController] - factory PlatformFindInteractionController( - PlatformFindInteractionControllerCreationParams params, - ) { - assert( - InAppWebViewPlatform.instance != null, - 'A platform implementation for `flutter_inappwebview` has not been set. Please ' - 'ensure that an implementation of `InAppWebViewPlatform` has been set to ' - '`InAppWebViewPlatform.instance` before use. For unit testing, ' - '`InAppWebViewPlatform.instance` can be set with your own test implementation.', - ); - final PlatformFindInteractionController webViewControllerDelegate = - InAppWebViewPlatform.instance!.createPlatformFindInteractionController( - params, - ); - PlatformInterface.verify(webViewControllerDelegate, _token); - return webViewControllerDelegate; - } - - /// Creates a new [PlatformFindInteractionController] - factory PlatformFindInteractionController.static() { - assert( - InAppWebViewPlatform.instance != null, - 'A platform implementation for `flutter_inappwebview` has not been set. Please ' - 'ensure that an implementation of `InAppWebViewPlatform` has been set to ' - '`WebViewPlatform.instance` before use. For unit testing, ' - '`WebViewPlatform.instance` can be set with your own test implementation.', - ); - final PlatformFindInteractionController findInteractionControllerStatic = - InAppWebViewPlatform.instance! - .createPlatformFindInteractionControllerStatic(); - PlatformInterface.verify(findInteractionControllerStatic, _token); - return findInteractionControllerStatic; - } - - /// Used by the platform implementation to create a new [PlatformFindInteractionController]. - /// - /// Should only be used by platform implementations because they can't extend - /// a class that only contains a factory constructor. - @protected - PlatformFindInteractionController.implementation(this.params) - : super(token: _token); - - static final Object _token = Object(); - - /// The parameters used to initialize the [PlatformFindInteractionController]. - final PlatformFindInteractionControllerCreationParams params; - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionControllerCreationParams.onFindResultReceived} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionControllerCreationParams.onFindResultReceived.supported_platforms} - void Function( - PlatformFindInteractionController controller, - int activeMatchOrdinal, - int numberOfMatches, - bool isDoneCounting, - )? - get onFindResultReceived => params.onFindResultReceived; - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.findAll} - ///Finds all instances of find on the page and highlights them. Notifies [PlatformFindInteractionController.onFindResultReceived] listener. - /// - ///[find] represents the string to find. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findAll.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebView.findAllAsync', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebView#findAllAsync(java.lang.String)', - note: - 'It finds all instances asynchronously. Successive calls to this will cancel any pending searches.', - ), - IOSPlatform( - note: - 'If [InAppWebViewSettings.isFindInteractionEnabled] is `true`, it uses the built-in find interaction native UI, otherwise this is implemented using CSS and Javascript. In this case, it will use the [Official API - UIFindInteraction.presentFindNavigator](https://developer.apple.com/documentation/uikit/uifindinteraction/3975832-presentfindnavigator?changes=_2) with [Official API - UIFindInteraction.searchText](https://developer.apple.com/documentation/uikit/uifindinteraction/3975834-searchtext?changes=_2)', - ), - MacOSPlatform(), - LinuxPlatform( - apiName: 'webkit_find_controller_search', - apiUrl: - 'https://wpewebkit.org/reference/stable/wpe-webkit-2.0/method.FindController.search.html', - ), - WindowsPlatform( - apiName: 'ICoreWebView2Find.Start', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2find#start', - ), - ], - ) - Future findAll({String? find}) { - throw UnimplementedError( - 'findAll is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.setFindOptions} - ///Sets the options used for find-on-page operations. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.setFindOptions.supported_platforms} - @SupportedPlatforms( - platforms: [ - WindowsPlatform( - apiName: 'ICoreWebView2Environment15.CreateFindOptions', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environment15?view=webview2-1.0.2849.39#createfindoptions', - ), - ], - ) - Future setFindOptions({FindOptions? options}) { - throw UnimplementedError( - 'setFindOptions is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.findNext} - ///Highlights and scrolls to the next match found by [findAll]. Notifies [PlatformFindInteractionController.onFindResultReceived] listener. - /// - ///[forward] represents the direction to search. The default value is `true`, meaning forward. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.findNext.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebView.findNext', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebView#findNext(boolean)', - ), - IOSPlatform( - note: - 'If [InAppWebViewSettings.isFindInteractionEnabled] is `true`, it uses the built-in find interaction native UI, otherwise this is implemented using CSS and Javascript. In this case, it will use the [Official API - UIFindInteraction.findNext](https://developer.apple.com/documentation/uikit/uifindinteraction/3975829-findnext?changes=_2) and ([Official API - UIFindInteraction.findPrevious](https://developer.apple.com/documentation/uikit/uifindinteraction/3975830-findprevious?changes=_2)', - ), - MacOSPlatform(), - LinuxPlatform( - apiName: 'webkit_find_controller_search_next', - apiUrl: - 'https://wpewebkit.org/reference/stable/wpe-webkit-2.0/method.FindController.search_next.html', - ), - WindowsPlatform( - apiName: 'ICoreWebView2Find.FindNext/FindPrevious', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2find#findnext', - ), - ], - ) - Future findNext({bool forward = true}) { - throw UnimplementedError( - 'findNext is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.clearMatches} - ///Clears the highlighting surrounding text matches created by [findAll]. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.clearMatches.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebView.clearMatches', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebView#clearMatches()', - ), - IOSPlatform( - note: - 'If [InAppWebViewSettings.isFindInteractionEnabled] is `true`, it uses the built-in find interaction native UI, otherwise this is implemented using CSS and Javascript. In this case, it will use the [Official API - UIFindInteraction.dismissFindNavigator](https://developer.apple.com/documentation/uikit/uifindinteraction/3975827-dismissfindnavigator?changes=_2)', - ), - MacOSPlatform(), - LinuxPlatform( - apiName: 'webkit_find_controller_search_finish', - apiUrl: - 'https://wpewebkit.org/reference/stable/wpe-webkit-2.0/method.FindController.search_finish.html', - ), - WindowsPlatform( - apiName: 'ICoreWebView2Find.Stop', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2find#stop', - ), - ], - ) - Future clearMatches() { - throw UnimplementedError( - 'clearMatches is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.setSearchText} - ///Pre-populate the search text to be used. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.setSearchText.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform( - apiName: 'UIFindInteraction.searchText', - apiUrl: - 'https://developer.apple.com/documentation/uikit/uifindinteraction/3975834-searchtext?changes=_2', - note: - 'If [InAppWebViewSettings.isFindInteractionEnabled] is `true`, it will pre-populate the system find panel\'s search text field with a search query.', - ), - MacOSPlatform(), - LinuxPlatform( - apiName: 'webkit_find_controller_search', - apiUrl: - 'https://wpewebkit.org/reference/stable/wpe-webkit-2.0/method.FindController.search.html', - ), - WindowsPlatform( - apiName: 'ICoreWebView2FindOptions.put_FindTerm', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2findoptions', - ), - ], - ) - Future setSearchText(String? searchText) { - throw UnimplementedError( - 'setSearchText is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.getSearchText} - ///Get the search text used. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getSearchText.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform( - apiName: 'UIFindInteraction.getSearchText', - apiUrl: - 'https://developer.apple.com/documentation/uikit/uifindinteraction/3975834-searchtext?changes=_2', - note: - 'If [InAppWebViewSettings.isFindInteractionEnabled] is `true`, it will get the system find panel\'s search text field value.', - ), - MacOSPlatform(), - LinuxPlatform( - apiName: 'webkit_find_controller_get_search_text', - apiUrl: - 'https://wpewebkit.org/reference/stable/wpe-webkit-2.0/method.FindController.get_search_text.html', - ), - WindowsPlatform(), - ], - ) - Future getSearchText() { - throw UnimplementedError( - 'getSearchText is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.isFindNavigatorVisible} - ///A Boolean value that indicates when the find panel displays onscreen. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.isFindNavigatorVisible.supported_platforms} - @SupportedPlatforms( - platforms: [ - IOSPlatform( - apiName: 'UIFindInteraction.isFindNavigatorVisible', - apiUrl: - 'https://developer.apple.com/documentation/uikit/uifindinteraction/3975828-isfindnavigatorvisible?changes=_2', - note: - 'Available only if [InAppWebViewSettings.isFindInteractionEnabled] is `true`.', - ), - ], - ) - Future isFindNavigatorVisible() { - throw UnimplementedError( - 'isFindNavigatorVisible is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.updateResultCount} - ///Updates the results the interface displays for the active search. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.updateResultCount.supported_platforms} - @SupportedPlatforms( - platforms: [ - IOSPlatform( - apiName: 'UIFindInteraction.updateResultCount', - apiUrl: - 'https://developer.apple.com/documentation/uikit/uifindinteraction/3975835-updateresultcount?changes=_2', - note: - 'Available only if [InAppWebViewSettings.isFindInteractionEnabled] is `true`.', - ), - ], - ) - Future updateResultCount() { - throw UnimplementedError( - 'updateResultCount is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.presentFindNavigator} - ///Begins a search, displaying the find panel. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.presentFindNavigator.supported_platforms} - @SupportedPlatforms( - platforms: [ - IOSPlatform( - apiName: 'UIFindInteraction.presentFindNavigator', - apiUrl: - 'https://developer.apple.com/documentation/uikit/uifindinteraction/3975832-presentfindnavigator?changes=_2', - note: - 'Available only if [InAppWebViewSettings.isFindInteractionEnabled] is `true`.', - ), - ], - ) - Future presentFindNavigator() { - throw UnimplementedError( - 'presentFindNavigator is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.dismissFindNavigator} - ///Dismisses the find panel, if present. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.dismissFindNavigator.supported_platforms} - @SupportedPlatforms( - platforms: [ - IOSPlatform( - apiName: 'UIFindInteraction.dismissFindNavigator', - apiUrl: - 'https://developer.apple.com/documentation/uikit/uifindinteraction/3975827-dismissfindnavigator?changes=_2', - note: - 'Available only if [InAppWebViewSettings.isFindInteractionEnabled] is `true`.', - ), - ], - ) - Future dismissFindNavigator() { - throw UnimplementedError( - 'dismissFindNavigator is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.getActiveFindSession} - ///If there's a currently active find session, returns the active find session. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.getActiveFindSession.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform( - apiName: 'UIFindInteraction.activeFindSession', - apiUrl: - 'https://developer.apple.com/documentation/uikit/uifindinteraction/3975825-activefindsession?changes=_7____4_8&language=objc', - ), - MacOSPlatform(), - LinuxPlatform( - apiName: 'WebKitFindController', - apiUrl: - 'https://wpewebkit.org/reference/stable/wpe-webkit-2.0/class.FindController.html', - ), - WindowsPlatform( - apiName: 'ICoreWebView2Find', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2find', - ), - ], - ) - Future getActiveFindSession() { - throw UnimplementedError( - 'getActiveFindSession is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.dispose} - ///Disposes the controller. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionController.dispose.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - LinuxPlatform(), - WindowsPlatform(), - ], - ) - @override - void dispose({bool isKeepAlive = false}) { - throw UnimplementedError( - 'dispose is not implemented on the current platform', - ); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionControllerCreationParams.isClassSupported} - bool isClassSupported({TargetPlatform? platform}) => - params.isClassSupported(platform: platform); - - ///{@macro flutter_inappwebview_platform_interface.PlatformFindInteractionControllerCreationParams.isPropertySupported} - bool isPropertySupported( - PlatformFindInteractionControllerCreationParamsProperty property, { - TargetPlatform? platform, - }) => params.isPropertySupported(property, platform: platform); - - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.isMethodSupported} - ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. - ///{@endtemplate} - bool isMethodSupported( - PlatformFindInteractionControllerMethod method, { - TargetPlatform? platform, - }) => _PlatformFindInteractionControllerMethodSupported.isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview_platform_interface/lib/src/find_interaction/platform_find_interaction_controller.g.dart b/flutter_inappwebview_platform_interface/lib/src/find_interaction/platform_find_interaction_controller.g.dart deleted file mode 100644 index d44e2e877d..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/find_interaction/platform_find_interaction_controller.g.dart +++ /dev/null @@ -1,382 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'platform_find_interaction_controller.dart'; - -// ************************************************************************** -// SupportedPlatformsGenerator -// ************************************************************************** - -extension _PlatformFindInteractionControllerCreationParamsClassSupported - on PlatformFindInteractionControllerCreationParams { - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionControllerCreationParams.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Linux WPE WebKit - ///- Windows WebView2 - /// - ///Use the [PlatformFindInteractionControllerCreationParams.isClassSupported] method to check if this class is supported at runtime. - ///{@endtemplate} - static bool isClassSupported({TargetPlatform? platform}) { - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.linux, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - } -} - -///List of [PlatformFindInteractionControllerCreationParams]'s properties that can be used to check i they are supported or not by the current platform. -enum PlatformFindInteractionControllerCreationParamsProperty { - ///Can be used to check if the [PlatformFindInteractionControllerCreationParams.onFindResultReceived] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionControllerCreationParams.onFindResultReceived.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebView.FindListener.onFindResultReceived](https://developer.android.com/reference/android/webkit/WebView.FindListener#onFindResultReceived(int,%20int,%20boolean))) - ///- iOS WKWebView: - /// - If [InAppWebViewSettings.isFindInteractionEnabled] is `true`, this event will not be called. - ///- macOS WKWebView - ///- Linux WPE WebKit ([Official API - WebKitFindController::counted-matches](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/signal.FindController.counted-matches.html)) - ///- Windows WebView2 ([Official API - ICoreWebView2Find.ActiveMatchIndexChanged/MatchCountChanged](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2find)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [controller]: all platforms - ///- [activeMatchOrdinal]: all platforms - ///- [numberOfMatches]: all platforms - ///- [isDoneCounting]: all platforms - /// - ///Use the [PlatformFindInteractionControllerCreationParams.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - onFindResultReceived, -} - -extension _PlatformFindInteractionControllerCreationParamsPropertySupported - on PlatformFindInteractionControllerCreationParams { - static bool isPropertySupported( - PlatformFindInteractionControllerCreationParamsProperty property, { - TargetPlatform? platform, - }) { - switch (property) { - case PlatformFindInteractionControllerCreationParamsProperty - .onFindResultReceived: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.linux, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - } - } -} - -extension _PlatformFindInteractionControllerClassSupported - on PlatformFindInteractionController { - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Linux WPE WebKit - ///- Windows WebView2 - /// - ///Use the [PlatformFindInteractionController.isClassSupported] method to check if this class is supported at runtime. - ///{@endtemplate} - static bool isClassSupported({TargetPlatform? platform}) { - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.linux, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - } -} - -///List of [PlatformFindInteractionController]'s methods that can be used to check if they are supported or not by the current platform. -enum PlatformFindInteractionControllerMethod { - ///Can be used to check if the [PlatformFindInteractionController.clearMatches] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.clearMatches.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebView.clearMatches](https://developer.android.com/reference/android/webkit/WebView#clearMatches())) - ///- iOS WKWebView: - /// - If [InAppWebViewSettings.isFindInteractionEnabled] is `true`, it uses the built-in find interaction native UI, otherwise this is implemented using CSS and Javascript. In this case, it will use the [Official API - UIFindInteraction.dismissFindNavigator](https://developer.apple.com/documentation/uikit/uifindinteraction/3975827-dismissfindnavigator?changes=_2) - ///- macOS WKWebView - ///- Linux WPE WebKit ([Official API - webkit_find_controller_search_finish](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/method.FindController.search_finish.html)) - ///- Windows WebView2 ([Official API - ICoreWebView2Find.Stop](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2find#stop)) - /// - ///Use the [PlatformFindInteractionController.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - clearMatches, - - ///Can be used to check if the [PlatformFindInteractionController.dismissFindNavigator] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.dismissFindNavigator.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView ([Official API - UIFindInteraction.dismissFindNavigator](https://developer.apple.com/documentation/uikit/uifindinteraction/3975827-dismissfindnavigator?changes=_2)): - /// - Available only if [InAppWebViewSettings.isFindInteractionEnabled] is `true`. - /// - ///Use the [PlatformFindInteractionController.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - dismissFindNavigator, - - ///Can be used to check if the [PlatformFindInteractionController.dispose] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.dispose.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Linux WPE WebKit - ///- Windows WebView2 - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [isKeepAlive]: all platforms - /// - ///Use the [PlatformFindInteractionController.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - dispose, - - ///Can be used to check if the [PlatformFindInteractionController.findAll] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.findAll.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebView.findAllAsync](https://developer.android.com/reference/android/webkit/WebView#findAllAsync(java.lang.String))): - /// - It finds all instances asynchronously. Successive calls to this will cancel any pending searches. - ///- iOS WKWebView: - /// - If [InAppWebViewSettings.isFindInteractionEnabled] is `true`, it uses the built-in find interaction native UI, otherwise this is implemented using CSS and Javascript. In this case, it will use the [Official API - UIFindInteraction.presentFindNavigator](https://developer.apple.com/documentation/uikit/uifindinteraction/3975832-presentfindnavigator?changes=_2) with [Official API - UIFindInteraction.searchText](https://developer.apple.com/documentation/uikit/uifindinteraction/3975834-searchtext?changes=_2) - ///- macOS WKWebView - ///- Linux WPE WebKit ([Official API - webkit_find_controller_search](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/method.FindController.search.html)) - ///- Windows WebView2 ([Official API - ICoreWebView2Find.Start](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2find#start)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [find]: all platforms - /// - ///Use the [PlatformFindInteractionController.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - findAll, - - ///Can be used to check if the [PlatformFindInteractionController.findNext] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.findNext.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebView.findNext](https://developer.android.com/reference/android/webkit/WebView#findNext(boolean))) - ///- iOS WKWebView: - /// - If [InAppWebViewSettings.isFindInteractionEnabled] is `true`, it uses the built-in find interaction native UI, otherwise this is implemented using CSS and Javascript. In this case, it will use the [Official API - UIFindInteraction.findNext](https://developer.apple.com/documentation/uikit/uifindinteraction/3975829-findnext?changes=_2) and ([Official API - UIFindInteraction.findPrevious](https://developer.apple.com/documentation/uikit/uifindinteraction/3975830-findprevious?changes=_2) - ///- macOS WKWebView - ///- Linux WPE WebKit ([Official API - webkit_find_controller_search_next](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/method.FindController.search_next.html)) - ///- Windows WebView2 ([Official API - ICoreWebView2Find.FindNext/FindPrevious](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2find#findnext)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [forward]: all platforms - /// - ///Use the [PlatformFindInteractionController.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - findNext, - - ///Can be used to check if the [PlatformFindInteractionController.getActiveFindSession] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.getActiveFindSession.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView ([Official API - UIFindInteraction.activeFindSession](https://developer.apple.com/documentation/uikit/uifindinteraction/3975825-activefindsession?changes=_7____4_8&language=objc)) - ///- macOS WKWebView - ///- Linux WPE WebKit ([Official API - WebKitFindController](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/class.FindController.html)) - ///- Windows WebView2 ([Official API - ICoreWebView2Find](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2find)) - /// - ///Use the [PlatformFindInteractionController.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - getActiveFindSession, - - ///Can be used to check if the [PlatformFindInteractionController.getSearchText] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.getSearchText.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView ([Official API - UIFindInteraction.getSearchText](https://developer.apple.com/documentation/uikit/uifindinteraction/3975834-searchtext?changes=_2)): - /// - If [InAppWebViewSettings.isFindInteractionEnabled] is `true`, it will get the system find panel's search text field value. - ///- macOS WKWebView - ///- Linux WPE WebKit ([Official API - webkit_find_controller_get_search_text](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/method.FindController.get_search_text.html)) - ///- Windows WebView2 - /// - ///Use the [PlatformFindInteractionController.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - getSearchText, - - ///Can be used to check if the [PlatformFindInteractionController.isFindNavigatorVisible] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.isFindNavigatorVisible.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView ([Official API - UIFindInteraction.isFindNavigatorVisible](https://developer.apple.com/documentation/uikit/uifindinteraction/3975828-isfindnavigatorvisible?changes=_2)): - /// - Available only if [InAppWebViewSettings.isFindInteractionEnabled] is `true`. - /// - ///Use the [PlatformFindInteractionController.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - isFindNavigatorVisible, - - ///Can be used to check if the [PlatformFindInteractionController.presentFindNavigator] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.presentFindNavigator.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView ([Official API - UIFindInteraction.presentFindNavigator](https://developer.apple.com/documentation/uikit/uifindinteraction/3975832-presentfindnavigator?changes=_2)): - /// - Available only if [InAppWebViewSettings.isFindInteractionEnabled] is `true`. - /// - ///Use the [PlatformFindInteractionController.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - presentFindNavigator, - - ///Can be used to check if the [PlatformFindInteractionController.setFindOptions] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.setFindOptions.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Windows WebView2 ([Official API - ICoreWebView2Environment15.CreateFindOptions](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environment15?view=webview2-1.0.2849.39#createfindoptions)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [options]: all platforms - /// - ///Use the [PlatformFindInteractionController.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - setFindOptions, - - ///Can be used to check if the [PlatformFindInteractionController.setSearchText] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.setSearchText.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView ([Official API - UIFindInteraction.searchText](https://developer.apple.com/documentation/uikit/uifindinteraction/3975834-searchtext?changes=_2)): - /// - If [InAppWebViewSettings.isFindInteractionEnabled] is `true`, it will pre-populate the system find panel's search text field with a search query. - ///- macOS WKWebView - ///- Linux WPE WebKit ([Official API - webkit_find_controller_search](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/method.FindController.search.html)) - ///- Windows WebView2 ([Official API - ICoreWebView2FindOptions.put_FindTerm](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2findoptions)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [searchText]: all platforms - /// - ///Use the [PlatformFindInteractionController.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - setSearchText, - - ///Can be used to check if the [PlatformFindInteractionController.updateResultCount] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformFindInteractionController.updateResultCount.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView ([Official API - UIFindInteraction.updateResultCount](https://developer.apple.com/documentation/uikit/uifindinteraction/3975835-updateresultcount?changes=_2)): - /// - Available only if [InAppWebViewSettings.isFindInteractionEnabled] is `true`. - /// - ///Use the [PlatformFindInteractionController.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - updateResultCount, -} - -extension _PlatformFindInteractionControllerMethodSupported - on PlatformFindInteractionController { - static bool isMethodSupported( - PlatformFindInteractionControllerMethod method, { - TargetPlatform? platform, - }) { - switch (method) { - case PlatformFindInteractionControllerMethod.clearMatches: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.linux, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformFindInteractionControllerMethod.dismissFindNavigator: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case PlatformFindInteractionControllerMethod.dispose: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.linux, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformFindInteractionControllerMethod.findAll: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.linux, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformFindInteractionControllerMethod.findNext: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.linux, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformFindInteractionControllerMethod.getActiveFindSession: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.linux, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformFindInteractionControllerMethod.getSearchText: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.linux, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformFindInteractionControllerMethod.isFindNavigatorVisible: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case PlatformFindInteractionControllerMethod.presentFindNavigator: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case PlatformFindInteractionControllerMethod.setFindOptions: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformFindInteractionControllerMethod.setSearchText: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.linux, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformFindInteractionControllerMethod.updateResultCount: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - } - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/android/in_app_browser_options.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_browser/android/in_app_browser_options.dart deleted file mode 100755 index 8cbb12b9e3..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/android/in_app_browser_options.dart +++ /dev/null @@ -1,69 +0,0 @@ -import '../../in_app_webview/android/in_app_webview_options.dart'; - -import '../in_app_browser_settings.dart'; -import '../platform_in_app_browser.dart'; - -///This class represents all the Android-only [PlatformInAppBrowser] options available. -///Use [InAppBrowserSettings] instead. -@Deprecated('Use InAppBrowserSettings instead') -class AndroidInAppBrowserOptions implements BrowserOptions, AndroidOptions { - ///Set to `true` if you want the title should be displayed. The default value is `false`. - bool hideTitleBar; - - ///Set the action bar's title. - String? toolbarTopFixedTitle; - - ///Set to `false` to not close the InAppBrowser when the user click on the Android back button and the WebView cannot go back to the history. The default value is `true`. - bool closeOnCannotGoBack; - - ///Set to `false` to block the InAppBrowser WebView going back when the user click on the Android back button. The default value is `true`. - bool allowGoBackWithBackButton; - - ///Set to `true` to close the InAppBrowser when the user click on the Android back button. The default value is `false`. - bool shouldCloseOnBackButtonPressed; - - AndroidInAppBrowserOptions({ - this.hideTitleBar = false, - this.toolbarTopFixedTitle, - this.closeOnCannotGoBack = true, - this.allowGoBackWithBackButton = true, - this.shouldCloseOnBackButtonPressed = false, - }); - - @override - Map toMap() { - return { - "hideTitleBar": hideTitleBar, - "toolbarTopFixedTitle": toolbarTopFixedTitle, - "closeOnCannotGoBack": closeOnCannotGoBack, - "allowGoBackWithBackButton": allowGoBackWithBackButton, - "shouldCloseOnBackButtonPressed": shouldCloseOnBackButtonPressed, - }; - } - - static AndroidInAppBrowserOptions fromMap(Map map) { - var instance = AndroidInAppBrowserOptions(); - instance.hideTitleBar = map["hideTitleBar"]; - instance.toolbarTopFixedTitle = map["toolbarTopFixedTitle"]; - instance.closeOnCannotGoBack = map["closeOnCannotGoBack"]; - instance.allowGoBackWithBackButton = map["allowGoBackWithBackButton"]; - instance.shouldCloseOnBackButtonPressed = - map["shouldCloseOnBackButtonPressed"]; - return instance; - } - - @override - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } - - @override - AndroidInAppBrowserOptions copy() { - return AndroidInAppBrowserOptions.fromMap(this.toMap()); - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/android/main.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_browser/android/main.dart deleted file mode 100644 index 3e70195763..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/android/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'in_app_browser_options.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/apple/in_app_browser_options.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_browser/apple/in_app_browser_options.dart deleted file mode 100755 index 7666064fa6..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/apple/in_app_browser_options.dart +++ /dev/null @@ -1,116 +0,0 @@ -import 'dart:ui'; - -import '../../in_app_webview/apple/in_app_webview_options.dart'; - -import '../in_app_browser_settings.dart'; -import '../platform_in_app_browser.dart'; - -import '../../types/main.dart'; -import '../../util.dart'; - -///This class represents all the iOS-only [PlatformInAppBrowser] options available. -///Use [InAppBrowserSettings] instead. -@Deprecated('Use InAppBrowserSettings instead') -class IOSInAppBrowserOptions implements BrowserOptions, IosOptions { - ///Set to `true` to set the toolbar at the top translucent. The default value is `true`. - bool toolbarTopTranslucent; - - ///Set the tint color to apply to the navigation bar background. - Color? toolbarTopBarTintColor; - - ///Set the tint color to apply to the navigation items and bar button items. - Color? toolbarTopTintColor; - - ///Set to `true` to hide the toolbar at the bottom of the WebView. The default value is `false`. - bool hideToolbarBottom; - - ///Set the custom background color of the toolbar at the bottom. - Color? toolbarBottomBackgroundColor; - - ///Set the tint color to apply to the bar button items. - Color? toolbarBottomTintColor; - - ///Set to `true` to set the toolbar at the bottom translucent. The default value is `true`. - bool toolbarBottomTranslucent; - - ///Set the custom text for the close button. - String? closeButtonCaption; - - ///Set the custom color for the close button. - Color? closeButtonColor; - - ///Set the custom modal presentation style when presenting the WebView. The default value is [IOSUIModalPresentationStyle.FULL_SCREEN]. - IOSUIModalPresentationStyle presentationStyle; - - ///Set to the custom transition style when presenting the WebView. The default value is [IOSUIModalTransitionStyle.COVER_VERTICAL]. - IOSUIModalTransitionStyle transitionStyle; - - IOSInAppBrowserOptions({ - this.toolbarTopTranslucent = true, - this.toolbarTopTintColor, - this.hideToolbarBottom = false, - this.toolbarBottomBackgroundColor, - this.toolbarBottomTintColor, - this.toolbarBottomTranslucent = true, - this.closeButtonCaption, - this.closeButtonColor, - this.presentationStyle = IOSUIModalPresentationStyle.FULL_SCREEN, - this.transitionStyle = IOSUIModalTransitionStyle.COVER_VERTICAL, - }); - - @override - Map toMap() { - return { - "toolbarTopTranslucent": toolbarTopTranslucent, - "toolbarTopTintColor": toolbarTopTintColor?.toHex(), - "hideToolbarBottom": hideToolbarBottom, - "toolbarBottomBackgroundColor": toolbarBottomBackgroundColor?.toHex(), - "toolbarBottomTintColor": toolbarBottomTintColor?.toHex(), - "toolbarBottomTranslucent": toolbarBottomTranslucent, - "closeButtonCaption": closeButtonCaption, - "closeButtonColor": closeButtonColor?.toHex(), - "presentationStyle": presentationStyle.toNativeValue(), - "transitionStyle": transitionStyle.toNativeValue(), - }; - } - - static IOSInAppBrowserOptions fromMap(Map map) { - var instance = IOSInAppBrowserOptions(); - instance.toolbarTopTranslucent = map["toolbarTopTranslucent"]; - instance.toolbarTopTintColor = UtilColor.fromHex( - map["toolbarTopTintColor"], - ); - instance.hideToolbarBottom = map["hideToolbarBottom"]; - instance.toolbarBottomBackgroundColor = UtilColor.fromHex( - map["toolbarBottomBackgroundColor"], - ); - instance.toolbarBottomTintColor = UtilColor.fromHex( - map["toolbarBottomTintColor"], - ); - instance.toolbarBottomTranslucent = map["toolbarBottomTranslucent"]; - instance.closeButtonCaption = map["closeButtonCaption"]; - instance.closeButtonColor = UtilColor.fromHex(map["closeButtonColor"]); - instance.presentationStyle = IOSUIModalPresentationStyle.fromNativeValue( - map["presentationStyle"], - )!; - instance.transitionStyle = IOSUIModalTransitionStyle.fromNativeValue( - map["transitionStyle"], - )!; - return instance; - } - - @override - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } - - @override - IOSInAppBrowserOptions copy() { - return IOSInAppBrowserOptions.fromMap(this.toMap()); - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/apple/main.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_browser/apple/main.dart deleted file mode 100644 index 3e70195763..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/apple/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'in_app_browser_options.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_menu_item.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_menu_item.dart deleted file mode 100644 index de07dc7d45..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_menu_item.dart +++ /dev/null @@ -1,88 +0,0 @@ -import 'dart:typed_data'; -import 'dart:ui'; - -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; - -import '../util.dart'; - -import 'platform_in_app_browser.dart'; -import '../types/main.dart'; -import '../types/enum_method.dart'; - -part 'in_app_browser_menu_item.g.dart'; - -dynamic _serializeIcon(dynamic icon, {EnumMethod? enumMethod}) { - return icon is Uint8List ? icon : icon?.toMap(enumMethod: enumMethod); -} - -dynamic _deserializeIcon(dynamic icon, {EnumMethod? enumMethod}) { - if (icon is Uint8List) { - return icon; - } - if (icon is Map) { - final iconMap = icon as Map; - if (iconMap.containsKey('defType')) { - return AndroidResource.fromMap(iconMap, enumMethod: enumMethod); - } - if (iconMap.containsKey('systemName')) { - return UIImage.fromMap(iconMap, enumMethod: enumMethod); - } - } - return null; -} - -///Class that represents a custom menu item for a [PlatformInAppBrowser] instance. -@SupportedPlatforms( - platforms: [AndroidPlatform(), IOSPlatform(), MacOSPlatform()], -) -@ExchangeableObject() -class InAppBrowserMenuItem_ { - ///The menu item id. - int id; - - ///The title of the menu item. - String title; - - ///Item icon. - @ExchangeableObjectProperty( - serializer: _serializeIcon, - deserializer: _deserializeIcon, - ) - dynamic icon; - - ///Icon color. - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(available: "13.0"), - MacOSPlatform(), - ], - ) - Color_? iconColor; - - ///Item order. - int? order; - - ///Show this item as a button in the Action Bar. - bool showAsAction; - - ///Callback function to be invoked when the menu item is clicked - void Function()? onClick; - - InAppBrowserMenuItem_({ - required this.id, - required this.title, - this.icon, - this.iconColor, - this.onClick, - this.order, - this.showAsAction = false, - }) { - assert( - this.icon == null || - this.icon is Uint8List || - this.icon is UIImage || - this.icon is AndroidResource, - ); - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_menu_item.g.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_menu_item.g.dart deleted file mode 100644 index 3f8ec1546b..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_menu_item.g.dart +++ /dev/null @@ -1,101 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'in_app_browser_menu_item.dart'; - -// ************************************************************************** -// ExchangeableObjectGenerator -// ************************************************************************** - -///Class that represents a custom menu item for a [PlatformInAppBrowser] instance. -/// -///**Officially Supported Platforms/Implementations**: -///- Android WebView -///- iOS WKWebView -///- macOS WKWebView -class InAppBrowserMenuItem { - ///Item icon. - dynamic icon; - - ///Icon color. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView 13.0+ - ///- macOS WKWebView - Color? iconColor; - - ///The menu item id. - int id; - - ///Callback function to be invoked when the menu item is clicked - void Function()? onClick; - - ///Item order. - int? order; - - ///Show this item as a button in the Action Bar. - bool showAsAction; - - ///The title of the menu item. - String title; - - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - InAppBrowserMenuItem({ - this.icon, - this.iconColor, - required this.id, - this.onClick, - this.order, - this.showAsAction = false, - required this.title, - }); - - ///Gets a possible [InAppBrowserMenuItem] instance from a [Map] value. - static InAppBrowserMenuItem? fromMap( - Map? map, { - EnumMethod? enumMethod, - }) { - if (map == null) { - return null; - } - final instance = InAppBrowserMenuItem( - icon: _deserializeIcon(map['icon'], enumMethod: enumMethod), - iconColor: map['iconColor'] != null - ? UtilColor.fromStringRepresentation(map['iconColor']) - : null, - id: map['id'], - order: map['order'], - title: map['title'], - ); - if (map['showAsAction'] != null) { - instance.showAsAction = map['showAsAction']; - } - return instance; - } - - ///Converts instance to a map. - Map toMap({EnumMethod? enumMethod}) { - return { - "icon": _serializeIcon(icon, enumMethod: enumMethod), - "iconColor": iconColor?.toHex(), - "id": id, - "order": order, - "showAsAction": showAsAction, - "title": title, - }; - } - - ///Converts instance to a map. - Map toJson() { - return toMap(); - } - - @override - String toString() { - return 'InAppBrowserMenuItem{icon: $icon, iconColor: $iconColor, id: $id, order: $order, showAsAction: $showAsAction, title: $title}'; - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_settings.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_settings.dart deleted file mode 100755 index 05071bfc43..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_settings.dart +++ /dev/null @@ -1,510 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; - -import '../types/in_app_webview_rect.dart'; -import '../types/modal_presentation_style.dart'; -import '../types/modal_transition_style.dart'; -import '../types/window_style_mask.dart'; -import '../types/window_titlebar_separator_style.dart'; -import '../types/window_type.dart'; -import '../util.dart'; - -import '../in_app_webview/in_app_webview_settings.dart'; - -import 'android/in_app_browser_options.dart'; -import '../in_app_webview/android/in_app_webview_options.dart'; - -import 'apple/in_app_browser_options.dart'; -import '../in_app_webview/apple/in_app_webview_options.dart'; -import '../types/enum_method.dart'; - -part 'in_app_browser_settings.g.dart'; - -///Class that represents the settings that can be used for an [InAppBrowser] instance. -class InAppBrowserClassSettings { - ///Browser settings. - late InAppBrowserSettings browserSettings; - - ///WebView settings. - late InAppWebViewSettings webViewSettings; - - InAppBrowserClassSettings({ - InAppBrowserSettings? browserSettings, - InAppWebViewSettings? webViewSettings, - }) { - this.browserSettings = browserSettings ?? InAppBrowserSettings(); - this.webViewSettings = webViewSettings ?? InAppWebViewSettings(); - } - - Map toMap() { - Map options = {}; - - options.addAll(browserSettings.toMap()); - options.addAll(webViewSettings.toMap()); - - return options; - } - - Map toJson() { - return toMap(); - } - - String toString() { - return toMap().toString(); - } - - factory InAppBrowserClassSettings.fromMap( - Map options, { - InAppBrowserClassSettings? instance, - EnumMethod? enumMethod, - }) { - if (instance == null) { - instance = InAppBrowserClassSettings(); - } - instance.browserSettings = - InAppBrowserSettings.fromMap(options, enumMethod: enumMethod) ?? - InAppBrowserSettings(); - instance.webViewSettings = - InAppWebViewSettings.fromMap(options, enumMethod: enumMethod) ?? - InAppWebViewSettings(); - return instance; - } - - InAppBrowserClassSettings copy() { - return InAppBrowserClassSettings.fromMap(toMap()); - } -} - -class BrowserOptions { - Map toMap() { - return {}; - } - - static BrowserOptions fromMap(Map map) { - return BrowserOptions(); - } - - BrowserOptions copy() { - return BrowserOptions.fromMap(this.toMap()); - } - - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } -} - -///{@template flutter_inappwebview_platform_interface.InAppWebViewSettings} -///This class represents all [InAppBrowser] settings available. -///{@endtemplate} -@ExchangeableObject(copyMethod: true) -@SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform( - apiName: 'GtkWindow', - apiUrl: 'https://docs.gtk.org/gtk3/class.Window.html', - ), - ], -) -class InAppBrowserSettings_ - implements BrowserOptions, AndroidOptions, IosOptions { - ///Set to `true` to create the browser and load the page, but not show it. Omit or set to `false` to have the browser open and load normally. - ///The default value is `false`. - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - bool? hidden; - - ///Set to `true` to hide the toolbar at the top of the WebView. The default value is `false`. - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - LinuxPlatform(), - ], - ) - bool? hideToolbarTop; - - ///Set the custom background color of the toolbar at the top. - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - LinuxPlatform(), - ], - ) - Color_? toolbarTopBackgroundColor; - - ///Set to `true` to hide the url bar on the toolbar at the top. The default value is `false`. - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - LinuxPlatform(), - ], - ) - bool? hideUrlBar; - - ///Set to `true` to hide the progress bar when the WebView is loading a page. The default value is `false`. - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - LinuxPlatform(), - ], - ) - bool? hideProgressBar; - - ///Set to `true` to hide the default menu items. The default value is `false`. - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - LinuxPlatform(), - ], - ) - bool? hideDefaultMenuItems; - - ///Set to `true` if you want the title should be displayed. The default value is `false`. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - bool? hideTitleBar; - - ///Set the action bar's title. - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - String? toolbarTopFixedTitle; - - ///Set to `false` to not close the InAppBrowser when the user click on the Android back button and the WebView cannot go back to the history. The default value is `true`. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - bool? closeOnCannotGoBack; - - ///Set to `false` to block the InAppBrowser WebView going back when the user click on the Android back button. The default value is `true`. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - bool? allowGoBackWithBackButton; - - ///Set to `true` to close the InAppBrowser when the user click on the Android back button. The default value is `false`. - @SupportedPlatforms(platforms: [AndroidPlatform()]) - bool? shouldCloseOnBackButtonPressed; - - ///Set to `true` to set the toolbar at the top translucent. The default value is `true`. - @SupportedPlatforms(platforms: [IOSPlatform()]) - bool? toolbarTopTranslucent; - - ///Set the tint color to apply to the navigation bar background. - @SupportedPlatforms(platforms: [IOSPlatform()]) - Color_? toolbarTopBarTintColor; - - ///Set the tint color to apply to the navigation items and bar button items. - @SupportedPlatforms(platforms: [IOSPlatform()]) - Color_? toolbarTopTintColor; - - ///Set to `true` to hide the toolbar at the bottom of the WebView. The default value is `false`. - @SupportedPlatforms(platforms: [IOSPlatform()]) - bool? hideToolbarBottom; - - ///Set the custom background color of the toolbar at the bottom. - @SupportedPlatforms(platforms: [IOSPlatform()]) - Color_? toolbarBottomBackgroundColor; - - ///Set the tint color to apply to the bar button items. - @SupportedPlatforms(platforms: [IOSPlatform()]) - Color_? toolbarBottomTintColor; - - ///Set to `true` to set the toolbar at the bottom translucent. The default value is `true`. - @SupportedPlatforms(platforms: [IOSPlatform()]) - bool? toolbarBottomTranslucent; - - ///Set the custom text for the close button. - @SupportedPlatforms(platforms: [IOSPlatform()]) - String? closeButtonCaption; - - ///Set the custom color for the close button. - @SupportedPlatforms(platforms: [IOSPlatform()]) - Color_? closeButtonColor; - - ///Set to `true` to hide the close button. The default value is `false`. - @SupportedPlatforms(platforms: [IOSPlatform()]) - bool? hideCloseButton; - - ///Set the custom color for the menu button. - @SupportedPlatforms(platforms: [IOSPlatform()]) - Color_? menuButtonColor; - - ///Set the custom modal presentation style when presenting the WebView. The default value is [ModalPresentationStyle.FULL_SCREEN]. - @SupportedPlatforms(platforms: [IOSPlatform()]) - ModalPresentationStyle_? presentationStyle; - - ///Set to the custom transition style when presenting the WebView. The default value is [ModalTransitionStyle.COVER_VERTICAL]. - @SupportedPlatforms(platforms: [IOSPlatform()]) - ModalTransitionStyle_? transitionStyle; - - ///How the browser window should be added to the main window. - ///The default value is [WindowType.WINDOW]. - @SupportedPlatforms( - platforms: [MacOSPlatform(), WindowsPlatform(), LinuxPlatform()], - ) - WindowType_? windowType; - - ///The window’s alpha value. - ///The default value is `1.0`. - @SupportedPlatforms( - platforms: [MacOSPlatform(), WindowsPlatform(), LinuxPlatform()], - ) - double? windowAlphaValue; - - ///Flags that describe the window’s current style, such as if it’s resizable or in full-screen mode. - @SupportedPlatforms(platforms: [MacOSPlatform()]) - WindowStyleMask_? windowStyleMask; - - ///The type of separator that the app displays between the title bar and content of a window. - @SupportedPlatforms(platforms: [MacOSPlatform(available: '11.0')]) - WindowTitlebarSeparatorStyle_? windowTitlebarSeparatorStyle; - - ///Sets the origin and size of the window’s frame rectangle according to a given frame rectangle, - ///thereby setting its position and size onscreen. - @SupportedPlatforms( - platforms: [MacOSPlatform(), WindowsPlatform(), LinuxPlatform()], - ) - InAppWebViewRect_? windowFrame; - - InAppBrowserSettings_({ - this.hidden = false, - this.hideToolbarTop = false, - this.toolbarTopBackgroundColor, - this.hideUrlBar = false, - this.hideProgressBar = false, - this.hideDefaultMenuItems = false, - this.toolbarTopTranslucent = true, - this.toolbarTopTintColor, - this.hideToolbarBottom = false, - this.toolbarBottomBackgroundColor, - this.toolbarBottomTintColor, - this.toolbarBottomTranslucent = true, - this.closeButtonCaption, - this.closeButtonColor, - this.hideCloseButton = false, - this.menuButtonColor, - this.presentationStyle = ModalPresentationStyle_.FULL_SCREEN, - this.transitionStyle = ModalTransitionStyle_.COVER_VERTICAL, - this.hideTitleBar = false, - this.toolbarTopFixedTitle, - this.closeOnCannotGoBack = true, - this.allowGoBackWithBackButton = true, - this.shouldCloseOnBackButtonPressed = false, - this.windowType, - this.windowAlphaValue = 1.0, - this.windowStyleMask, - this.windowTitlebarSeparatorStyle, - this.windowFrame, - }); - - @override - @ExchangeableObjectMethod(ignore: true) - InAppBrowserSettings_ copy() { - throw UnimplementedError(); - } - - @override - @ExchangeableObjectMethod(ignore: true) - Map toJson() { - throw UnimplementedError(); - } - - @override - @ExchangeableObjectMethod(ignore: true) - Map toMap() { - throw UnimplementedError(); - } - - ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. - static bool isPropertySupported( - InAppBrowserSettingsProperty property, { - TargetPlatform? platform, - }) => _InAppBrowserSettingsPropertySupported.isPropertySupported( - property, - platform: platform, - ); -} - -///Class that represents the options that can be used for an [InAppBrowser] WebView. -///Use [InAppBrowserClassSettings] instead. -@Deprecated('Use InAppBrowserClassSettings instead') -class InAppBrowserClassOptions { - ///Cross-platform options. - late InAppBrowserOptions crossPlatform; - - ///Android-specific options. - late AndroidInAppBrowserOptions android; - - ///iOS-specific options. - late IOSInAppBrowserOptions ios; - - ///WebView options. - late InAppWebViewGroupOptions inAppWebViewGroupOptions; - - InAppBrowserClassOptions({ - InAppBrowserOptions? crossPlatform, - AndroidInAppBrowserOptions? android, - IOSInAppBrowserOptions? ios, - InAppWebViewGroupOptions? inAppWebViewGroupOptions, - }) { - this.crossPlatform = crossPlatform ?? InAppBrowserOptions(); - this.android = android ?? AndroidInAppBrowserOptions(); - this.ios = ios ?? IOSInAppBrowserOptions(); - this.inAppWebViewGroupOptions = - inAppWebViewGroupOptions ?? InAppWebViewGroupOptions(); - } - - Map toMap() { - Map options = {}; - - options.addAll(this.crossPlatform.toMap()); - options.addAll(this.inAppWebViewGroupOptions.crossPlatform.toMap()); - if (Util.isAndroid) { - options.addAll(this.android.toMap()); - options.addAll(this.inAppWebViewGroupOptions.android.toMap()); - } else if (Util.isIOS) { - options.addAll(this.ios.toMap()); - options.addAll(this.inAppWebViewGroupOptions.ios.toMap()); - } - - return options; - } - - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } - - static InAppBrowserClassOptions fromMap( - Map options, { - EnumMethod? enumMethod, - }) { - InAppBrowserClassOptions inAppBrowserClassOptions = - InAppBrowserClassOptions(); - - inAppBrowserClassOptions.crossPlatform = InAppBrowserOptions.fromMap( - options, - ); - inAppBrowserClassOptions.inAppWebViewGroupOptions = - InAppWebViewGroupOptions(); - inAppBrowserClassOptions.inAppWebViewGroupOptions.crossPlatform = - InAppWebViewOptions.fromMap(options); - if (Util.isAndroid) { - inAppBrowserClassOptions.android = AndroidInAppBrowserOptions.fromMap( - options, - ); - inAppBrowserClassOptions.inAppWebViewGroupOptions.android = - AndroidInAppWebViewOptions.fromMap(options); - } else if (Util.isIOS) { - inAppBrowserClassOptions.ios = IOSInAppBrowserOptions.fromMap(options); - inAppBrowserClassOptions.inAppWebViewGroupOptions.ios = - IOSInAppWebViewOptions.fromMap(options); - } - - return inAppBrowserClassOptions; - } - - InAppBrowserClassOptions copy() { - return InAppBrowserClassOptions.fromMap(this.toMap()); - } -} - -///This class represents all the cross-platform [InAppBrowser] options available. -///Use [InAppBrowserClassSettings] instead. -@Deprecated('Use InAppBrowserClassSettings instead') -class InAppBrowserOptions - implements BrowserOptions, AndroidOptions, IosOptions { - ///Set to `true` to create the browser and load the page, but not show it. Omit or set to `false` to have the browser open and load normally. - ///The default value is `false`. - bool hidden; - - ///Set to `true` to hide the toolbar at the top of the WebView. The default value is `false`. - bool hideToolbarTop; - - ///Set the custom background color of the toolbar at the top. - Color? toolbarTopBackgroundColor; - - ///Set to `true` to hide the url bar on the toolbar at the top. The default value is `false`. - bool hideUrlBar; - - ///Set to `true` to hide the progress bar when the WebView is loading a page. The default value is `false`. - bool hideProgressBar; - - InAppBrowserOptions({ - this.hidden = false, - this.hideToolbarTop = false, - this.toolbarTopBackgroundColor, - this.hideUrlBar = false, - this.hideProgressBar = false, - }); - - @override - Map toMap() { - return { - "hidden": hidden, - "hideToolbarTop": hideToolbarTop, - "toolbarTopBackgroundColor": toolbarTopBackgroundColor?.toHex(), - "hideUrlBar": hideUrlBar, - "hideProgressBar": hideProgressBar, - }; - } - - static InAppBrowserOptions fromMap(Map map) { - var instance = InAppBrowserOptions(); - instance.hidden = map["hidden"]; - instance.hideToolbarTop = map["hideToolbarTop"]; - instance.toolbarTopBackgroundColor = UtilColor.fromHex( - map["toolbarTopBackgroundColor"], - ); - instance.hideUrlBar = map["hideUrlBar"]; - instance.hideProgressBar = map["hideProgressBar"]; - return instance; - } - - @override - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } - - @override - InAppBrowserOptions copy() { - return InAppBrowserOptions.fromMap(this.toMap()); - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_settings.g.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_settings.g.dart deleted file mode 100644 index 7e60d58ccd..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_settings.g.dart +++ /dev/null @@ -1,954 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'in_app_browser_settings.dart'; - -// ************************************************************************** -// ExchangeableObjectGenerator -// ************************************************************************** - -///{@template flutter_inappwebview_platform_interface.InAppWebViewSettings} -///This class represents all [InAppBrowser] settings available. -///{@endtemplate} -/// -///**Officially Supported Platforms/Implementations**: -///- Android WebView -///- iOS WKWebView -///- macOS WKWebView -///- Windows WebView2 -///- Linux WPE WebKit ([Official API - GtkWindow](https://docs.gtk.org/gtk3/class.Window.html)) -class InAppBrowserSettings - implements BrowserOptions, AndroidOptions, IosOptions { - ///Set to `false` to block the InAppBrowser WebView going back when the user click on the Android back button. The default value is `true`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - bool? allowGoBackWithBackButton; - - ///Set the custom text for the close button. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - String? closeButtonCaption; - - ///Set the custom color for the close button. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - Color? closeButtonColor; - - ///Set to `false` to not close the InAppBrowser when the user click on the Android back button and the WebView cannot go back to the history. The default value is `true`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - bool? closeOnCannotGoBack; - - ///Set to `true` to create the browser and load the page, but not show it. Omit or set to `false` to have the browser open and load normally. - ///The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - bool? hidden; - - ///Set to `true` to hide the close button. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - bool? hideCloseButton; - - ///Set to `true` to hide the default menu items. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Linux WPE WebKit - bool? hideDefaultMenuItems; - - ///Set to `true` to hide the progress bar when the WebView is loading a page. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Linux WPE WebKit - bool? hideProgressBar; - - ///Set to `true` if you want the title should be displayed. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - bool? hideTitleBar; - - ///Set to `true` to hide the toolbar at the bottom of the WebView. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - bool? hideToolbarBottom; - - ///Set to `true` to hide the toolbar at the top of the WebView. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Linux WPE WebKit - bool? hideToolbarTop; - - ///Set to `true` to hide the url bar on the toolbar at the top. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Linux WPE WebKit - bool? hideUrlBar; - - ///Set the custom color for the menu button. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - Color? menuButtonColor; - - ///Set the custom modal presentation style when presenting the WebView. The default value is [ModalPresentationStyle.FULL_SCREEN]. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - ModalPresentationStyle? presentationStyle; - - ///Set to `true` to close the InAppBrowser when the user click on the Android back button. The default value is `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - bool? shouldCloseOnBackButtonPressed; - - ///Set the custom background color of the toolbar at the bottom. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - Color? toolbarBottomBackgroundColor; - - ///Set the tint color to apply to the bar button items. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - Color? toolbarBottomTintColor; - - ///Set to `true` to set the toolbar at the bottom translucent. The default value is `true`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - bool? toolbarBottomTranslucent; - - ///Set the custom background color of the toolbar at the top. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Linux WPE WebKit - Color? toolbarTopBackgroundColor; - - ///Set the tint color to apply to the navigation bar background. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - Color? toolbarTopBarTintColor; - - ///Set the action bar's title. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - String? toolbarTopFixedTitle; - - ///Set the tint color to apply to the navigation items and bar button items. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - Color? toolbarTopTintColor; - - ///Set to `true` to set the toolbar at the top translucent. The default value is `true`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - bool? toolbarTopTranslucent; - - ///Set to the custom transition style when presenting the WebView. The default value is [ModalTransitionStyle.COVER_VERTICAL]. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - ModalTransitionStyle? transitionStyle; - - ///The window’s alpha value. - ///The default value is `1.0`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - double? windowAlphaValue; - - ///Sets the origin and size of the window’s frame rectangle according to a given frame rectangle, - ///thereby setting its position and size onscreen. - /// - ///**Officially Supported Platforms/Implementations**: - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - InAppWebViewRect? windowFrame; - - ///Flags that describe the window’s current style, such as if it’s resizable or in full-screen mode. - /// - ///**Officially Supported Platforms/Implementations**: - ///- macOS WKWebView - WindowStyleMask? windowStyleMask; - - ///The type of separator that the app displays between the title bar and content of a window. - /// - ///**Officially Supported Platforms/Implementations**: - ///- macOS WKWebView 11.0+ - WindowTitlebarSeparatorStyle? windowTitlebarSeparatorStyle; - - ///How the browser window should be added to the main window. - ///The default value is [WindowType.WINDOW]. - /// - ///**Officially Supported Platforms/Implementations**: - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - WindowType? windowType; - - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit ([Official API - GtkWindow](https://docs.gtk.org/gtk3/class.Window.html)) - InAppBrowserSettings({ - this.allowGoBackWithBackButton = true, - this.closeButtonCaption, - this.closeButtonColor, - this.closeOnCannotGoBack = true, - this.hidden = false, - this.hideCloseButton = false, - this.hideDefaultMenuItems = false, - this.hideProgressBar = false, - this.hideTitleBar = false, - this.hideToolbarBottom = false, - this.hideToolbarTop = false, - this.hideUrlBar = false, - this.menuButtonColor, - ModalPresentationStyle? presentationStyle, - this.shouldCloseOnBackButtonPressed = false, - this.toolbarBottomBackgroundColor, - this.toolbarBottomTintColor, - this.toolbarBottomTranslucent = true, - this.toolbarTopBackgroundColor, - this.toolbarTopFixedTitle, - this.toolbarTopTintColor, - this.toolbarTopTranslucent = true, - ModalTransitionStyle? transitionStyle, - this.windowAlphaValue = 1.0, - this.windowFrame, - this.windowStyleMask, - this.windowTitlebarSeparatorStyle, - this.windowType, - }) : presentationStyle = - presentationStyle ?? ModalPresentationStyle.FULL_SCREEN, - transitionStyle = transitionStyle ?? ModalTransitionStyle.COVER_VERTICAL; - - ///Gets a possible [InAppBrowserSettings] instance from a [Map] value. - static InAppBrowserSettings? fromMap( - Map? map, { - EnumMethod? enumMethod, - }) { - if (map == null) { - return null; - } - final instance = InAppBrowserSettings( - closeButtonCaption: map['closeButtonCaption'], - closeButtonColor: map['closeButtonColor'] != null - ? UtilColor.fromStringRepresentation(map['closeButtonColor']) - : null, - menuButtonColor: map['menuButtonColor'] != null - ? UtilColor.fromStringRepresentation(map['menuButtonColor']) - : null, - toolbarBottomBackgroundColor: map['toolbarBottomBackgroundColor'] != null - ? UtilColor.fromStringRepresentation( - map['toolbarBottomBackgroundColor'], - ) - : null, - toolbarBottomTintColor: map['toolbarBottomTintColor'] != null - ? UtilColor.fromStringRepresentation(map['toolbarBottomTintColor']) - : null, - toolbarTopBackgroundColor: map['toolbarTopBackgroundColor'] != null - ? UtilColor.fromStringRepresentation(map['toolbarTopBackgroundColor']) - : null, - toolbarTopFixedTitle: map['toolbarTopFixedTitle'], - toolbarTopTintColor: map['toolbarTopTintColor'] != null - ? UtilColor.fromStringRepresentation(map['toolbarTopTintColor']) - : null, - windowFrame: InAppWebViewRect.fromMap( - map['windowFrame']?.cast(), - enumMethod: enumMethod, - ), - windowStyleMask: switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => WindowStyleMask.fromNativeValue( - map['windowStyleMask'], - ), - EnumMethod.value => WindowStyleMask.fromValue(map['windowStyleMask']), - EnumMethod.name => WindowStyleMask.byName(map['windowStyleMask']), - }, - windowTitlebarSeparatorStyle: switch (enumMethod ?? - EnumMethod.nativeValue) { - EnumMethod.nativeValue => WindowTitlebarSeparatorStyle.fromNativeValue( - map['windowTitlebarSeparatorStyle'], - ), - EnumMethod.value => WindowTitlebarSeparatorStyle.fromValue( - map['windowTitlebarSeparatorStyle'], - ), - EnumMethod.name => WindowTitlebarSeparatorStyle.byName( - map['windowTitlebarSeparatorStyle'], - ), - }, - windowType: switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => WindowType.fromNativeValue(map['windowType']), - EnumMethod.value => WindowType.fromValue(map['windowType']), - EnumMethod.name => WindowType.byName(map['windowType']), - }, - ); - instance.allowGoBackWithBackButton = map['allowGoBackWithBackButton']; - instance.closeOnCannotGoBack = map['closeOnCannotGoBack']; - instance.hidden = map['hidden']; - instance.hideCloseButton = map['hideCloseButton']; - instance.hideDefaultMenuItems = map['hideDefaultMenuItems']; - instance.hideProgressBar = map['hideProgressBar']; - instance.hideTitleBar = map['hideTitleBar']; - instance.hideToolbarBottom = map['hideToolbarBottom']; - instance.hideToolbarTop = map['hideToolbarTop']; - instance.hideUrlBar = map['hideUrlBar']; - instance.presentationStyle = switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => ModalPresentationStyle.fromNativeValue( - map['presentationStyle'], - ), - EnumMethod.value => ModalPresentationStyle.fromValue( - map['presentationStyle'], - ), - EnumMethod.name => ModalPresentationStyle.byName( - map['presentationStyle'], - ), - }; - instance.shouldCloseOnBackButtonPressed = - map['shouldCloseOnBackButtonPressed']; - instance.toolbarBottomTranslucent = map['toolbarBottomTranslucent']; - instance.toolbarTopBarTintColor = map['toolbarTopBarTintColor'] != null - ? UtilColor.fromStringRepresentation(map['toolbarTopBarTintColor']) - : null; - instance.toolbarTopTranslucent = map['toolbarTopTranslucent']; - instance.transitionStyle = switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => ModalTransitionStyle.fromNativeValue( - map['transitionStyle'], - ), - EnumMethod.value => ModalTransitionStyle.fromValue( - map['transitionStyle'], - ), - EnumMethod.name => ModalTransitionStyle.byName(map['transitionStyle']), - }; - instance.windowAlphaValue = map['windowAlphaValue']; - return instance; - } - - ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. - static bool isPropertySupported( - InAppBrowserSettingsProperty property, { - TargetPlatform? platform, - }) => _InAppBrowserSettingsPropertySupported.isPropertySupported( - property, - platform: platform, - ); - - ///Converts instance to a map. - Map toMap({EnumMethod? enumMethod}) { - return { - "allowGoBackWithBackButton": allowGoBackWithBackButton, - "closeButtonCaption": closeButtonCaption, - "closeButtonColor": closeButtonColor?.toHex(), - "closeOnCannotGoBack": closeOnCannotGoBack, - "hidden": hidden, - "hideCloseButton": hideCloseButton, - "hideDefaultMenuItems": hideDefaultMenuItems, - "hideProgressBar": hideProgressBar, - "hideTitleBar": hideTitleBar, - "hideToolbarBottom": hideToolbarBottom, - "hideToolbarTop": hideToolbarTop, - "hideUrlBar": hideUrlBar, - "menuButtonColor": menuButtonColor?.toHex(), - "presentationStyle": switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => presentationStyle?.toNativeValue(), - EnumMethod.value => presentationStyle?.toValue(), - EnumMethod.name => presentationStyle?.name(), - }, - "shouldCloseOnBackButtonPressed": shouldCloseOnBackButtonPressed, - "toolbarBottomBackgroundColor": toolbarBottomBackgroundColor?.toHex(), - "toolbarBottomTintColor": toolbarBottomTintColor?.toHex(), - "toolbarBottomTranslucent": toolbarBottomTranslucent, - "toolbarTopBackgroundColor": toolbarTopBackgroundColor?.toHex(), - "toolbarTopBarTintColor": toolbarTopBarTintColor?.toHex(), - "toolbarTopFixedTitle": toolbarTopFixedTitle, - "toolbarTopTintColor": toolbarTopTintColor?.toHex(), - "toolbarTopTranslucent": toolbarTopTranslucent, - "transitionStyle": switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => transitionStyle?.toNativeValue(), - EnumMethod.value => transitionStyle?.toValue(), - EnumMethod.name => transitionStyle?.name(), - }, - "windowAlphaValue": windowAlphaValue, - "windowFrame": windowFrame?.toMap(enumMethod: enumMethod), - "windowStyleMask": switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => windowStyleMask?.toNativeValue(), - EnumMethod.value => windowStyleMask?.toValue(), - EnumMethod.name => windowStyleMask?.name(), - }, - "windowTitlebarSeparatorStyle": switch (enumMethod ?? - EnumMethod.nativeValue) { - EnumMethod.nativeValue => windowTitlebarSeparatorStyle?.toNativeValue(), - EnumMethod.value => windowTitlebarSeparatorStyle?.toValue(), - EnumMethod.name => windowTitlebarSeparatorStyle?.name(), - }, - "windowType": switch (enumMethod ?? EnumMethod.nativeValue) { - EnumMethod.nativeValue => windowType?.toNativeValue(), - EnumMethod.value => windowType?.toValue(), - EnumMethod.name => windowType?.name(), - }, - }; - } - - ///Converts instance to a map. - Map toJson() { - return toMap(); - } - - ///Returns a copy of InAppBrowserSettings. - InAppBrowserSettings copy() { - return InAppBrowserSettings.fromMap(toMap()) ?? InAppBrowserSettings(); - } - - @override - String toString() { - return 'InAppBrowserSettings{allowGoBackWithBackButton: $allowGoBackWithBackButton, closeButtonCaption: $closeButtonCaption, closeButtonColor: $closeButtonColor, closeOnCannotGoBack: $closeOnCannotGoBack, hidden: $hidden, hideCloseButton: $hideCloseButton, hideDefaultMenuItems: $hideDefaultMenuItems, hideProgressBar: $hideProgressBar, hideTitleBar: $hideTitleBar, hideToolbarBottom: $hideToolbarBottom, hideToolbarTop: $hideToolbarTop, hideUrlBar: $hideUrlBar, menuButtonColor: $menuButtonColor, presentationStyle: $presentationStyle, shouldCloseOnBackButtonPressed: $shouldCloseOnBackButtonPressed, toolbarBottomBackgroundColor: $toolbarBottomBackgroundColor, toolbarBottomTintColor: $toolbarBottomTintColor, toolbarBottomTranslucent: $toolbarBottomTranslucent, toolbarTopBackgroundColor: $toolbarTopBackgroundColor, toolbarTopBarTintColor: $toolbarTopBarTintColor, toolbarTopFixedTitle: $toolbarTopFixedTitle, toolbarTopTintColor: $toolbarTopTintColor, toolbarTopTranslucent: $toolbarTopTranslucent, transitionStyle: $transitionStyle, windowAlphaValue: $windowAlphaValue, windowFrame: $windowFrame, windowStyleMask: $windowStyleMask, windowTitlebarSeparatorStyle: $windowTitlebarSeparatorStyle, windowType: $windowType}'; - } -} - -// ************************************************************************** -// SupportedPlatformsGenerator -// ************************************************************************** - -///List of [InAppBrowserSettings]'s properties that can be used to check i they are supported or not by the current platform. -enum InAppBrowserSettingsProperty { - ///Can be used to check if the [InAppBrowserSettings.allowGoBackWithBackButton] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.allowGoBackWithBackButton.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - allowGoBackWithBackButton, - - ///Can be used to check if the [InAppBrowserSettings.closeButtonCaption] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.closeButtonCaption.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - closeButtonCaption, - - ///Can be used to check if the [InAppBrowserSettings.closeButtonColor] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.closeButtonColor.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - closeButtonColor, - - ///Can be used to check if the [InAppBrowserSettings.closeOnCannotGoBack] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.closeOnCannotGoBack.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - closeOnCannotGoBack, - - ///Can be used to check if the [InAppBrowserSettings.hidden] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.hidden.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - hidden, - - ///Can be used to check if the [InAppBrowserSettings.hideCloseButton] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.hideCloseButton.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - hideCloseButton, - - ///Can be used to check if the [InAppBrowserSettings.hideDefaultMenuItems] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.hideDefaultMenuItems.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Linux WPE WebKit - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - hideDefaultMenuItems, - - ///Can be used to check if the [InAppBrowserSettings.hideProgressBar] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.hideProgressBar.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Linux WPE WebKit - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - hideProgressBar, - - ///Can be used to check if the [InAppBrowserSettings.hideTitleBar] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.hideTitleBar.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - hideTitleBar, - - ///Can be used to check if the [InAppBrowserSettings.hideToolbarBottom] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.hideToolbarBottom.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - hideToolbarBottom, - - ///Can be used to check if the [InAppBrowserSettings.hideToolbarTop] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.hideToolbarTop.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Linux WPE WebKit - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - hideToolbarTop, - - ///Can be used to check if the [InAppBrowserSettings.hideUrlBar] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.hideUrlBar.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Linux WPE WebKit - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - hideUrlBar, - - ///Can be used to check if the [InAppBrowserSettings.menuButtonColor] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.menuButtonColor.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - menuButtonColor, - - ///Can be used to check if the [InAppBrowserSettings.presentationStyle] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.presentationStyle.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - presentationStyle, - - ///Can be used to check if the [InAppBrowserSettings.shouldCloseOnBackButtonPressed] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.shouldCloseOnBackButtonPressed.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - shouldCloseOnBackButtonPressed, - - ///Can be used to check if the [InAppBrowserSettings.toolbarBottomBackgroundColor] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.toolbarBottomBackgroundColor.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - toolbarBottomBackgroundColor, - - ///Can be used to check if the [InAppBrowserSettings.toolbarBottomTintColor] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.toolbarBottomTintColor.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - toolbarBottomTintColor, - - ///Can be used to check if the [InAppBrowserSettings.toolbarBottomTranslucent] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.toolbarBottomTranslucent.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - toolbarBottomTranslucent, - - ///Can be used to check if the [InAppBrowserSettings.toolbarTopBackgroundColor] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.toolbarTopBackgroundColor.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Linux WPE WebKit - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - toolbarTopBackgroundColor, - - ///Can be used to check if the [InAppBrowserSettings.toolbarTopBarTintColor] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.toolbarTopBarTintColor.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - toolbarTopBarTintColor, - - ///Can be used to check if the [InAppBrowserSettings.toolbarTopFixedTitle] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.toolbarTopFixedTitle.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - toolbarTopFixedTitle, - - ///Can be used to check if the [InAppBrowserSettings.toolbarTopTintColor] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.toolbarTopTintColor.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - toolbarTopTintColor, - - ///Can be used to check if the [InAppBrowserSettings.toolbarTopTranslucent] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.toolbarTopTranslucent.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - toolbarTopTranslucent, - - ///Can be used to check if the [InAppBrowserSettings.transitionStyle] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.transitionStyle.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - transitionStyle, - - ///Can be used to check if the [InAppBrowserSettings.windowAlphaValue] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.windowAlphaValue.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - windowAlphaValue, - - ///Can be used to check if the [InAppBrowserSettings.windowFrame] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.windowFrame.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - windowFrame, - - ///Can be used to check if the [InAppBrowserSettings.windowStyleMask] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.windowStyleMask.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- macOS WKWebView - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - windowStyleMask, - - ///Can be used to check if the [InAppBrowserSettings.windowTitlebarSeparatorStyle] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.windowTitlebarSeparatorStyle.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- macOS WKWebView 11.0+ - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - windowTitlebarSeparatorStyle, - - ///Can be used to check if the [InAppBrowserSettings.windowType] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.InAppBrowserSettings.windowType.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [InAppBrowserSettings.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - windowType, -} - -extension _InAppBrowserSettingsPropertySupported on InAppBrowserSettings { - static bool isPropertySupported( - InAppBrowserSettingsProperty property, { - TargetPlatform? platform, - }) { - switch (property) { - case InAppBrowserSettingsProperty.allowGoBackWithBackButton: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.closeButtonCaption: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.closeButtonColor: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.closeOnCannotGoBack: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.hidden: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.hideCloseButton: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.hideDefaultMenuItems: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.hideProgressBar: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.hideTitleBar: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.hideToolbarBottom: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.hideToolbarTop: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.hideUrlBar: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.menuButtonColor: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.presentationStyle: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.shouldCloseOnBackButtonPressed: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.toolbarBottomBackgroundColor: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.toolbarBottomTintColor: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.toolbarBottomTranslucent: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.toolbarTopBackgroundColor: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.toolbarTopBarTintColor: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.toolbarTopFixedTitle: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.toolbarTopTintColor: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.toolbarTopTranslucent: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.transitionStyle: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.windowAlphaValue: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.windowFrame: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.windowStyleMask: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.macOS].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.windowTitlebarSeparatorStyle: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.macOS].contains(platform ?? defaultTargetPlatform); - case InAppBrowserSettingsProperty.windowType: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - } - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/main.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_browser/main.dart deleted file mode 100644 index 6dba5c5052..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/main.dart +++ /dev/null @@ -1,5 +0,0 @@ -export 'platform_in_app_browser.dart'; -export 'in_app_browser_settings.dart' hide InAppBrowserSettings_; -export 'android/main.dart'; -export 'apple/main.dart'; -export 'in_app_browser_menu_item.dart' show InAppBrowserMenuItem; diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/platform_in_app_browser.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_browser/platform_in_app_browser.dart deleted file mode 100755 index 0b99565b72..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/platform_in_app_browser.dart +++ /dev/null @@ -1,2470 +0,0 @@ -import 'dart:async'; -import 'dart:collection'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; - -import '../context_menu/context_menu.dart'; -import '../debug_logging_settings.dart'; -import '../find_interaction/platform_find_interaction_controller.dart'; -import '../in_app_webview/in_app_webview_settings.dart'; -import '../in_app_webview/platform_inappwebview_controller.dart'; -import '../inappwebview_platform.dart'; -import '../platform_webview_feature.dart'; -import '../print_job/main.dart'; -import '../pull_to_refresh/main.dart'; -import '../pull_to_refresh/platform_pull_to_refresh_controller.dart'; -import '../types/main.dart'; -import '../web_uri.dart'; -import '../webview_environment/platform_webview_environment.dart'; -import 'in_app_browser_menu_item.dart'; -import 'in_app_browser_settings.dart'; - -part 'platform_in_app_browser.g.dart'; - -///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserCreationParams} -/// Object specifying creation parameters for creating a [PlatformInAppBrowser]. -/// -/// Platform specific implementations can add additional fields by extending -/// this class. -///{@endtemplate} -@immutable -class PlatformInAppBrowserCreationParams { - /// Used by the platform implementation to create a new [PlatformInAppBrowser]. - const PlatformInAppBrowserCreationParams({ - this.contextMenu, - this.pullToRefreshController, - this.findInteractionController, - this.initialUserScripts, - this.windowId, - this.webViewEnvironment, - }); - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.contextMenu} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.contextMenu.supported_platforms} - final ContextMenu? contextMenu; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.pullToRefreshController} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.pullToRefreshController.supported_platforms} - final PlatformPullToRefreshController? pullToRefreshController; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.findInteractionController} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.findInteractionController.supported_platforms} - final PlatformFindInteractionController? findInteractionController; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.initialUserScripts} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.initialUserScripts.supported_platforms} - final UnmodifiableListView? initialUserScripts; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.windowId} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.windowId.supported_platforms} - final int? windowId; - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserCreationParams.webViewEnvironment} - ///Used to create the [PlatformInAppBrowser] using the specified environment. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.webViewEnvironment.supported_platforms} - final PlatformWebViewEnvironment? webViewEnvironment; -} - -///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser} -///This class represents a native WebView displayed on top of the Flutter App, -///so it's not integrated into the Flutter widget tree. -///It uses the native WebView of the platform. -///The [webViewController] field can be used to access the [PlatformInAppWebViewController] API. -///{@endtemplate} -/// -///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.supported_platforms} -@SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform( - apiName: 'GtkWindow + WPE WebKit', - apiUrl: - 'https://wpewebkit.org/reference/stable/wpe-webkit-2.0/class.WebView.html', - ), - ], -) -abstract class PlatformInAppBrowser extends PlatformInterface - implements Disposable { - ///Debug settings. - static DebugLoggingSettings debugLoggingSettings = DebugLoggingSettings(); - - /// Event handler object that handles the [PlatformInAppBrowser] events. - PlatformInAppBrowserEvents? eventHandler; - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.id} - ///View ID used internally. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.id.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - String get id { - throw UnimplementedError('id is not implemented on the current platform'); - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.contextMenu} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.contextMenu.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform(), IOSPlatform()]) - ContextMenu? get contextMenu => params.contextMenu; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.pullToRefreshController} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.pullToRefreshController.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform(), IOSPlatform()]) - PlatformPullToRefreshController? get pullToRefreshController => - params.pullToRefreshController; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.findInteractionController} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.findInteractionController.supported_platforms} - @SupportedPlatforms( - platforms: [AndroidPlatform(), IOSPlatform(), MacOSPlatform()], - ) - PlatformFindInteractionController? get findInteractionController => - params.findInteractionController; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.initialUserScripts} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.initialUserScripts.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform( - note: - """This property will be ignored if the [PlatformWebViewCreationParams.windowId] has been set. -There isn't any way to add/remove user scripts specific to iOS window WebViews. -This is a limitation of the native WebKit APIs.""", - ), - MacOSPlatform( - note: - """This property will be ignored if the [PlatformWebViewCreationParams.windowId] has been set. -There isn't any way to add/remove user scripts specific to iOS window WebViews. -This is a limitation of the native WebKit APIs.""", - ), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - UnmodifiableListView? get initialUserScripts => - params.initialUserScripts; - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.windowId} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.windowId.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - int? get windowId => params.windowId; - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserCreationParams.webViewEnvironment} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.webViewEnvironment.supported_platforms} - @SupportedPlatforms(platforms: [WindowsPlatform()]) - PlatformWebViewEnvironment? get webViewEnvironment => - params.webViewEnvironment; - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.webViewController} - ///WebView Controller that can be used to access the [PlatformInAppWebViewController] API. - ///When [onExit] is fired, this will be `null` and cannot be used anymore. - ///{@endtemplate} - PlatformInAppWebViewController? get webViewController { - throw UnimplementedError( - 'webViewController is not implemented on the current platform', - ); - } - - /// Creates a new [PlatformInAppBrowser] - factory PlatformInAppBrowser(PlatformInAppBrowserCreationParams params) { - assert( - InAppWebViewPlatform.instance != null, - 'A platform implementation for `flutter_inappwebview` has not been set. Please ' - 'ensure that an implementation of `InAppWebViewPlatform` has been set to ' - '`InAppWebViewPlatform.instance` before use. For unit testing, ' - '`InAppWebViewPlatform.instance` can be set with your own test implementation.', - ); - final PlatformInAppBrowser inAppBrowser = InAppWebViewPlatform.instance! - .createPlatformInAppBrowser(params); - PlatformInterface.verify(inAppBrowser, _token); - return inAppBrowser; - } - - /// Creates a new [PlatformInAppBrowser] to access static methods. - factory PlatformInAppBrowser.static() { - assert( - InAppWebViewPlatform.instance != null, - 'A platform implementation for `flutter_inappwebview` has not been set. Please ' - 'ensure that an implementation of `InAppWebViewPlatform` has been set to ' - '`InAppWebViewPlatform.instance` before use. For unit testing, ' - '`InAppWebViewPlatform.instance` can be set with your own test implementation.', - ); - final PlatformInAppBrowser inAppBrowserStatic = InAppWebViewPlatform - .instance! - .createPlatformInAppBrowserStatic(); - PlatformInterface.verify(inAppBrowserStatic, _token); - return inAppBrowserStatic; - } - - /// Used by the platform implementation to create a new [PlatformInAppBrowser]. - /// - /// Should only be used by platform implementations because they can't extend - /// a class that only contains a factory constructor. - @protected - PlatformInAppBrowser.implementation(this.params) : super(token: _token); - - static final Object _token = Object(); - - /// The parameters used to initialize the [PlatformInAppBrowser]. - final PlatformInAppBrowserCreationParams params; - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.openUrlRequest} - ///Opens the [PlatformInAppBrowser] instance with an [urlRequest]. - /// - ///[urlRequest]: The [urlRequest] to load. - /// - ///[options]: Options for the [PlatformInAppBrowser]. - /// - ///[settings]: Settings for the [PlatformInAppBrowser]. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.openUrlRequest.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - Future openUrlRequest({ - required URLRequest urlRequest, - // ignore: deprecated_member_use_from_same_package - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) { - throw UnimplementedError( - 'openUrlRequest is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.openFile} - ///Opens the [PlatformInAppBrowser] instance with the given [assetFilePath] file. - /// - ///[options]: Options for the [PlatformInAppBrowser]. - /// - ///To be able to load your local files (assets, js, css, etc.), you need to add them in the `assets` section of the `pubspec.yaml` file, otherwise they cannot be found! - /// - ///Example of a `pubspec.yaml` file: - ///```yaml - ///... - /// - ///# The following section is specific to Flutter. - ///flutter: - /// - /// # The following line ensures that the Material Icons font is - /// # included with your application, so that you can use the icons in - /// # the material Icons class. - /// uses-material-design: true - /// - /// assets: - /// - assets/index.html - /// - assets/css/ - /// - assets/images/ - /// - ///... - ///``` - ///Example of a `main.dart` file: - ///```dart - ///... - ///inAppBrowser.openFile(assetFilePath: "assets/index.html"); - ///... - ///``` - /// - ///[headers]: The additional headers to be used in the HTTP request for this URL, specified as a map from name to value. - /// - ///[options]: Options for the [PlatformInAppBrowser]. - /// - ///[settings]: Settings for the [PlatformInAppBrowser]. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.openFile.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - Future openFile({ - required String assetFilePath, - // ignore: deprecated_member_use_from_same_package - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) { - throw UnimplementedError( - 'openFile is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.openData} - ///Opens the [PlatformInAppBrowser] instance with [data] as a content, using [baseUrl] as the base URL for it. - /// - ///The [mimeType] parameter specifies the format of the data. The default value is `"text/html"`. - /// - ///The [encoding] parameter specifies the encoding of the data. The default value is `"utf8"`. - /// - ///The [androidHistoryUrl] parameter is the URL to use as the history entry. The default value is `about:blank`. If non-null, this must be a valid URL. This parameter is used only on Android. - /// - ///The [options] parameter specifies the options for the [PlatformInAppBrowser]. - /// - ///[settings]: Settings for the [PlatformInAppBrowser]. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.openData.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - Future openData({ - required String data, - String mimeType = "text/html", - String encoding = "utf8", - WebUri? baseUrl, - @Deprecated("Use historyUrl instead") Uri? androidHistoryUrl, - WebUri? historyUrl, - // ignore: deprecated_member_use_from_same_package - @Deprecated('Use settings instead') InAppBrowserClassOptions? options, - InAppBrowserClassSettings? settings, - }) { - throw UnimplementedError( - 'openData is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.openWithSystemBrowser} - ///This is a static method that opens an [url] in the system browser. - ///You wont be able to use the [PlatformInAppBrowser] events and methods here. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.openWithSystemBrowser.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - Future openWithSystemBrowser({required WebUri url}) { - throw UnimplementedError( - 'openWithSystemBrowser is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.addMenuItem} - ///Adds a [InAppBrowserMenuItem] to the menu. - ///If the browser is already open, - ///it will take effect the next time it is opened. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.addMenuItem.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(available: '14.0'), - MacOSPlatform(available: '10.15'), - ], - ) - void addMenuItem(InAppBrowserMenuItem menuItem) { - throw UnimplementedError( - 'addMenuItem is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.addMenuItems} - ///Adds a list of [InAppBrowserMenuItem] to the menu. - ///If the browser is already open, - ///it will take effect the next time it is opened. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.addMenuItems.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(available: '14.0'), - MacOSPlatform(available: '10.15'), - ], - ) - void addMenuItems(List menuItems) { - throw UnimplementedError( - 'addMenuItems is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.removeMenuItem} - ///Removes the [menuItem] from the list. - ///Returns `true` if it was in the list, `false` otherwise. - ///If the browser is already open, - ///it will take effect the next time it is opened. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.removeMenuItem.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(available: '14.0'), - MacOSPlatform(available: '10.15'), - ], - ) - bool removeMenuItem(InAppBrowserMenuItem menuItem) { - throw UnimplementedError( - 'removeMenuItem is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.removeMenuItems} - ///Removes a list of [menuItems] from the list. - ///If the browser is already open, - ///it will take effect the next time it is opened. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.removeMenuItems.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(available: '14.0'), - MacOSPlatform(available: '10.15'), - ], - ) - void removeMenuItems(List menuItems) { - throw UnimplementedError( - 'removeMenuItems is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.removeAllMenuItem} - ///Removes all the menu items from the list. - ///If the browser is already open, - ///it will take effect the next time it is opened. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.removeAllMenuItem.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(available: '14.0'), - MacOSPlatform(available: '10.15'), - ], - ) - void removeAllMenuItem() { - throw UnimplementedError( - 'removeAllMenuItem is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.hasMenuItem} - ///Returns `true` if the [menuItem] has been already added, otherwise `false`. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.hasMenuItem.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(available: '14.0'), - MacOSPlatform(available: '10.15'), - ], - ) - bool hasMenuItem(InAppBrowserMenuItem menuItem) { - throw UnimplementedError( - 'hasMenuItem is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.show} - ///Displays a [PlatformInAppBrowser] window that was opened hidden. Calling this has no effect if the [PlatformInAppBrowser] was already visible. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.show.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - Future show() { - throw UnimplementedError('show is not implemented on the current platform'); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.hide} - ///Hides the [PlatformInAppBrowser] window. Calling this has no effect if the [PlatformInAppBrowser] was already hidden. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.hide.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - Future hide() { - throw UnimplementedError('hide is not implemented on the current platform'); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.close} - ///Closes the [PlatformInAppBrowser] window. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.close.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - Future close() { - throw UnimplementedError( - 'close is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.isHidden} - ///Check if the Web View of the [PlatformInAppBrowser] instance is hidden. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.isHidden.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - Future isHidden() { - throw UnimplementedError( - 'isHidden is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.setOptions} - ///Use [setSettings] instead. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.setOptions.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform(), IOSPlatform()]) - @Deprecated('Use setSettings instead') - Future setOptions({required InAppBrowserClassOptions options}) { - throw UnimplementedError( - 'setOptions is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.getOptions} - ///Use [getSettings] instead. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.getOptions.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform(), IOSPlatform()]) - @Deprecated('Use getSettings instead') - Future getOptions() { - throw UnimplementedError( - 'getOptions is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.setSettings} - ///Sets the [PlatformInAppBrowser] settings with the new [settings] and evaluates them. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.setSettings.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - Future setSettings({required InAppBrowserClassSettings settings}) { - throw UnimplementedError( - 'setSettings is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.getSettings} - ///Gets the current [PlatformInAppBrowser] settings. Returns `null` if it wasn't able to get them. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.getSettings.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - Future getSettings() { - throw UnimplementedError( - 'getSettings is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.isOpened} - ///Returns `true` if the [PlatformInAppBrowser] instance is opened, otherwise `false`. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.isOpened.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - bool isOpened() { - throw UnimplementedError( - 'isOpened is not implemented on the current platform', - ); - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.dispose} - ///Disposes the channel and controllers. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.dispose.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - @override - @mustCallSuper - void dispose() { - eventHandler = null; - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.isClassSupported} - ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. - ///{@endtemplate} - bool isClassSupported({TargetPlatform? platform}) => - _PlatformInAppBrowserClassSupported.isClassSupported(platform: platform); - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.isPropertySupported} - ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. - ///{@endtemplate} - bool isPropertySupported( - PlatformInAppBrowserProperty property, { - TargetPlatform? platform, - }) => _PlatformInAppBrowserPropertySupported.isPropertySupported( - property, - platform: platform, - ); - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.isMethodSupported} - ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. - ///{@endtemplate} - bool isMethodSupported( - PlatformInAppBrowserMethod method, { - TargetPlatform? platform, - }) => _PlatformInAppBrowserMethodSupported.isMethodSupported( - method, - platform: platform, - ); - - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.isMethodSupported} - bool isEventMethodSupported( - PlatformInAppBrowserEventsMethod method, { - TargetPlatform? platform, - }) => - PlatformInAppBrowserEvents.isMethodSupported(method, platform: platform); -} - -@SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], -) -abstract class PlatformInAppBrowserEvents { - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onBrowserCreated} - ///Event fired when the [PlatformInAppBrowser] is created. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onBrowserCreated.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - void onBrowserCreated() {} - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onExit} - ///Event fired when the [PlatformInAppBrowser] window is closed. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onExit.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - LinuxPlatform(), - ], - ) - void onExit() {} - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onMainWindowWillClose} - ///Event fired when the main window is about to close. - ///{@endtemplate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onMainWindowWillClose.supported_platforms} - @SupportedPlatforms(platforms: [MacOSPlatform()]) - void onMainWindowWillClose() {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onLoadStart} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLoadStart.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.onPageStarted', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap)', - ), - IOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455621-webview', - ), - MacOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455621-webview', - ), - WindowsPlatform( - apiName: 'ICoreWebView2.add_NavigationStarting', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/iwebview2webview?view=webview2-0.8.355#add_navigationstarting', - ), - ], - ) - void onLoadStart(WebUri? url) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onLoadStop} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLoadStop.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.onPageFinished', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#onPageFinished(android.webkit.WebView,%20java.lang.String)', - ), - IOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455629-webview', - ), - MacOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455629-webview', - ), - WindowsPlatform( - apiName: 'ICoreWebView2.add_NavigationCompleted', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/iwebview2webview?view=webview2-0.8.355#add_navigationcompleted', - ), - ], - ) - void onLoadStop(WebUri? url) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onLoadError} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLoadError.supported_platforms} - @SupportedPlatforms( - platforms: [AndroidPlatform(), IOSPlatform(), MacOSPlatform()], - ) - @Deprecated("Use onReceivedError instead") - void onLoadError(Uri? url, int code, String message) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onReceivedError} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onReceivedError.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.onReceivedError', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedError(android.webkit.WebView,%20android.webkit.WebResourceRequest,%20android.webkit.WebResourceError)', - ), - IOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455623-webview', - ), - MacOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455623-webview', - ), - WindowsPlatform( - apiName: 'ICoreWebView2.add_NavigationCompleted', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/iwebview2webview?view=webview2-0.8.355#add_navigationcompleted', - ), - ], - ) - void onReceivedError(WebResourceRequest request, WebResourceError error) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onLoadHttpError} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLoadHttpError.supported_platforms} - @SupportedPlatforms( - platforms: [AndroidPlatform(), IOSPlatform(), MacOSPlatform()], - ) - @Deprecated("Use onReceivedHttpError instead") - void onLoadHttpError(Uri? url, int statusCode, String description) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onReceivedHttpError} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onReceivedHttpError.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.onReceivedHttpError', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedHttpError(android.webkit.WebView,%20android.webkit.WebResourceRequest,%20android.webkit.WebResourceResponse)', - available: '23', - ), - IOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview', - ), - MacOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview', - ), - WindowsPlatform( - apiName: 'ICoreWebView2.add_NavigationCompleted', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/iwebview2webview?view=webview2-0.8.355#add_navigationcompleted', - ), - ], - ) - void onReceivedHttpError( - WebResourceRequest request, - WebResourceResponse errorResponse, - ) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onProgressChanged} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onProgressChanged.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onProgressChanged', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onProgressChanged(android.webkit.WebView,%20int)', - ), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform(), - ], - ) - void onProgressChanged(int progress) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onConsoleMessage} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onConsoleMessage.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onConsoleMessage', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onConsoleMessage(android.webkit.ConsoleMessage)', - ), - IOSPlatform(note: 'This event is implemented using JavaScript.'), - MacOSPlatform(note: 'This event is implemented using JavaScript.'), - WebPlatform(), - WindowsPlatform(), - ], - ) - void onConsoleMessage(ConsoleMessage consoleMessage) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.shouldOverrideUrlLoading} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.shouldOverrideUrlLoading.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.shouldOverrideUrlLoading', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#shouldOverrideUrlLoading(android.webkit.WebView,%20java.lang.String)', - note: - """There isn't any way to load an URL for a frame that is not the main frame, so if the request is not for the main frame, the navigation is allowed by default. -However, if you want to cancel requests for subframes, you can use the [InAppWebViewSettings.regexToCancelSubFramesLoading] setting -to write a Regular Expression that, if the url request of a subframe matches, then the request of that subframe is canceled. -Instead, the [InAppWebViewSettings.regexToAllowSyncUrlLoading] setting could -be used to allow navigation requests synchronously, as this event is synchronous on native side -and the current plugin implementation will always cancel the current request and load a new request if -this event returns [NavigationActionPolicy.ALLOW] because Flutter method channels work only asynchronously. -Also, this event is not called for POST requests and is not called on the first page load.""", - ), - IOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455641-webview', - ), - MacOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455641-webview', - ), - WindowsPlatform(), - ], - ) - FutureOr? shouldOverrideUrlLoading( - NavigationAction navigationAction, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onLaunchingExternalUriScheme} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLaunchingExternalUriScheme.supported_platforms} - @SupportedPlatforms( - platforms: [ - WindowsPlatform( - apiName: 'ICoreWebView2_18.add_LaunchingExternalUriScheme', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_18?view=webview2-1.0.2849.39#add_launchingexternalurischeme', - ), - ], - ) - FutureOr? onLaunchingExternalUriScheme( - LaunchingExternalUriSchemeRequest request, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onLoadResource} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLoadResource.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(note: 'This event is implemented using JavaScript.'), - IOSPlatform(note: 'This event is implemented using JavaScript.'), - MacOSPlatform(note: 'This event is implemented using JavaScript.'), - ], - ) - void onLoadResource(LoadedResource resource) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onScrollChanged} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onScrollChanged.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebView.onScrollChanged', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebView#onScrollChanged(int,%20int,%20int,%20int)', - ), - IOSPlatform( - apiName: 'UIScrollViewDelegate.scrollViewDidScroll', - apiUrl: - 'https://developer.apple.com/documentation/uikit/uiscrollviewdelegate/1619392-scrollviewdidscroll', - ), - MacOSPlatform(note: 'This event is implemented using JavaScript.'), - ], - ) - void onScrollChanged(int x, int y) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onDownloadStart} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onDownloadStart.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform(), IOSPlatform()]) - @Deprecated('Use onDownloadStarting instead') - void onDownloadStart(Uri url) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onDownloadStartRequest} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onDownloadStartRequest.supported_platforms} - @SupportedPlatforms( - platforms: [AndroidPlatform(), IOSPlatform(), MacOSPlatform()], - ) - @Deprecated('Use onDownloadStarting instead') - void onDownloadStartRequest(DownloadStartRequest downloadStartRequest) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onDownloadStarting} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onDownloadStarting.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebView.setDownloadListener', - apiUrl: - '(https://developer.android.com/reference/android/webkit/WebView#setDownloadListener(android.webkit.DownloadListener)', - ), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform( - apiName: 'ICoreWebView2_4.add_DownloadStarting', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_4?view=webview2-1.0.2849.39#add_downloadstarting', - ), - ], - ) - FutureOr? onDownloadStarting( - DownloadStartRequest downloadStartRequest, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onLoadResourceCustomScheme} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLoadResourceCustomScheme.supported_platforms} - @SupportedPlatforms( - platforms: [AndroidPlatform(), IOSPlatform(), MacOSPlatform()], - ) - @Deprecated('Use onLoadResourceWithCustomScheme instead') - FutureOr? onLoadResourceCustomScheme(Uri url) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onLoadResourceWithCustomScheme} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLoadResourceWithCustomScheme.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform(), - IOSPlatform( - apiName: 'WKURLSchemeHandler', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wkurlschemehandler', - ), - MacOSPlatform( - apiName: 'WKURLSchemeHandler', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wkurlschemehandler', - ), - WindowsPlatform(), - ], - ) - FutureOr? onLoadResourceWithCustomScheme( - WebResourceRequest request, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onCreateWindow} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onCreateWindow.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onCreateWindow', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onCreateWindow(android.webkit.WebView,%20boolean,%20boolean,%20android.os.Message)', - note: - 'You need to set [InAppWebViewSettings.supportMultipleWindows] setting to `true`. Also, if the request has been created using JavaScript (`window.open()`), then there are some limitation: check the [NavigationAction] class.', - ), - IOSPlatform( - apiName: 'WKUIDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wkuidelegate/1536907-webview', - note: - """Setting these initial settings [InAppWebViewSettings.supportZoom], [InAppWebViewSettings.useOnLoadResource], [InAppWebViewSettings.useShouldInterceptAjaxRequest], -[InAppWebViewSettings.useShouldInterceptFetchRequest], [InAppWebViewSettings.applicationNameForUserAgent], [InAppWebViewSettings.javaScriptCanOpenWindowsAutomatically], -[InAppWebViewSettings.javaScriptEnabled], [InAppWebViewSettings.minimumFontSize], [InAppWebViewSettings.preferredContentMode], [InAppWebViewSettings.incognito], -[InAppWebViewSettings.cacheEnabled], [InAppWebViewSettings.mediaPlaybackRequiresUserGesture], -[InAppWebViewSettings.resourceCustomSchemes], [InAppWebViewSettings.sharedCookiesEnabled], -[InAppWebViewSettings.enableViewportScale], [InAppWebViewSettings.allowsAirPlayForMediaPlayback], -[InAppWebViewSettings.allowsPictureInPictureMediaPlayback], [InAppWebViewSettings.isFraudulentWebsiteWarningEnabled], -[InAppWebViewSettings.allowsInlineMediaPlayback], [InAppWebViewSettings.suppressesIncrementalRendering], [InAppWebViewSettings.selectionGranularity], -[InAppWebViewSettings.ignoresViewportScaleLimits], [InAppWebViewSettings.limitsNavigationsToAppBoundDomains], -[InAppWebViewSettings.upgradeKnownHostsToHTTPS], -will have no effect due to a `WKWebView` limitation when creating the new window WebView: it's impossible to return the new `WKWebView` -with a different `WKWebViewConfiguration` instance (see https://developer.apple.com/documentation/webkit/wkuidelegate/1536907-webview). -So, these options will be inherited from the caller WebView. -Also, note that calling [InAppWebViewController.setSettings] method using the controller of the new created WebView, -it will update also the WebView options of the caller WebView.""", - ), - MacOSPlatform( - apiName: 'WKUIDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wkuidelegate/1536907-webview', - note: - """Setting these initial settings [InAppWebViewSettings.supportZoom], [InAppWebViewSettings.useOnLoadResource], [InAppWebViewSettings.useShouldInterceptAjaxRequest], -[InAppWebViewSettings.useShouldInterceptFetchRequest], [InAppWebViewSettings.applicationNameForUserAgent], [InAppWebViewSettings.javaScriptCanOpenWindowsAutomatically], -[InAppWebViewSettings.javaScriptEnabled], [InAppWebViewSettings.minimumFontSize], [InAppWebViewSettings.preferredContentMode], [InAppWebViewSettings.incognito], -[InAppWebViewSettings.cacheEnabled], [InAppWebViewSettings.mediaPlaybackRequiresUserGesture], -[InAppWebViewSettings.resourceCustomSchemes], [InAppWebViewSettings.sharedCookiesEnabled], -[InAppWebViewSettings.enableViewportScale], [InAppWebViewSettings.allowsAirPlayForMediaPlayback], -[InAppWebViewSettings.allowsPictureInPictureMediaPlayback], [InAppWebViewSettings.isFraudulentWebsiteWarningEnabled], -[InAppWebViewSettings.allowsInlineMediaPlayback], [InAppWebViewSettings.suppressesIncrementalRendering], [InAppWebViewSettings.selectionGranularity], -[InAppWebViewSettings.ignoresViewportScaleLimits], [InAppWebViewSettings.limitsNavigationsToAppBoundDomains], -[InAppWebViewSettings.upgradeKnownHostsToHTTPS], -will have no effect due to a `WKWebView` limitation when creating the new window WebView: it's impossible to return the new `WKWebView` -with a different `WKWebViewConfiguration` instance (see https://developer.apple.com/documentation/webkit/wkuidelegate/1536907-webview). -So, these options will be inherited from the caller WebView. -Also, note that calling [InAppWebViewController.setSettings] method using the controller of the new created WebView, -it will update also the WebView options of the caller WebView.""", - ), - WindowsPlatform( - apiName: 'ICoreWebView2.add_NewWindowRequested', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_newwindowrequested', - ), - ], - ) - FutureOr? onCreateWindow(CreateWindowAction createWindowAction) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onCloseWindow} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onCloseWindow.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onCloseWindow', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onCloseWindow(android.webkit.WebView)', - ), - IOSPlatform( - apiName: 'WKUIDelegate.webViewDidClose', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wkuidelegate/1537390-webviewdidclose', - ), - MacOSPlatform( - apiName: 'WKUIDelegate.webViewDidClose', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wkuidelegate/1537390-webviewdidclose', - ), - WebPlatform(), - WindowsPlatform( - apiName: 'ICoreWebView2.add_WindowCloseRequested', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_windowcloserequested', - ), - ], - ) - void onCloseWindow() {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onWindowFocus} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onWindowFocus.supported_platforms} - @SupportedPlatforms( - platforms: [AndroidPlatform(), IOSPlatform(), MacOSPlatform()], - ) - void onWindowFocus() {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onWindowBlur} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onWindowBlur.supported_platforms} - @SupportedPlatforms( - platforms: [AndroidPlatform(), IOSPlatform(), MacOSPlatform()], - ) - void onWindowBlur() {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onJsAlert} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onJsAlert.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onJsAlert', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onJsAlert(android.webkit.WebView,%20java.lang.String,%20java.lang.String,%20android.webkit.JsResult)', - ), - IOSPlatform( - apiName: 'WKUIDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wkuidelegate/1537406-webview', - ), - MacOSPlatform( - apiName: 'WKUIDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wkuidelegate/1537406-webview', - ), - ], - ) - FutureOr? onJsAlert(JsAlertRequest jsAlertRequest) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onJsConfirm} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onJsConfirm.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onJsConfirm', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onJsConfirm(android.webkit.WebView,%20java.lang.String,%20java.lang.String,%20android.webkit.JsResult)', - ), - IOSPlatform( - apiName: 'WKUIDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wkuidelegate/1536489-webview', - ), - MacOSPlatform( - apiName: 'WKUIDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wkuidelegate/1536489-webview', - ), - ], - ) - FutureOr? onJsConfirm(JsConfirmRequest jsConfirmRequest) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onJsPrompt} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onJsPrompt.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onJsPrompt', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onJsPrompt(android.webkit.WebView,%20java.lang.String,%20java.lang.String,%20java.lang.String,%20android.webkit.JsPromptResult)', - ), - IOSPlatform( - apiName: 'WKUIDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wkuidelegate/1538086-webview', - ), - MacOSPlatform( - apiName: 'WKUIDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wkuidelegate/1538086-webview', - ), - ], - ) - FutureOr? onJsPrompt(JsPromptRequest jsPromptRequest) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onReceivedHttpAuthRequest} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onReceivedHttpAuthRequest.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.onReceivedHttpAuthRequest', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedHttpAuthRequest(android.webkit.WebView,%20android.webkit.HttpAuthHandler,%20java.lang.String,%20java.lang.String)', - ), - IOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview', - ), - MacOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview', - ), - WindowsPlatform( - apiName: 'ICoreWebView2_10.add_BasicAuthenticationRequested', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_10?view=webview2-1.0.2849.39#add_basicauthenticationrequested', - ), - ], - ) - FutureOr? onReceivedHttpAuthRequest( - HttpAuthenticationChallenge challenge, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onReceivedServerTrustAuthRequest} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onReceivedServerTrustAuthRequest.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.onReceivedSslError', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedSslError(android.webkit.WebView,%20android.webkit.SslErrorHandler,%20android.net.http.SslError)', - ), - IOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview', - note: - """To override the certificate verification logic, you have to provide ATS (App Transport Security) exceptions in your iOS/macOS `Info.plist`. -See `NSAppTransportSecurity` in the [Information Property List Key Reference](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW1) for details.""", - ), - MacOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview', - note: - """To override the certificate verification logic, you have to provide ATS (App Transport Security) exceptions in your iOS/macOS `Info.plist`. -See `NSAppTransportSecurity` in the [Information Property List Key Reference](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW1) for details.""", - ), - WindowsPlatform( - apiName: 'ICoreWebView2_14.add_ServerCertificateErrorDetected', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_14?view=webview2-1.0.2792.45#add_servercertificateerrordetected', - ), - ], - ) - FutureOr? onReceivedServerTrustAuthRequest( - ServerTrustChallenge challenge, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onReceivedClientCertRequest} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onReceivedClientCertRequest.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.onReceivedClientCertRequest', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedClientCertRequest(android.webkit.WebView,%20android.webkit.ClientCertRequest)', - ), - IOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview', - ), - MacOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview', - ), - WindowsPlatform( - apiName: 'ICoreWebView2_5.add_ClientCertificateRequested', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_5?view=webview2-1.0.2849.39#add_clientcertificaterequested', - ), - ], - ) - FutureOr? onReceivedClientCertRequest( - ClientCertChallenge challenge, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onFindResultReceived} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onFindResultReceived.supported_platforms} - @SupportedPlatforms( - platforms: [AndroidPlatform(), IOSPlatform(), MacOSPlatform()], - ) - @Deprecated('Use FindInteractionController.onFindResultReceived instead') - void onFindResultReceived( - int activeMatchOrdinal, - int numberOfMatches, - bool isDoneCounting, - ) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.shouldInterceptAjaxRequest} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.shouldInterceptAjaxRequest.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - note: - """In order to be able to listen this event, check the [InAppWebViewSettings.useShouldInterceptAjaxRequest] setting documentation. -Also, on Android that doesn't support the [WebViewFeature.DOCUMENT_START_SCRIPT], unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that -can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code -used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS. -In that case, after the `window.addEventListener("flutterInAppWebViewPlatformReady")` event is dispatched, the ajax requests can be intercept for sure.""", - ), - IOSPlatform(), - MacOSPlatform(), - ], - ) - FutureOr? shouldInterceptAjaxRequest(AjaxRequest ajaxRequest) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onAjaxReadyStateChange} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onAjaxReadyStateChange.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - note: - """In order to be able to listen this event, check the [InAppWebViewSettings.useShouldInterceptAjaxRequest] and [InAppWebViewSettings.useOnAjaxReadyStateChange] settings documentation. -Also, on Android that doesn't support the [WebViewFeature.DOCUMENT_START_SCRIPT], unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that -can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code -used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS. -In that case, after the `window.addEventListener("flutterInAppWebViewPlatformReady")` event is dispatched, the ajax requests can be intercept for sure.""", - ), - IOSPlatform(), - MacOSPlatform(), - ], - ) - FutureOr? onAjaxReadyStateChange( - AjaxRequest ajaxRequest, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onAjaxProgress} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onAjaxProgress.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - note: - """In order to be able to listen this event, check the [InAppWebViewSettings.useShouldInterceptAjaxRequest] and [InAppWebViewSettings.useOnAjaxProgress] settings documentation. -Also, on Android that doesn't support the [WebViewFeature.DOCUMENT_START_SCRIPT], unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that -can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code -used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS. -In that case, after the `window.addEventListener("flutterInAppWebViewPlatformReady")` event is dispatched, the ajax requests can be intercept for sure.""", - ), - IOSPlatform(), - MacOSPlatform(), - ], - ) - FutureOr? onAjaxProgress(AjaxRequest ajaxRequest) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.shouldInterceptFetchRequest} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.shouldInterceptFetchRequest.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - note: - """In order to be able to listen this event, check the [InAppWebViewSettings.useShouldInterceptFetchRequest] setting documentation. -Also, on Android that doesn't support the [WebViewFeature.DOCUMENT_START_SCRIPT], unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that -can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code -used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS. -In that case, after the `window.addEventListener("flutterInAppWebViewPlatformReady")` event is dispatched, the ajax requests can be intercept for sure.""", - ), - IOSPlatform(), - MacOSPlatform(), - ], - ) - FutureOr? shouldInterceptFetchRequest( - FetchRequest fetchRequest, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onUpdateVisitedHistory} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onUpdateVisitedHistory.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.doUpdateVisitedHistory', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#doUpdateVisitedHistory(android.webkit.WebView,%20java.lang.String,%20boolean)', - ), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform( - apiName: 'ICoreWebView2.add_HistoryChanged', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_historychanged', - ), - ], - ) - void onUpdateVisitedHistory( - WebUri? url, - @SupportedPlatforms(platforms: [AndroidPlatform()]) bool? isReload, - ) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onPrint} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onPrint.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform(), IOSPlatform()]) - @Deprecated("Use onPrintRequest instead") - void onPrint(Uri? url) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onPrintRequest} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onPrintRequest.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'View.scrollBy', - apiUrl: - 'https://developer.android.com/reference/android/view/View#scrollBy(int,%20int)', - ), - IOSPlatform( - apiName: 'UIScrollView.setContentOffset', - apiUrl: - 'https://developer.apple.com/documentation/uikit/uiscrollview/1619400-setcontentoffset', - ), - MacOSPlatform(note: 'This method is implemented using JavaScript.'), - ], - ) - FutureOr? onPrintRequest( - WebUri? url, - PlatformPrintJobController? printJobController, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onLongPressHitTestResult} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLongPressHitTestResult.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'View.setOnLongClickListener', - apiUrl: - 'https://developer.android.com/reference/android/view/View#setOnLongClickListener(android.view.View.OnLongClickListener)', - ), - IOSPlatform( - apiName: 'UILongPressGestureRecognizer', - apiUrl: - 'https://developer.apple.com/documentation/uikit/uilongpressgesturerecognizer', - ), - ], - ) - void onLongPressHitTestResult(InAppWebViewHitTestResult hitTestResult) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onEnterFullscreen} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onEnterFullscreen.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onShowCustomView', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onShowCustomView(android.view.View,%20android.webkit.WebChromeClient.CustomViewCallback)', - ), - IOSPlatform( - apiName: 'UIWindow.didBecomeVisibleNotification', - apiUrl: - 'https://developer.apple.com/documentation/uikit/uiwindow/1621621-didbecomevisiblenotification', - ), - MacOSPlatform( - apiName: 'NSWindow.didEnterFullScreenNotification', - apiUrl: - 'https://developer.apple.com/documentation/appkit/nswindow/1419651-didenterfullscreennotification', - ), - WindowsPlatform( - apiName: 'ICoreWebView2.add_ContainsFullScreenElementChanged', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_containsfullscreenelementchanged', - ), - ], - ) - void onEnterFullscreen() {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onExitFullscreen} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onExitFullscreen.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onHideCustomView', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onHideCustomView()', - ), - IOSPlatform( - apiName: 'UIWindow.didBecomeHiddenNotification', - apiUrl: - 'https://developer.apple.com/documentation/uikit/uiwindow/1621617-didbecomehiddennotification', - ), - MacOSPlatform( - apiName: 'NSWindow.didExitFullScreenNotification', - apiUrl: - 'https://developer.apple.com/documentation/appkit/nswindow/1419177-didexitfullscreennotification', - ), - WindowsPlatform( - apiName: 'ICoreWebView2.add_ContainsFullScreenElementChanged', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_containsfullscreenelementchanged', - ), - ], - ) - void onExitFullscreen() {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onContentLoading} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onContentLoading.supported_platforms} - @SupportedPlatforms( - platforms: [ - WindowsPlatform( - apiName: 'ICoreWebView2.add_ContentLoading', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_contentloading', - ), - ], - ) - void onContentLoading(WebUri? url) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onDOMContentLoaded} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onDOMContentLoaded.supported_platforms} - @SupportedPlatforms( - platforms: [ - WindowsPlatform( - apiName: 'ICoreWebView2_2.add_DOMContentLoaded', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_2?view=webview2-1.0.2210.55#add_domcontentloaded', - ), - ], - ) - void onDOMContentLoaded(WebUri? url) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onPageCommitVisible} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onPageCommitVisible.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.onPageCommitVisible', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#onPageCommitVisible(android.webkit.WebView,%20java.lang.String)', - ), - IOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455635-webview', - ), - MacOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455635-webview', - ), - ], - ) - void onPageCommitVisible(WebUri? url) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onTitleChanged} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onTitleChanged.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onReceivedTitle', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onReceivedTitle(android.webkit.WebView,%20java.lang.String)', - ), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform( - apiName: 'ICoreWebView2.add_DocumentTitleChanged', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_documenttitlechanged', - ), - ], - ) - void onTitleChanged(String? title) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onOverScrolled} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onOverScrolled.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebView.onOverScrolled', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebView#onOverScrolled(int,%20int,%20boolean,%20boolean)', - ), - IOSPlatform(), - ], - ) - void onOverScrolled(int x, int y, bool clampedX, bool clampedY) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onZoomScaleChanged} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onZoomScaleChanged.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.onScaleChanged', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#onScaleChanged(android.webkit.WebView,%20float,%20float)', - ), - IOSPlatform( - apiName: 'UIScrollViewDelegate.scrollViewDidZoom', - apiUrl: - 'https://developer.apple.com/documentation/uikit/uiscrollviewdelegate/1619409-scrollviewdidzoom', - ), - WindowsPlatform( - apiName: 'ICoreWebView2Controller.add_ZoomFactorChanged', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2controller?view=webview2-1.0.2849.39#add_zoomfactorchanged', - ), - ], - ) - void onZoomScaleChanged(double oldScale, double newScale) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.androidOnSafeBrowsingHit} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnSafeBrowsingHit.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - @Deprecated("Use onSafeBrowsingHit instead") - FutureOr? androidOnSafeBrowsingHit( - Uri url, - SafeBrowsingThreat? threatType, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onSafeBrowsingHit} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onSafeBrowsingHit.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.onSafeBrowsingHit', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#onSafeBrowsingHit(android.webkit.WebView,%20android.webkit.WebResourceRequest,%20int,%20android.webkit.SafeBrowsingResponse)', - available: '27', - ), - ], - ) - FutureOr? onSafeBrowsingHit( - WebUri url, - SafeBrowsingThreat? threatType, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.androidOnPermissionRequest} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnPermissionRequest.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - @Deprecated("Use onPermissionRequest instead") - FutureOr? androidOnPermissionRequest( - String origin, - List resources, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onPermissionRequest} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onPermissionRequest.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onPermissionRequest', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onPermissionRequest(android.webkit.PermissionRequest)', - available: '21', - ), - IOSPlatform( - available: '15.0', - note: - 'The default [PermissionResponse.action] is [PermissionResponseAction.PROMPT].', - ), - MacOSPlatform( - available: '12.0', - note: - 'The default [PermissionResponse.action] is [PermissionResponseAction.PROMPT].', - ), - WindowsPlatform( - apiName: 'ICoreWebView2.add_PermissionRequested', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_permissionrequested', - ), - ], - ) - FutureOr? onPermissionRequest( - PermissionRequest permissionRequest, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.androidOnGeolocationPermissionsShowPrompt} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnGeolocationPermissionsShowPrompt.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - @Deprecated("Use onGeolocationPermissionsShowPrompt instead") - FutureOr? - androidOnGeolocationPermissionsShowPrompt(String origin) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onGeolocationPermissionsShowPrompt} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onGeolocationPermissionsShowPrompt.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onGeolocationPermissionsShowPrompt', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onGeolocationPermissionsShowPrompt(java.lang.String,%20android.webkit.GeolocationPermissions.Callback)', - ), - ], - ) - FutureOr? - onGeolocationPermissionsShowPrompt(String origin) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.androidOnGeolocationPermissionsHidePrompt} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnGeolocationPermissionsHidePrompt.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - @Deprecated("Use onGeolocationPermissionsHidePrompt instead") - void androidOnGeolocationPermissionsHidePrompt() {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onGeolocationPermissionsHidePrompt} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onGeolocationPermissionsHidePrompt.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onGeolocationPermissionsHidePrompt', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onGeolocationPermissionsHidePrompt()', - ), - ], - ) - void onGeolocationPermissionsHidePrompt() {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.androidShouldInterceptRequest} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidShouldInterceptRequest.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - @Deprecated("Use shouldInterceptRequest instead") - FutureOr? androidShouldInterceptRequest( - WebResourceRequest request, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.shouldInterceptRequest} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.shouldInterceptRequest.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.shouldInterceptRequest', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#shouldInterceptRequest(android.webkit.WebView,%20android.webkit.WebResourceRequest)', - ), - WindowsPlatform( - apiName: 'ICoreWebView2.add_WebResourceRequested', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2478.35#add_webresourcerequested', - ), - ], - ) - FutureOr? shouldInterceptRequest( - WebResourceRequest request, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.androidOnRenderProcessUnresponsive} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnRenderProcessUnresponsive.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - @Deprecated("Use onRenderProcessUnresponsive instead") - FutureOr? androidOnRenderProcessUnresponsive( - Uri? url, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onRenderProcessUnresponsive} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onRenderProcessUnresponsive.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewRenderProcessClient.onRenderProcessUnresponsive', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewRenderProcessClient#onRenderProcessUnresponsive(android.webkit.WebView,%20android.webkit.WebViewRenderProcess)', - available: '29', - ), - WindowsPlatform( - apiName: 'ICoreWebView2.add_ProcessFailed', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2849.39#add_processfailed', - ), - ], - ) - FutureOr? onRenderProcessUnresponsive( - WebUri? url, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.androidOnRenderProcessResponsive} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnRenderProcessResponsive.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - @Deprecated("Use onRenderProcessResponsive instead") - FutureOr? androidOnRenderProcessResponsive( - Uri? url, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onRenderProcessResponsive} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onRenderProcessResponsive.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewRenderProcessClient.onRenderProcessResponsive', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewRenderProcessClient#onRenderProcessResponsive(android.webkit.WebView,%20android.webkit.WebViewRenderProcess)', - available: '29', - ), - ], - ) - FutureOr? onRenderProcessResponsive( - WebUri? url, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.androidOnRenderProcessGone} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnRenderProcessGone.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - @Deprecated("Use onRenderProcessGone instead") - void androidOnRenderProcessGone(RenderProcessGoneDetail detail) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onRenderProcessGone} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onRenderProcessGone.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.onRenderProcessGone', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#onRenderProcessGone(android.webkit.WebView,%20android.webkit.RenderProcessGoneDetail)', - available: '26', - ), - WindowsPlatform( - apiName: 'ICoreWebView2.add_ProcessFailed', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2849.39#add_processfailed', - ), - ], - ) - void onRenderProcessGone(RenderProcessGoneDetail detail) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.androidOnFormResubmission} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnFormResubmission.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - @Deprecated('Use onFormResubmission instead') - FutureOr? androidOnFormResubmission(Uri? url) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onFormResubmission} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onFormResubmission.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.onFormResubmission', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#onFormResubmission(android.webkit.WebView,%20android.os.Message,%20android.os.Message)', - ), - ], - ) - FutureOr? onFormResubmission(WebUri? url) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.androidOnScaleChanged} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnScaleChanged.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - @Deprecated('Use onZoomScaleChanged instead') - void androidOnScaleChanged(double oldScale, double newScale) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.androidOnReceivedIcon} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnReceivedIcon.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - @Deprecated('Use onReceivedIcon instead') - void androidOnReceivedIcon(Uint8List icon) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onReceivedIcon} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onReceivedIcon.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onReceivedIcon', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onReceivedIcon(android.webkit.WebView,%20android.graphics.Bitmap)', - ), - ], - ) - @Deprecated('Use onFaviconChanged instead') - void onReceivedIcon(Uint8List icon) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onFaviconChanged} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onFaviconChanged.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onReceivedIcon', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onReceivedIcon(android.webkit.WebView,%20android.graphics.Bitmap)', - ), - WindowsPlatform( - apiName: 'ICoreWebView2_15.add_FaviconChanged', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_15?view=webview2-1.0.2849.39#add_faviconchanged', - ), - ], - ) - void onFaviconChanged(FaviconChangedRequest faviconChangedRequest) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.androidOnReceivedTouchIconUrl} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnReceivedTouchIconUrl.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - @Deprecated('Use onReceivedTouchIconUrl instead') - void androidOnReceivedTouchIconUrl(Uri url, bool precomposed) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.androidOnReceivedTouchIconUrl} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnReceivedTouchIconUrl.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onReceivedTouchIconUrl', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onReceivedTouchIconUrl(android.webkit.WebView,%20java.lang.String,%20boolean)', - ), - ], - ) - void onReceivedTouchIconUrl(WebUri url, bool precomposed) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.androidOnJsBeforeUnload} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnJsBeforeUnload.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - @Deprecated('Use onJsBeforeUnload instead') - FutureOr? androidOnJsBeforeUnload( - JsBeforeUnloadRequest jsBeforeUnloadRequest, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onJsBeforeUnload} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onJsBeforeUnload.supported_platforms} - FutureOr? onJsBeforeUnload( - JsBeforeUnloadRequest jsBeforeUnloadRequest, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.androidOnReceivedLoginRequest} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnReceivedLoginRequest.supported_platforms} - @SupportedPlatforms(platforms: [AndroidPlatform()]) - @Deprecated('Use onReceivedLoginRequest instead') - void androidOnReceivedLoginRequest(LoginRequest loginRequest) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onReceivedLoginRequest} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onReceivedLoginRequest.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebViewClient.onReceivedLoginRequest', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedLoginRequest(android.webkit.WebView,%20java.lang.String,%20java.lang.String,%20java.lang.String)', - ), - ], - ) - void onReceivedLoginRequest(LoginRequest loginRequest) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onPermissionRequestCanceled} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onPermissionRequestCanceled.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onPermissionRequestCanceled', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onPermissionRequestCanceled(android.webkit.PermissionRequest)', - available: '21', - ), - ], - ) - void onPermissionRequestCanceled(PermissionRequest permissionRequest) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onRequestFocus} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onRequestFocus.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onRequestFocus', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onRequestFocus(android.webkit.WebView)', - ), - ], - ) - void onRequestFocus() {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.iosOnWebContentProcessDidTerminate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.iosOnWebContentProcessDidTerminate.supported_platforms} - @SupportedPlatforms(platforms: [IOSPlatform()]) - @Deprecated('Use onWebContentProcessDidTerminate instead') - void iosOnWebContentProcessDidTerminate() {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onWebContentProcessDidTerminate} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onWebContentProcessDidTerminate.supported_platforms} - @SupportedPlatforms( - platforms: [ - IOSPlatform( - apiName: 'WKNavigationDelegate.webViewWebContentProcessDidTerminate', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455639-webviewwebcontentprocessdidtermi', - ), - MacOSPlatform( - apiName: 'WKNavigationDelegate.webViewWebContentProcessDidTerminate', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455639-webviewwebcontentprocessdidtermi', - ), - WindowsPlatform( - apiName: 'ICoreWebView2.add_ProcessFailed', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2849.39#add_processfailed', - ), - ], - ) - void onWebContentProcessDidTerminate() {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.iosOnDidReceiveServerRedirectForProvisionalNavigation} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.iosOnDidReceiveServerRedirectForProvisionalNavigation.supported_platforms} - @SupportedPlatforms(platforms: [IOSPlatform()]) - @Deprecated('Use onDidReceiveServerRedirectForProvisionalNavigation instead') - void iosOnDidReceiveServerRedirectForProvisionalNavigation() {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onDidReceiveServerRedirectForProvisionalNavigation} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onDidReceiveServerRedirectForProvisionalNavigation.supported_platforms} - @SupportedPlatforms( - platforms: [ - IOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455627-webview', - ), - MacOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455627-webview', - ), - ], - ) - void onDidReceiveServerRedirectForProvisionalNavigation() {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.iosOnNavigationResponse} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.iosOnNavigationResponse.supported_platforms} - @SupportedPlatforms(platforms: [IOSPlatform()]) - @Deprecated('Use onNavigationResponse instead') - FutureOr? iosOnNavigationResponse( - IOSWKNavigationResponse navigationResponse, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onNavigationResponse} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onNavigationResponse.supported_platforms} - @SupportedPlatforms( - platforms: [ - IOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview', - ), - MacOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview', - ), - ], - ) - FutureOr? onNavigationResponse( - NavigationResponse navigationResponse, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.iosShouldAllowDeprecatedTLS} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.iosShouldAllowDeprecatedTLS.supported_platforms} - @SupportedPlatforms(platforms: [IOSPlatform()]) - @Deprecated('Use shouldAllowDeprecatedTLS instead') - FutureOr? iosShouldAllowDeprecatedTLS( - URLAuthenticationChallenge challenge, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.shouldAllowDeprecatedTLS} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.shouldAllowDeprecatedTLS.supported_platforms} - @SupportedPlatforms( - platforms: [ - IOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/3601237-webview', - available: '14.0', - ), - MacOSPlatform( - apiName: 'WKNavigationDelegate.webView', - apiUrl: - 'https://developer.apple.com/documentation/webkit/wknavigationdelegate/3601237-webview', - available: '11.0', - ), - ], - ) - FutureOr? shouldAllowDeprecatedTLS( - URLAuthenticationChallenge challenge, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onCameraCaptureStateChanged} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onCameraCaptureStateChanged.supported_platforms} - @SupportedPlatforms( - platforms: [ - IOSPlatform(available: '15.0'), - MacOSPlatform(available: '12.0'), - ], - ) - void onCameraCaptureStateChanged( - MediaCaptureState? oldState, - MediaCaptureState? newState, - ) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onMicrophoneCaptureStateChanged} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onMicrophoneCaptureStateChanged.supported_platforms} - @SupportedPlatforms( - platforms: [ - IOSPlatform(available: '15.0'), - MacOSPlatform(available: '12.0'), - ], - ) - void onMicrophoneCaptureStateChanged( - MediaCaptureState? oldState, - MediaCaptureState? newState, - ) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onContentSizeChanged} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onContentSizeChanged.supported_platforms} - @SupportedPlatforms(platforms: [IOSPlatform()]) - void onContentSizeChanged(Size oldContentSize, Size newContentSize) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onProcessFailed} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onProcessFailed.supported_platforms} - @SupportedPlatforms( - platforms: [ - WindowsPlatform( - apiName: 'ICoreWebView2.add_ProcessFailed', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2849.39#add_processfailed', - ), - ], - ) - void onProcessFailed(ProcessFailedDetail detail) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onNotificationReceived} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onNotificationReceived.supported_platforms} - @SupportedPlatforms( - platforms: [ - WindowsPlatform( - apiName: 'ICoreWebView2_24.add_NotificationReceived', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_24?view=webview2-1.0.2849.39#add_notificationreceived', - ), - ], - ) - FutureOr? onNotificationReceived( - NotificationReceivedRequest request, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onSaveAsUIShowing} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onSaveAsUIShowing.supported_platforms} - @SupportedPlatforms( - platforms: [ - WindowsPlatform( - apiName: 'ICoreWebView2_25.add_SaveAsUIShowing', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_25?view=webview2-1.0.2849.39#add_saveasuishowing', - ), - ], - ) - FutureOr? onSaveAsUIShowing( - SaveAsUIShowingRequest request, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onSaveFileSecurityCheckStarting} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onSaveFileSecurityCheckStarting.supported_platforms} - @SupportedPlatforms( - platforms: [ - WindowsPlatform( - apiName: 'ICoreWebView2_26.add_SaveFileSecurityCheckStarting', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_26?view=webview2-1.0.2849.39#add_savefilesecuritycheckstarting', - ), - ], - ) - FutureOr? - onSaveFileSecurityCheckStarting( - SaveFileSecurityCheckStartingRequest request, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onScreenCaptureStarting} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onScreenCaptureStarting.supported_platforms} - @SupportedPlatforms( - platforms: [ - WindowsPlatform( - apiName: 'ICoreWebView2_27.add_ScreenCaptureStarting', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_27?view=webview2-1.0.2849.39#add_screencapturestarting', - ), - ], - ) - FutureOr? onScreenCaptureStarting( - ScreenCaptureStartingRequest request, - ) { - return null; - } - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onAcceleratorKeyPressed} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onAcceleratorKeyPressed.supported_platforms} - @SupportedPlatforms( - platforms: [ - WindowsPlatform( - apiName: 'ICoreWebView2Controller.add_AcceleratorKeyPressed', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2controller?view=webview2-1.0.2849.39#add_acceleratorkeypressed', - ), - ], - ) - void onAcceleratorKeyPressed(AcceleratorKeyPressedDetail detail) {} - - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.onShowFileChooser} - /// - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onShowFileChooser.supported_platforms} - @SupportedPlatforms( - platforms: [ - AndroidPlatform( - apiName: 'WebChromeClient.onShowFileChooser', - apiUrl: - 'https://developer.android.com/reference/android/webkit/WebChromeClient#onShowFileChooser(android.webkit.WebView,%20android.webkit.ValueCallback%3Candroid.net.Uri[]%3E,%20android.webkit.WebChromeClient.FileChooserParams)', - ), - ], - ) - FutureOr onShowFileChooser( - ShowFileChooserRequest request, - ) { - return null; - } - - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.isMethodSupported} - ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. - ///{@endtemplate} - static bool isMethodSupported( - PlatformInAppBrowserEventsMethod method, { - TargetPlatform? platform, - }) => _PlatformInAppBrowserEventsMethodSupported.isMethodSupported( - method, - platform: platform, - ); -} diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/platform_in_app_browser.g.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_browser/platform_in_app_browser.g.dart deleted file mode 100644 index 4d8b0e1304..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/platform_in_app_browser.g.dart +++ /dev/null @@ -1,2748 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'platform_in_app_browser.dart'; - -// ************************************************************************** -// SupportedPlatformsGenerator -// ************************************************************************** - -extension _PlatformInAppBrowserClassSupported on PlatformInAppBrowser { - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit ([Official API - GtkWindow + WPE WebKit](https://wpewebkit.org/reference/stable/wpe-webkit-2.0/class.WebView.html)) - /// - ///Use the [PlatformInAppBrowser.isClassSupported] method to check if this class is supported at runtime. - ///{@endtemplate} - static bool isClassSupported({TargetPlatform? platform}) { - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - } -} - -///List of [PlatformInAppBrowser]'s properties that can be used to check i they are supported or not by the current platform. -enum PlatformInAppBrowserProperty { - ///Can be used to check if the [PlatformInAppBrowser.contextMenu] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.contextMenu.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - /// - ///Use the [PlatformInAppBrowser.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - contextMenu, - - ///Can be used to check if the [PlatformInAppBrowser.findInteractionController] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.findInteractionController.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - /// - ///Use the [PlatformInAppBrowser.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - findInteractionController, - - ///Can be used to check if the [PlatformInAppBrowser.id] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.id.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [PlatformInAppBrowser.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - id, - - ///Can be used to check if the [PlatformInAppBrowser.initialUserScripts] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.initialUserScripts.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView: - /// - This property will be ignored if the [PlatformWebViewCreationParams.windowId] has been set. There isn't any way to add/remove user scripts specific to iOS window WebViews. This is a limitation of the native WebKit APIs. - ///- macOS WKWebView: - /// - This property will be ignored if the [PlatformWebViewCreationParams.windowId] has been set. There isn't any way to add/remove user scripts specific to iOS window WebViews. This is a limitation of the native WebKit APIs. - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [PlatformInAppBrowser.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - initialUserScripts, - - ///Can be used to check if the [PlatformInAppBrowser.pullToRefreshController] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.pullToRefreshController.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - /// - ///Use the [PlatformInAppBrowser.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - pullToRefreshController, - - ///Can be used to check if the [PlatformInAppBrowser.webViewEnvironment] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.webViewEnvironment.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Windows WebView2 - /// - ///Use the [PlatformInAppBrowser.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - webViewEnvironment, - - ///Can be used to check if the [PlatformInAppBrowser.windowId] property is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.windowId.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [PlatformInAppBrowser.isPropertySupported] method to check if this property is supported at runtime. - ///{@endtemplate} - windowId, -} - -extension _PlatformInAppBrowserPropertySupported on PlatformInAppBrowser { - static bool isPropertySupported( - PlatformInAppBrowserProperty property, { - TargetPlatform? platform, - }) { - switch (property) { - case PlatformInAppBrowserProperty.contextMenu: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserProperty.findInteractionController: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserProperty.id: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserProperty.initialUserScripts: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserProperty.pullToRefreshController: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserProperty.webViewEnvironment: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserProperty.windowId: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - } - } -} - -///List of [PlatformInAppBrowser]'s methods that can be used to check if they are supported or not by the current platform. -enum PlatformInAppBrowserMethod { - ///Can be used to check if the [PlatformInAppBrowser.addMenuItem] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.addMenuItem.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView 14.0+ - ///- macOS WKWebView 10.15+ - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [menuItem]: all platforms - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - addMenuItem, - - ///Can be used to check if the [PlatformInAppBrowser.addMenuItems] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.addMenuItems.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView 14.0+ - ///- macOS WKWebView 10.15+ - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [menuItems]: all platforms - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - addMenuItems, - - ///Can be used to check if the [PlatformInAppBrowser.close] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.close.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - close, - - ///Can be used to check if the [PlatformInAppBrowser.dispose] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.dispose.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - dispose, - - ///Can be used to check if the [PlatformInAppBrowser.getOptions] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.getOptions.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use getSettings instead') - getOptions, - - ///Can be used to check if the [PlatformInAppBrowser.getSettings] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.getSettings.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - getSettings, - - ///Can be used to check if the [PlatformInAppBrowser.hasMenuItem] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.hasMenuItem.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView 14.0+ - ///- macOS WKWebView 10.15+ - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [menuItem]: all platforms - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - hasMenuItem, - - ///Can be used to check if the [PlatformInAppBrowser.hide] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.hide.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - hide, - - ///Can be used to check if the [PlatformInAppBrowser.isHidden] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.isHidden.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - isHidden, - - ///Can be used to check if the [PlatformInAppBrowser.isOpened] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.isOpened.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - isOpened, - - ///Can be used to check if the [PlatformInAppBrowser.openData] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.openData.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [data]: all platforms - ///- [mimeType]: all platforms - ///- [encoding]: all platforms - ///- [baseUrl]: all platforms - ///- [historyUrl]: all platforms - ///- [settings]: all platforms - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - openData, - - ///Can be used to check if the [PlatformInAppBrowser.openFile] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.openFile.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [assetFilePath]: all platforms - ///- [settings]: all platforms - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - openFile, - - ///Can be used to check if the [PlatformInAppBrowser.openUrlRequest] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.openUrlRequest.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [urlRequest]: all platforms - ///- [settings]: all platforms - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - openUrlRequest, - - ///Can be used to check if the [PlatformInAppBrowser.openWithSystemBrowser] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.openWithSystemBrowser.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - openWithSystemBrowser, - - ///Can be used to check if the [PlatformInAppBrowser.removeAllMenuItem] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.removeAllMenuItem.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView 14.0+ - ///- macOS WKWebView 10.15+ - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - removeAllMenuItem, - - ///Can be used to check if the [PlatformInAppBrowser.removeMenuItem] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.removeMenuItem.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView 14.0+ - ///- macOS WKWebView 10.15+ - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [menuItem]: all platforms - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - removeMenuItem, - - ///Can be used to check if the [PlatformInAppBrowser.removeMenuItems] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.removeMenuItems.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView 14.0+ - ///- macOS WKWebView 10.15+ - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [menuItems]: all platforms - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - removeMenuItems, - - ///Can be used to check if the [PlatformInAppBrowser.setOptions] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.setOptions.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [options]: all platforms - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use setSettings instead') - setOptions, - - ///Can be used to check if the [PlatformInAppBrowser.setSettings] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.setSettings.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [settings]: all platforms - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - setSettings, - - ///Can be used to check if the [PlatformInAppBrowser.show] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowser.show.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [PlatformInAppBrowser.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - show, -} - -extension _PlatformInAppBrowserMethodSupported on PlatformInAppBrowser { - static bool isMethodSupported( - PlatformInAppBrowserMethod method, { - TargetPlatform? platform, - }) { - switch (method) { - case PlatformInAppBrowserMethod.addMenuItem: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.addMenuItems: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.close: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.dispose: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.getOptions: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.getSettings: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.hasMenuItem: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.hide: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.isHidden: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.isOpened: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.openData: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.openFile: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.openUrlRequest: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.openWithSystemBrowser: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.removeAllMenuItem: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.removeMenuItem: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.removeMenuItems: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.setOptions: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.setSettings: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserMethod.show: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - } - } -} - -///List of [PlatformInAppBrowserEvents]'s methods that can be used to check if they are supported or not by the current platform. -enum PlatformInAppBrowserEventsMethod { - ///Can be used to check if the [PlatformInAppBrowserEvents.androidOnFormResubmission] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnFormResubmission.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onFormResubmission instead') - androidOnFormResubmission, - - ///Can be used to check if the [PlatformInAppBrowserEvents.androidOnGeolocationPermissionsHidePrompt] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnGeolocationPermissionsHidePrompt.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onGeolocationPermissionsHidePrompt instead') - androidOnGeolocationPermissionsHidePrompt, - - ///Can be used to check if the [PlatformInAppBrowserEvents.androidOnGeolocationPermissionsShowPrompt] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnGeolocationPermissionsShowPrompt.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [origin]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onGeolocationPermissionsShowPrompt instead') - androidOnGeolocationPermissionsShowPrompt, - - ///Can be used to check if the [PlatformInAppBrowserEvents.androidOnJsBeforeUnload] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnJsBeforeUnload.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [jsBeforeUnloadRequest]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onJsBeforeUnload instead') - androidOnJsBeforeUnload, - - ///Can be used to check if the [PlatformInAppBrowserEvents.androidOnPermissionRequest] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnPermissionRequest.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [origin]: all platforms - ///- [resources]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onPermissionRequest instead') - androidOnPermissionRequest, - - ///Can be used to check if the [PlatformInAppBrowserEvents.androidOnReceivedIcon] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnReceivedIcon.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [icon]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onReceivedIcon instead') - androidOnReceivedIcon, - - ///Can be used to check if the [PlatformInAppBrowserEvents.androidOnReceivedLoginRequest] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnReceivedLoginRequest.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [loginRequest]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onReceivedLoginRequest instead') - androidOnReceivedLoginRequest, - - ///Can be used to check if the [PlatformInAppBrowserEvents.androidOnReceivedTouchIconUrl] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnReceivedTouchIconUrl.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - ///- [precomposed]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onReceivedTouchIconUrl instead') - androidOnReceivedTouchIconUrl, - - ///Can be used to check if the [PlatformInAppBrowserEvents.androidOnRenderProcessGone] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnRenderProcessGone.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [detail]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onRenderProcessGone instead') - androidOnRenderProcessGone, - - ///Can be used to check if the [PlatformInAppBrowserEvents.androidOnRenderProcessResponsive] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnRenderProcessResponsive.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onRenderProcessResponsive instead') - androidOnRenderProcessResponsive, - - ///Can be used to check if the [PlatformInAppBrowserEvents.androidOnRenderProcessUnresponsive] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnRenderProcessUnresponsive.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onRenderProcessUnresponsive instead') - androidOnRenderProcessUnresponsive, - - ///Can be used to check if the [PlatformInAppBrowserEvents.androidOnSafeBrowsingHit] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnSafeBrowsingHit.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - ///- [threatType]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onSafeBrowsingHit instead') - androidOnSafeBrowsingHit, - - ///Can be used to check if the [PlatformInAppBrowserEvents.androidOnScaleChanged] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidOnScaleChanged.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [oldScale]: all platforms - ///- [newScale]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onZoomScaleChanged instead') - androidOnScaleChanged, - - ///Can be used to check if the [PlatformInAppBrowserEvents.androidShouldInterceptRequest] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.androidShouldInterceptRequest.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [request]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use shouldInterceptRequest instead') - androidShouldInterceptRequest, - - ///Can be used to check if the [PlatformInAppBrowserEvents.iosOnDidReceiveServerRedirectForProvisionalNavigation] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.iosOnDidReceiveServerRedirectForProvisionalNavigation.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onDidReceiveServerRedirectForProvisionalNavigation instead') - iosOnDidReceiveServerRedirectForProvisionalNavigation, - - ///Can be used to check if the [PlatformInAppBrowserEvents.iosOnNavigationResponse] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.iosOnNavigationResponse.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [navigationResponse]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onNavigationResponse instead') - iosOnNavigationResponse, - - ///Can be used to check if the [PlatformInAppBrowserEvents.iosOnWebContentProcessDidTerminate] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.iosOnWebContentProcessDidTerminate.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onWebContentProcessDidTerminate instead') - iosOnWebContentProcessDidTerminate, - - ///Can be used to check if the [PlatformInAppBrowserEvents.iosShouldAllowDeprecatedTLS] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.iosShouldAllowDeprecatedTLS.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [challenge]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use shouldAllowDeprecatedTLS instead') - iosShouldAllowDeprecatedTLS, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onAcceleratorKeyPressed] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onAcceleratorKeyPressed.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Windows WebView2 ([Official API - ICoreWebView2Controller.add_AcceleratorKeyPressed](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2controller?view=webview2-1.0.2849.39#add_acceleratorkeypressed)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [detail]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onAcceleratorKeyPressed, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onAjaxProgress] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onAjaxProgress.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView: - /// - In order to be able to listen this event, check the [InAppWebViewSettings.useShouldInterceptAjaxRequest] and [InAppWebViewSettings.useOnAjaxProgress] settings documentation. Also, on Android that doesn't support the [WebViewFeature.DOCUMENT_START_SCRIPT], unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS. In that case, after the `window.addEventListener("flutterInAppWebViewPlatformReady")` event is dispatched, the ajax requests can be intercept for sure. - ///- iOS WKWebView - ///- macOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [ajaxRequest]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onAjaxProgress, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onAjaxReadyStateChange] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onAjaxReadyStateChange.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView: - /// - In order to be able to listen this event, check the [InAppWebViewSettings.useShouldInterceptAjaxRequest] and [InAppWebViewSettings.useOnAjaxReadyStateChange] settings documentation. Also, on Android that doesn't support the [WebViewFeature.DOCUMENT_START_SCRIPT], unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS. In that case, after the `window.addEventListener("flutterInAppWebViewPlatformReady")` event is dispatched, the ajax requests can be intercept for sure. - ///- iOS WKWebView - ///- macOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [ajaxRequest]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onAjaxReadyStateChange, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onBrowserCreated] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onBrowserCreated.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onBrowserCreated, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onCameraCaptureStateChanged] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onCameraCaptureStateChanged.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView 15.0+ - ///- macOS WKWebView 12.0+ - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [oldState]: all platforms - ///- [newState]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onCameraCaptureStateChanged, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onCloseWindow] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onCloseWindow.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onCloseWindow](https://developer.android.com/reference/android/webkit/WebChromeClient#onCloseWindow(android.webkit.WebView))) - ///- iOS WKWebView ([Official API - WKUIDelegate.webViewDidClose](https://developer.apple.com/documentation/webkit/wkuidelegate/1537390-webviewdidclose)) - ///- macOS WKWebView ([Official API - WKUIDelegate.webViewDidClose](https://developer.apple.com/documentation/webkit/wkuidelegate/1537390-webviewdidclose)) - ///- Web \ but requires same origin - ///- Windows WebView2 ([Official API - ICoreWebView2.add_WindowCloseRequested](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_windowcloserequested)) - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onCloseWindow, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onConsoleMessage] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onConsoleMessage.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onConsoleMessage](https://developer.android.com/reference/android/webkit/WebChromeClient#onConsoleMessage(android.webkit.ConsoleMessage))) - ///- iOS WKWebView: - /// - This event is implemented using JavaScript. - ///- macOS WKWebView: - /// - This event is implemented using JavaScript. - ///- Web \ but requires same origin - ///- Windows WebView2 - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [consoleMessage]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onConsoleMessage, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onContentLoading] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onContentLoading.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Windows WebView2 ([Official API - ICoreWebView2.add_ContentLoading](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_contentloading)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onContentLoading, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onContentSizeChanged] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onContentSizeChanged.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [oldContentSize]: all platforms - ///- [newContentSize]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onContentSizeChanged, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onCreateWindow] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onCreateWindow.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onCreateWindow](https://developer.android.com/reference/android/webkit/WebChromeClient#onCreateWindow(android.webkit.WebView,%20boolean,%20boolean,%20android.os.Message))): - /// - You need to set [InAppWebViewSettings.supportMultipleWindows] setting to `true`. Also, if the request has been created using JavaScript (`window.open()`), then there are some limitation: check the [NavigationAction] class. - ///- iOS WKWebView ([Official API - WKUIDelegate.webView](https://developer.apple.com/documentation/webkit/wkuidelegate/1536907-webview)): - /// - Setting these initial settings [InAppWebViewSettings.supportZoom], [InAppWebViewSettings.useOnLoadResource], [InAppWebViewSettings.useShouldInterceptAjaxRequest], [InAppWebViewSettings.useShouldInterceptFetchRequest], [InAppWebViewSettings.applicationNameForUserAgent], [InAppWebViewSettings.javaScriptCanOpenWindowsAutomatically], [InAppWebViewSettings.javaScriptEnabled], [InAppWebViewSettings.minimumFontSize], [InAppWebViewSettings.preferredContentMode], [InAppWebViewSettings.incognito], [InAppWebViewSettings.cacheEnabled], [InAppWebViewSettings.mediaPlaybackRequiresUserGesture], [InAppWebViewSettings.resourceCustomSchemes], [InAppWebViewSettings.sharedCookiesEnabled], [InAppWebViewSettings.enableViewportScale], [InAppWebViewSettings.allowsAirPlayForMediaPlayback], [InAppWebViewSettings.allowsPictureInPictureMediaPlayback], [InAppWebViewSettings.isFraudulentWebsiteWarningEnabled], [InAppWebViewSettings.allowsInlineMediaPlayback], [InAppWebViewSettings.suppressesIncrementalRendering], [InAppWebViewSettings.selectionGranularity], [InAppWebViewSettings.ignoresViewportScaleLimits], [InAppWebViewSettings.limitsNavigationsToAppBoundDomains], [InAppWebViewSettings.upgradeKnownHostsToHTTPS], will have no effect due to a `WKWebView` limitation when creating the new window WebView: it's impossible to return the new `WKWebView` with a different `WKWebViewConfiguration` instance (see https://developer.apple.com/documentation/webkit/wkuidelegate/1536907-webview). So, these options will be inherited from the caller WebView. Also, note that calling [InAppWebViewController.setSettings] method using the controller of the new created WebView, it will update also the WebView options of the caller WebView. - ///- macOS WKWebView ([Official API - WKUIDelegate.webView](https://developer.apple.com/documentation/webkit/wkuidelegate/1536907-webview)): - /// - Setting these initial settings [InAppWebViewSettings.supportZoom], [InAppWebViewSettings.useOnLoadResource], [InAppWebViewSettings.useShouldInterceptAjaxRequest], [InAppWebViewSettings.useShouldInterceptFetchRequest], [InAppWebViewSettings.applicationNameForUserAgent], [InAppWebViewSettings.javaScriptCanOpenWindowsAutomatically], [InAppWebViewSettings.javaScriptEnabled], [InAppWebViewSettings.minimumFontSize], [InAppWebViewSettings.preferredContentMode], [InAppWebViewSettings.incognito], [InAppWebViewSettings.cacheEnabled], [InAppWebViewSettings.mediaPlaybackRequiresUserGesture], [InAppWebViewSettings.resourceCustomSchemes], [InAppWebViewSettings.sharedCookiesEnabled], [InAppWebViewSettings.enableViewportScale], [InAppWebViewSettings.allowsAirPlayForMediaPlayback], [InAppWebViewSettings.allowsPictureInPictureMediaPlayback], [InAppWebViewSettings.isFraudulentWebsiteWarningEnabled], [InAppWebViewSettings.allowsInlineMediaPlayback], [InAppWebViewSettings.suppressesIncrementalRendering], [InAppWebViewSettings.selectionGranularity], [InAppWebViewSettings.ignoresViewportScaleLimits], [InAppWebViewSettings.limitsNavigationsToAppBoundDomains], [InAppWebViewSettings.upgradeKnownHostsToHTTPS], will have no effect due to a `WKWebView` limitation when creating the new window WebView: it's impossible to return the new `WKWebView` with a different `WKWebViewConfiguration` instance (see https://developer.apple.com/documentation/webkit/wkuidelegate/1536907-webview). So, these options will be inherited from the caller WebView. Also, note that calling [InAppWebViewController.setSettings] method using the controller of the new created WebView, it will update also the WebView options of the caller WebView. - ///- Windows WebView2 ([Official API - ICoreWebView2.add_NewWindowRequested](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_newwindowrequested)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [createWindowAction]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onCreateWindow, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onDOMContentLoaded] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onDOMContentLoaded.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Windows WebView2 ([Official API - ICoreWebView2_2.add_DOMContentLoaded](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_2?view=webview2-1.0.2210.55#add_domcontentloaded)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onDOMContentLoaded, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onDidReceiveServerRedirectForProvisionalNavigation] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onDidReceiveServerRedirectForProvisionalNavigation.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455627-webview)) - ///- macOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455627-webview)) - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onDidReceiveServerRedirectForProvisionalNavigation, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onDownloadStart] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onDownloadStart.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onDownloadStarting instead') - onDownloadStart, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onDownloadStartRequest] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onDownloadStartRequest.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [downloadStartRequest]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onDownloadStarting instead') - onDownloadStartRequest, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onDownloadStarting] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onDownloadStarting.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebView.setDownloadListener]((https://developer.android.com/reference/android/webkit/WebView#setDownloadListener(android.webkit.DownloadListener))) - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 ([Official API - ICoreWebView2_4.add_DownloadStarting](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_4?view=webview2-1.0.2849.39#add_downloadstarting)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [downloadStartRequest]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onDownloadStarting, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onEnterFullscreen] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onEnterFullscreen.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onShowCustomView](https://developer.android.com/reference/android/webkit/WebChromeClient#onShowCustomView(android.view.View,%20android.webkit.WebChromeClient.CustomViewCallback))) - ///- iOS WKWebView ([Official API - UIWindow.didBecomeVisibleNotification](https://developer.apple.com/documentation/uikit/uiwindow/1621621-didbecomevisiblenotification)) - ///- macOS WKWebView ([Official API - NSWindow.didEnterFullScreenNotification](https://developer.apple.com/documentation/appkit/nswindow/1419651-didenterfullscreennotification)) - ///- Windows WebView2 ([Official API - ICoreWebView2.add_ContainsFullScreenElementChanged](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_containsfullscreenelementchanged)) - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onEnterFullscreen, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onExit] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onExit.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - ///- Linux WPE WebKit - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onExit, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onExitFullscreen] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onExitFullscreen.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onHideCustomView](https://developer.android.com/reference/android/webkit/WebChromeClient#onHideCustomView())) - ///- iOS WKWebView ([Official API - UIWindow.didBecomeHiddenNotification](https://developer.apple.com/documentation/uikit/uiwindow/1621617-didbecomehiddennotification)) - ///- macOS WKWebView ([Official API - NSWindow.didExitFullScreenNotification](https://developer.apple.com/documentation/appkit/nswindow/1419177-didexitfullscreennotification)) - ///- Windows WebView2 ([Official API - ICoreWebView2.add_ContainsFullScreenElementChanged](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_containsfullscreenelementchanged)) - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onExitFullscreen, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onFaviconChanged] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onFaviconChanged.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onReceivedIcon](https://developer.android.com/reference/android/webkit/WebChromeClient#onReceivedIcon(android.webkit.WebView,%20android.graphics.Bitmap))) - ///- Windows WebView2 ([Official API - ICoreWebView2_15.add_FaviconChanged](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_15?view=webview2-1.0.2849.39#add_faviconchanged)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [faviconChangedRequest]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onFaviconChanged, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onFindResultReceived] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onFindResultReceived.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [activeMatchOrdinal]: all platforms - ///- [numberOfMatches]: all platforms - ///- [isDoneCounting]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use FindInteractionController.onFindResultReceived instead') - onFindResultReceived, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onFormResubmission] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onFormResubmission.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebViewClient.onFormResubmission](https://developer.android.com/reference/android/webkit/WebViewClient#onFormResubmission(android.webkit.WebView,%20android.os.Message,%20android.os.Message))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onFormResubmission, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onGeolocationPermissionsHidePrompt] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onGeolocationPermissionsHidePrompt.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onGeolocationPermissionsHidePrompt](https://developer.android.com/reference/android/webkit/WebChromeClient#onGeolocationPermissionsHidePrompt())) - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onGeolocationPermissionsHidePrompt, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onGeolocationPermissionsShowPrompt] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onGeolocationPermissionsShowPrompt.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onGeolocationPermissionsShowPrompt](https://developer.android.com/reference/android/webkit/WebChromeClient#onGeolocationPermissionsShowPrompt(java.lang.String,%20android.webkit.GeolocationPermissions.Callback))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [origin]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onGeolocationPermissionsShowPrompt, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onJsAlert] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onJsAlert.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onJsAlert](https://developer.android.com/reference/android/webkit/WebChromeClient#onJsAlert(android.webkit.WebView,%20java.lang.String,%20java.lang.String,%20android.webkit.JsResult))) - ///- iOS WKWebView ([Official API - WKUIDelegate.webView](https://developer.apple.com/documentation/webkit/wkuidelegate/1537406-webview)) - ///- macOS WKWebView ([Official API - WKUIDelegate.webView](https://developer.apple.com/documentation/webkit/wkuidelegate/1537406-webview)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [jsAlertRequest]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onJsAlert, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onJsConfirm] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onJsConfirm.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onJsConfirm](https://developer.android.com/reference/android/webkit/WebChromeClient#onJsConfirm(android.webkit.WebView,%20java.lang.String,%20java.lang.String,%20android.webkit.JsResult))) - ///- iOS WKWebView ([Official API - WKUIDelegate.webView](https://developer.apple.com/documentation/webkit/wkuidelegate/1536489-webview)) - ///- macOS WKWebView ([Official API - WKUIDelegate.webView](https://developer.apple.com/documentation/webkit/wkuidelegate/1536489-webview)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [jsConfirmRequest]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onJsConfirm, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onJsPrompt] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onJsPrompt.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onJsPrompt](https://developer.android.com/reference/android/webkit/WebChromeClient#onJsPrompt(android.webkit.WebView,%20java.lang.String,%20java.lang.String,%20java.lang.String,%20android.webkit.JsPromptResult))) - ///- iOS WKWebView ([Official API - WKUIDelegate.webView](https://developer.apple.com/documentation/webkit/wkuidelegate/1538086-webview)) - ///- macOS WKWebView ([Official API - WKUIDelegate.webView](https://developer.apple.com/documentation/webkit/wkuidelegate/1538086-webview)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [jsPromptRequest]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onJsPrompt, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onLaunchingExternalUriScheme] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLaunchingExternalUriScheme.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Windows WebView2 ([Official API - ICoreWebView2_18.add_LaunchingExternalUriScheme](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_18?view=webview2-1.0.2849.39#add_launchingexternalurischeme)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [request]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onLaunchingExternalUriScheme, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onLoadError] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLoadError.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - ///- [code]: all platforms - ///- [message]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onReceivedError instead') - onLoadError, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onLoadHttpError] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLoadHttpError.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - ///- [statusCode]: all platforms - ///- [description]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onReceivedHttpError instead') - onLoadHttpError, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onLoadResource] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLoadResource.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView: - /// - This event is implemented using JavaScript. - ///- iOS WKWebView: - /// - This event is implemented using JavaScript. - ///- macOS WKWebView: - /// - This event is implemented using JavaScript. - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [resource]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onLoadResource, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onLoadResourceCustomScheme] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLoadResourceCustomScheme.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onLoadResourceWithCustomScheme instead') - onLoadResourceCustomScheme, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onLoadResourceWithCustomScheme] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLoadResourceWithCustomScheme.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView ([Official API - WKURLSchemeHandler](https://developer.apple.com/documentation/webkit/wkurlschemehandler)) - ///- macOS WKWebView ([Official API - WKURLSchemeHandler](https://developer.apple.com/documentation/webkit/wkurlschemehandler)) - ///- Windows WebView2 - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [request]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onLoadResourceWithCustomScheme, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onLoadStart] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLoadStart.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebViewClient.onPageStarted](https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap))) - ///- iOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455621-webview)) - ///- macOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455621-webview)) - ///- Windows WebView2 ([Official API - ICoreWebView2.add_NavigationStarting](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/iwebview2webview?view=webview2-0.8.355#add_navigationstarting)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onLoadStart, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onLoadStop] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLoadStop.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebViewClient.onPageFinished](https://developer.android.com/reference/android/webkit/WebViewClient#onPageFinished(android.webkit.WebView,%20java.lang.String))) - ///- iOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455629-webview)) - ///- macOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455629-webview)) - ///- Windows WebView2 ([Official API - ICoreWebView2.add_NavigationCompleted](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/iwebview2webview?view=webview2-0.8.355#add_navigationcompleted)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onLoadStop, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onLongPressHitTestResult] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onLongPressHitTestResult.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - View.setOnLongClickListener](https://developer.android.com/reference/android/view/View#setOnLongClickListener(android.view.View.OnLongClickListener))) - ///- iOS WKWebView ([Official API - UILongPressGestureRecognizer](https://developer.apple.com/documentation/uikit/uilongpressgesturerecognizer)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [hitTestResult]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onLongPressHitTestResult, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onMainWindowWillClose] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onMainWindowWillClose.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- macOS WKWebView - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onMainWindowWillClose, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onMicrophoneCaptureStateChanged] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onMicrophoneCaptureStateChanged.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView 15.0+ - ///- macOS WKWebView 12.0+ - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [oldState]: all platforms - ///- [newState]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onMicrophoneCaptureStateChanged, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onNavigationResponse] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onNavigationResponse.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview)) - ///- macOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [navigationResponse]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onNavigationResponse, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onNotificationReceived] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onNotificationReceived.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Windows WebView2 ([Official API - ICoreWebView2_24.add_NotificationReceived](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_24?view=webview2-1.0.2849.39#add_notificationreceived)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [request]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onNotificationReceived, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onOverScrolled] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onOverScrolled.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebView.onOverScrolled](https://developer.android.com/reference/android/webkit/WebView#onOverScrolled(int,%20int,%20boolean,%20boolean))) - ///- iOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [x]: all platforms - ///- [y]: all platforms - ///- [clampedX]: all platforms - ///- [clampedY]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onOverScrolled, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onPageCommitVisible] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onPageCommitVisible.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebViewClient.onPageCommitVisible](https://developer.android.com/reference/android/webkit/WebViewClient#onPageCommitVisible(android.webkit.WebView,%20java.lang.String))) - ///- iOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455635-webview)) - ///- macOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455635-webview)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onPageCommitVisible, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onPermissionRequest] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onPermissionRequest.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView 21+ ([Official API - WebChromeClient.onPermissionRequest](https://developer.android.com/reference/android/webkit/WebChromeClient#onPermissionRequest(android.webkit.PermissionRequest))) - ///- iOS WKWebView 15.0+: - /// - The default [PermissionResponse.action] is [PermissionResponseAction.PROMPT]. - ///- macOS WKWebView 12.0+: - /// - The default [PermissionResponse.action] is [PermissionResponseAction.PROMPT]. - ///- Windows WebView2 ([Official API - ICoreWebView2.add_PermissionRequested](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_permissionrequested)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [permissionRequest]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onPermissionRequest, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onPermissionRequestCanceled] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onPermissionRequestCanceled.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView 21+ ([Official API - WebChromeClient.onPermissionRequestCanceled](https://developer.android.com/reference/android/webkit/WebChromeClient#onPermissionRequestCanceled(android.webkit.PermissionRequest))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [permissionRequest]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onPermissionRequestCanceled, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onPrint] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onPrint.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onPrintRequest instead') - onPrint, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onPrintRequest] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onPrintRequest.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - View.scrollBy](https://developer.android.com/reference/android/view/View#scrollBy(int,%20int))) - ///- iOS WKWebView ([Official API - UIScrollView.setContentOffset](https://developer.apple.com/documentation/uikit/uiscrollview/1619400-setcontentoffset)) - ///- macOS WKWebView: - /// - This method is implemented using JavaScript. - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - ///- [printJobController]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onPrintRequest, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onProcessFailed] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onProcessFailed.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Windows WebView2 ([Official API - ICoreWebView2.add_ProcessFailed](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2849.39#add_processfailed)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [detail]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onProcessFailed, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onProgressChanged] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onProgressChanged.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onProgressChanged](https://developer.android.com/reference/android/webkit/WebChromeClient#onProgressChanged(android.webkit.WebView,%20int))) - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [progress]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onProgressChanged, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onReceivedClientCertRequest] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onReceivedClientCertRequest.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebViewClient.onReceivedClientCertRequest](https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedClientCertRequest(android.webkit.WebView,%20android.webkit.ClientCertRequest))) - ///- iOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview)) - ///- macOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview)) - ///- Windows WebView2 ([Official API - ICoreWebView2_5.add_ClientCertificateRequested](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_5?view=webview2-1.0.2849.39#add_clientcertificaterequested)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [challenge]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onReceivedClientCertRequest, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onReceivedError] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onReceivedError.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebViewClient.onReceivedError](https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedError(android.webkit.WebView,%20android.webkit.WebResourceRequest,%20android.webkit.WebResourceError))) - ///- iOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455623-webview)) - ///- macOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455623-webview)) - ///- Windows WebView2 ([Official API - ICoreWebView2.add_NavigationCompleted](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/iwebview2webview?view=webview2-0.8.355#add_navigationcompleted)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [request]: all platforms - ///- [error]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onReceivedError, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onReceivedHttpAuthRequest] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onReceivedHttpAuthRequest.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebViewClient.onReceivedHttpAuthRequest](https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedHttpAuthRequest(android.webkit.WebView,%20android.webkit.HttpAuthHandler,%20java.lang.String,%20java.lang.String))) - ///- iOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview)) - ///- macOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview)) - ///- Windows WebView2 ([Official API - ICoreWebView2_10.add_BasicAuthenticationRequested](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_10?view=webview2-1.0.2849.39#add_basicauthenticationrequested)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [challenge]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onReceivedHttpAuthRequest, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onReceivedHttpError] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onReceivedHttpError.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView 23+ ([Official API - WebViewClient.onReceivedHttpError](https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedHttpError(android.webkit.WebView,%20android.webkit.WebResourceRequest,%20android.webkit.WebResourceResponse))) - ///- iOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview)) - ///- macOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview)) - ///- Windows WebView2 ([Official API - ICoreWebView2.add_NavigationCompleted](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/iwebview2webview?view=webview2-0.8.355#add_navigationcompleted)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [request]: all platforms - ///- [errorResponse]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onReceivedHttpError, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onReceivedIcon] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onReceivedIcon.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onReceivedIcon](https://developer.android.com/reference/android/webkit/WebChromeClient#onReceivedIcon(android.webkit.WebView,%20android.graphics.Bitmap))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [icon]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - @Deprecated('Use onFaviconChanged instead') - onReceivedIcon, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onReceivedLoginRequest] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onReceivedLoginRequest.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebViewClient.onReceivedLoginRequest](https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedLoginRequest(android.webkit.WebView,%20java.lang.String,%20java.lang.String,%20java.lang.String))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [loginRequest]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onReceivedLoginRequest, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onReceivedServerTrustAuthRequest] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onReceivedServerTrustAuthRequest.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebViewClient.onReceivedSslError](https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedSslError(android.webkit.WebView,%20android.webkit.SslErrorHandler,%20android.net.http.SslError))) - ///- iOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview)): - /// - To override the certificate verification logic, you have to provide ATS (App Transport Security) exceptions in your iOS/macOS `Info.plist`. See `NSAppTransportSecurity` in the [Information Property List Key Reference](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW1) for details. - ///- macOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview)): - /// - To override the certificate verification logic, you have to provide ATS (App Transport Security) exceptions in your iOS/macOS `Info.plist`. See `NSAppTransportSecurity` in the [Information Property List Key Reference](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW1) for details. - ///- Windows WebView2 ([Official API - ICoreWebView2_14.add_ServerCertificateErrorDetected](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_14?view=webview2-1.0.2792.45#add_servercertificateerrordetected)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [challenge]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onReceivedServerTrustAuthRequest, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onReceivedTouchIconUrl] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onReceivedTouchIconUrl.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onReceivedTouchIconUrl](https://developer.android.com/reference/android/webkit/WebChromeClient#onReceivedTouchIconUrl(android.webkit.WebView,%20java.lang.String,%20boolean))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - ///- [precomposed]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onReceivedTouchIconUrl, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onRenderProcessGone] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onRenderProcessGone.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView 26+ ([Official API - WebViewClient.onRenderProcessGone](https://developer.android.com/reference/android/webkit/WebViewClient#onRenderProcessGone(android.webkit.WebView,%20android.webkit.RenderProcessGoneDetail))) - ///- Windows WebView2 ([Official API - ICoreWebView2.add_ProcessFailed](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2849.39#add_processfailed)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [detail]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onRenderProcessGone, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onRenderProcessResponsive] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onRenderProcessResponsive.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView 29+ ([Official API - WebViewRenderProcessClient.onRenderProcessResponsive](https://developer.android.com/reference/android/webkit/WebViewRenderProcessClient#onRenderProcessResponsive(android.webkit.WebView,%20android.webkit.WebViewRenderProcess))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onRenderProcessResponsive, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onRenderProcessUnresponsive] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onRenderProcessUnresponsive.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView 29+ ([Official API - WebViewRenderProcessClient.onRenderProcessUnresponsive](https://developer.android.com/reference/android/webkit/WebViewRenderProcessClient#onRenderProcessUnresponsive(android.webkit.WebView,%20android.webkit.WebViewRenderProcess))) - ///- Windows WebView2 ([Official API - ICoreWebView2.add_ProcessFailed](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2849.39#add_processfailed)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onRenderProcessUnresponsive, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onRequestFocus] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onRequestFocus.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onRequestFocus](https://developer.android.com/reference/android/webkit/WebChromeClient#onRequestFocus(android.webkit.WebView))) - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onRequestFocus, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onSafeBrowsingHit] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onSafeBrowsingHit.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView 27+ ([Official API - WebViewClient.onSafeBrowsingHit](https://developer.android.com/reference/android/webkit/WebViewClient#onSafeBrowsingHit(android.webkit.WebView,%20android.webkit.WebResourceRequest,%20int,%20android.webkit.SafeBrowsingResponse))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - ///- [threatType]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onSafeBrowsingHit, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onSaveAsUIShowing] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onSaveAsUIShowing.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Windows WebView2 ([Official API - ICoreWebView2_25.add_SaveAsUIShowing](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_25?view=webview2-1.0.2849.39#add_saveasuishowing)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [request]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onSaveAsUIShowing, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onSaveFileSecurityCheckStarting] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onSaveFileSecurityCheckStarting.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Windows WebView2 ([Official API - ICoreWebView2_26.add_SaveFileSecurityCheckStarting](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_26?view=webview2-1.0.2849.39#add_savefilesecuritycheckstarting)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [request]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onSaveFileSecurityCheckStarting, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onScreenCaptureStarting] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onScreenCaptureStarting.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Windows WebView2 ([Official API - ICoreWebView2_27.add_ScreenCaptureStarting](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_27?view=webview2-1.0.2849.39#add_screencapturestarting)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [request]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onScreenCaptureStarting, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onScrollChanged] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onScrollChanged.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebView.onScrollChanged](https://developer.android.com/reference/android/webkit/WebView#onScrollChanged(int,%20int,%20int,%20int))) - ///- iOS WKWebView ([Official API - UIScrollViewDelegate.scrollViewDidScroll](https://developer.apple.com/documentation/uikit/uiscrollviewdelegate/1619392-scrollviewdidscroll)) - ///- macOS WKWebView: - /// - This event is implemented using JavaScript. - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [x]: all platforms - ///- [y]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onScrollChanged, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onShowFileChooser] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onShowFileChooser.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onShowFileChooser](https://developer.android.com/reference/android/webkit/WebChromeClient#onShowFileChooser(android.webkit.WebView,%20android.webkit.ValueCallback%3Candroid.net.Uri[]%3E,%20android.webkit.WebChromeClient.FileChooserParams))) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [request]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onShowFileChooser, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onTitleChanged] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onTitleChanged.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebChromeClient.onReceivedTitle](https://developer.android.com/reference/android/webkit/WebChromeClient#onReceivedTitle(android.webkit.WebView,%20java.lang.String))) - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 ([Official API - ICoreWebView2.add_DocumentTitleChanged](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_documenttitlechanged)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [title]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onTitleChanged, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onUpdateVisitedHistory] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onUpdateVisitedHistory.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebViewClient.doUpdateVisitedHistory](https://developer.android.com/reference/android/webkit/WebViewClient#doUpdateVisitedHistory(android.webkit.WebView,%20java.lang.String,%20boolean))) - ///- iOS WKWebView - ///- macOS WKWebView - ///- Windows WebView2 ([Official API - ICoreWebView2.add_HistoryChanged](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_historychanged)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [url]: all platforms - ///- [isReload]: - /// - Android WebView - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onUpdateVisitedHistory, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onWebContentProcessDidTerminate] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onWebContentProcessDidTerminate.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView ([Official API - WKNavigationDelegate.webViewWebContentProcessDidTerminate](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455639-webviewwebcontentprocessdidtermi)) - ///- macOS WKWebView ([Official API - WKNavigationDelegate.webViewWebContentProcessDidTerminate](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455639-webviewwebcontentprocessdidtermi)) - ///- Windows WebView2 ([Official API - ICoreWebView2.add_ProcessFailed](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2849.39#add_processfailed)) - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onWebContentProcessDidTerminate, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onWindowBlur] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onWindowBlur.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onWindowBlur, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onWindowFocus] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onWindowFocus.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView - ///- iOS WKWebView - ///- macOS WKWebView - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onWindowFocus, - - ///Can be used to check if the [PlatformInAppBrowserEvents.onZoomScaleChanged] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.onZoomScaleChanged.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebViewClient.onScaleChanged](https://developer.android.com/reference/android/webkit/WebViewClient#onScaleChanged(android.webkit.WebView,%20float,%20float))) - ///- iOS WKWebView ([Official API - UIScrollViewDelegate.scrollViewDidZoom](https://developer.apple.com/documentation/uikit/uiscrollviewdelegate/1619409-scrollviewdidzoom)) - ///- Windows WebView2 ([Official API - ICoreWebView2Controller.add_ZoomFactorChanged](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2controller?view=webview2-1.0.2849.39#add_zoomfactorchanged)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [oldScale]: all platforms - ///- [newScale]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - onZoomScaleChanged, - - ///Can be used to check if the [PlatformInAppBrowserEvents.shouldAllowDeprecatedTLS] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.shouldAllowDeprecatedTLS.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS WKWebView 14.0+ ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/3601237-webview)) - ///- macOS WKWebView 11.0+ ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/3601237-webview)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [challenge]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - shouldAllowDeprecatedTLS, - - ///Can be used to check if the [PlatformInAppBrowserEvents.shouldInterceptAjaxRequest] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.shouldInterceptAjaxRequest.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView: - /// - In order to be able to listen this event, check the [InAppWebViewSettings.useShouldInterceptAjaxRequest] setting documentation. Also, on Android that doesn't support the [WebViewFeature.DOCUMENT_START_SCRIPT], unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS. In that case, after the `window.addEventListener("flutterInAppWebViewPlatformReady")` event is dispatched, the ajax requests can be intercept for sure. - ///- iOS WKWebView - ///- macOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [ajaxRequest]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - shouldInterceptAjaxRequest, - - ///Can be used to check if the [PlatformInAppBrowserEvents.shouldInterceptFetchRequest] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.shouldInterceptFetchRequest.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView: - /// - In order to be able to listen this event, check the [InAppWebViewSettings.useShouldInterceptFetchRequest] setting documentation. Also, on Android that doesn't support the [WebViewFeature.DOCUMENT_START_SCRIPT], unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS. In that case, after the `window.addEventListener("flutterInAppWebViewPlatformReady")` event is dispatched, the ajax requests can be intercept for sure. - ///- iOS WKWebView - ///- macOS WKWebView - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [fetchRequest]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - shouldInterceptFetchRequest, - - ///Can be used to check if the [PlatformInAppBrowserEvents.shouldInterceptRequest] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.shouldInterceptRequest.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebViewClient.shouldInterceptRequest](https://developer.android.com/reference/android/webkit/WebViewClient#shouldInterceptRequest(android.webkit.WebView,%20android.webkit.WebResourceRequest))) - ///- Windows WebView2 ([Official API - ICoreWebView2.add_WebResourceRequested](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2478.35#add_webresourcerequested)) - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [request]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - shouldInterceptRequest, - - ///Can be used to check if the [PlatformInAppBrowserEvents.shouldOverrideUrlLoading] method is supported at runtime. - /// - ///{@template flutter_inappwebview_platform_interface.PlatformInAppBrowserEvents.shouldOverrideUrlLoading.supported_platforms} - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android WebView ([Official API - WebViewClient.shouldOverrideUrlLoading](https://developer.android.com/reference/android/webkit/WebViewClient#shouldOverrideUrlLoading(android.webkit.WebView,%20java.lang.String))): - /// - There isn't any way to load an URL for a frame that is not the main frame, so if the request is not for the main frame, the navigation is allowed by default. However, if you want to cancel requests for subframes, you can use the [InAppWebViewSettings.regexToCancelSubFramesLoading] setting to write a Regular Expression that, if the url request of a subframe matches, then the request of that subframe is canceled. Instead, the [InAppWebViewSettings.regexToAllowSyncUrlLoading] setting could be used to allow navigation requests synchronously, as this event is synchronous on native side and the current plugin implementation will always cancel the current request and load a new request if this event returns [NavigationActionPolicy.ALLOW] because Flutter method channels work only asynchronously. Also, this event is not called for POST requests and is not called on the first page load. - ///- iOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455641-webview)) - ///- macOS WKWebView ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455641-webview)) - ///- Windows WebView2 - /// - ///**Parameters - Officially Supported Platforms/Implementations**: - ///- [navigationAction]: all platforms - /// - ///Use the [PlatformInAppBrowserEvents.isMethodSupported] method to check if this method is supported at runtime. - ///{@endtemplate} - shouldOverrideUrlLoading, -} - -extension _PlatformInAppBrowserEventsMethodSupported - on PlatformInAppBrowserEvents { - static bool isMethodSupported( - PlatformInAppBrowserEventsMethod method, { - TargetPlatform? platform, - }) { - switch (method) { - case PlatformInAppBrowserEventsMethod.androidOnFormResubmission: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod - .androidOnGeolocationPermissionsHidePrompt: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod - .androidOnGeolocationPermissionsShowPrompt: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.androidOnJsBeforeUnload: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.androidOnPermissionRequest: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.androidOnReceivedIcon: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.androidOnReceivedLoginRequest: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.androidOnReceivedTouchIconUrl: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.androidOnRenderProcessGone: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.androidOnRenderProcessResponsive: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.androidOnRenderProcessUnresponsive: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.androidOnSafeBrowsingHit: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.androidOnScaleChanged: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.androidShouldInterceptRequest: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod - .iosOnDidReceiveServerRedirectForProvisionalNavigation: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.iosOnNavigationResponse: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.iosOnWebContentProcessDidTerminate: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.iosShouldAllowDeprecatedTLS: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onAcceleratorKeyPressed: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onAjaxProgress: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onAjaxReadyStateChange: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onBrowserCreated: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onCameraCaptureStateChanged: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onCloseWindow: - return kIsWeb && platform == null - ? true - : ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onConsoleMessage: - return kIsWeb && platform == null - ? true - : ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onContentLoading: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onContentSizeChanged: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.iOS].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onCreateWindow: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onDOMContentLoaded: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod - .onDidReceiveServerRedirectForProvisionalNavigation: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onDownloadStart: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onDownloadStartRequest: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onDownloadStarting: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onEnterFullscreen: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onExit: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.linux, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onExitFullscreen: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onFaviconChanged: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onFindResultReceived: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onFormResubmission: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onGeolocationPermissionsHidePrompt: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onGeolocationPermissionsShowPrompt: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onJsAlert: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onJsConfirm: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onJsPrompt: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onLaunchingExternalUriScheme: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onLoadError: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onLoadHttpError: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onLoadResource: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onLoadResourceCustomScheme: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onLoadResourceWithCustomScheme: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onLoadStart: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onLoadStop: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onLongPressHitTestResult: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onMainWindowWillClose: - return ((kIsWeb && platform != null) || !kIsWeb) && - [TargetPlatform.macOS].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onMicrophoneCaptureStateChanged: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onNavigationResponse: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onNotificationReceived: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onOverScrolled: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onPageCommitVisible: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onPermissionRequest: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onPermissionRequestCanceled: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onPrint: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onPrintRequest: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onProcessFailed: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onProgressChanged: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onReceivedClientCertRequest: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onReceivedError: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onReceivedHttpAuthRequest: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onReceivedHttpError: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onReceivedIcon: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onReceivedLoginRequest: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onReceivedServerTrustAuthRequest: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onReceivedTouchIconUrl: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onRenderProcessGone: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onRenderProcessResponsive: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onRenderProcessUnresponsive: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onRequestFocus: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onSafeBrowsingHit: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onSaveAsUIShowing: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onSaveFileSecurityCheckStarting: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onScreenCaptureStarting: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onScrollChanged: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onShowFileChooser: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onTitleChanged: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onUpdateVisitedHistory: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onWebContentProcessDidTerminate: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onWindowBlur: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onWindowFocus: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.onZoomScaleChanged: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.shouldAllowDeprecatedTLS: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.shouldInterceptAjaxRequest: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.shouldInterceptFetchRequest: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.shouldInterceptRequest: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - case PlatformInAppBrowserEventsMethod.shouldOverrideUrlLoading: - return ((kIsWeb && platform != null) || !kIsWeb) && - [ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.macOS, - TargetPlatform.windows, - ].contains(platform ?? defaultTargetPlatform); - } - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_localhost_server.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_localhost_server.dart deleted file mode 100755 index 3adba1ec63..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_localhost_server.dart +++ /dev/null @@ -1,197 +0,0 @@ -import 'dart:io'; -import 'dart:async'; -import 'dart:typed_data'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart' show rootBundle; - -import 'mime_type_resolver.dart'; -import 'platform_in_app_localhost_server.dart'; - -/// Object specifying creation parameters for creating a [DefaultInAppLocalhostServer]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformInAppLocalhostServerCreationParams] for -/// more information. -@immutable -class DefaultInAppLocalhostServerCreationParams - extends PlatformInAppLocalhostServerCreationParams { - /// Creates a new [DefaultInAppLocalhostServerCreationParams] instance. - const DefaultInAppLocalhostServerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformInAppLocalhostServerCreationParams params, - ) : super(); - - /// Creates a [DefaultInAppLocalhostServerCreationParams] instance based on [PlatformInAppLocalhostServerCreationParams]. - factory DefaultInAppLocalhostServerCreationParams.fromPlatformInAppLocalhostServerCreationParams( - PlatformInAppLocalhostServerCreationParams params, - ) { - return DefaultInAppLocalhostServerCreationParams(params); - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer} -class DefaultInAppLocalhostServer extends PlatformInAppLocalhostServer { - bool _started = false; - HttpServer? _server; - int _port = 8080; - bool _shared = false; - String _directoryIndex = 'index.html'; - String _documentRoot = './'; - Future Function(HttpRequest)? _customOnData; - - static final DefaultInAppLocalhostServer _staticValue = - DefaultInAppLocalhostServer( - const PlatformInAppLocalhostServerCreationParams(), - ); - - /// Creates a new empty [DefaultInAppLocalhostServer] to access static methods. - factory DefaultInAppLocalhostServer.static() => _staticValue; - - /// Creates a new [DefaultInAppLocalhostServer]. - DefaultInAppLocalhostServer(PlatformInAppLocalhostServerCreationParams params) - : super.implementation( - params is DefaultInAppLocalhostServerCreationParams - ? params - : DefaultInAppLocalhostServerCreationParams.fromPlatformInAppLocalhostServerCreationParams( - params, - ), - ) { - this._port = params.port; - this._directoryIndex = params.directoryIndex; - this._documentRoot = (params.documentRoot.endsWith('/')) - ? params.documentRoot - : '${params.documentRoot}/'; - this._shared = params.shared; - this._customOnData = params.onData; - } - - @override - int get port => _port; - - @override - String get directoryIndex => _directoryIndex; - - @override - String get documentRoot => _documentRoot; - - @override - bool get shared => _shared; - - @override - Future Function(HttpRequest request)? get onData => _customOnData; - - @override - Future start() async { - if (this._started) { - throw Exception('Server already started on http://localhost:$_port'); - } - this._started = true; - - final completer = Completer(); - - runZonedGuarded( - () { - HttpServer.bind('127.0.0.1', _port, shared: _shared).then((server) { - if (kDebugMode) { - print('Server running on http://localhost:' + _port.toString()); - } - - this._server = server; - - server.listen((HttpRequest request) async { - if (await _customOnData?.call(request) ?? false) { - // if _customOnData returns true, - // it means that the request has been handled - return; - } - - Uint8List body = Uint8List(0); - - var path = request.requestedUri.path; - path = (path.startsWith('/')) ? path.substring(1) : path; - path += (path.endsWith('/')) ? _directoryIndex : ''; - if (path == '') { - // if the path still empty, try to load the index file - path = _directoryIndex; - } - path = _documentRoot + path; - - try { - body = (await rootBundle.load( - Uri.decodeFull(path), - )).buffer.asUint8List(); - } catch (e) { - if (kDebugMode) { - print(Uri.decodeFull(path)); - print(e.toString()); - } - request.response.close(); - return; - } - - var contentType = ContentType('text', 'html', charset: 'utf-8'); - if (!request.requestedUri.path.endsWith('/') && - request.requestedUri.pathSegments.isNotEmpty) { - final mimeType = MimeTypeResolver.lookup( - request.requestedUri.path, - ); - if (mimeType != null) { - contentType = _getContentTypeFromMimeType(mimeType); - } - } - - request.response.headers.contentType = contentType; - print(request.response.headers); - request.response.add(body); - request.response.close(); - }); - - completer.complete(); - }); - }, - (e, stackTrace) { - if (kDebugMode) { - print('Error: $e $stackTrace'); - } - }, - ); - - return completer.future; - } - - @override - Future close() async { - if (this._server == null) { - return; - } - await this._server!.close(force: true); - if (kDebugMode) { - print('Server running on http://localhost:$_port closed'); - } - this._started = false; - this._server = null; - } - - @override - bool isRunning() { - return this._server != null; - } - - ContentType _getContentTypeFromMimeType(String mimeType) { - final contentType = mimeType.split('/'); - String? charset; - - if (_isTextFile(mimeType)) { - charset = 'utf-8'; - } - - return ContentType(contentType[0], contentType[1], charset: charset); - } - - bool _isTextFile(String mimeType) { - final textFile = RegExp(r'^text\/|^application\/(javascript|json)'); - return textFile.hasMatch(mimeType); - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/android/in_app_webview_options.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/android/in_app_webview_options.dart deleted file mode 100755 index 6b0422b6f9..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/android/in_app_webview_options.dart +++ /dev/null @@ -1,460 +0,0 @@ -import 'dart:ui'; - -import '../../util.dart'; -import '../../types/main.dart'; -import '../../in_app_browser/in_app_browser_settings.dart'; -import '../in_app_webview_settings.dart'; - -class AndroidOptions {} - -///Use [InAppWebViewSettings] instead. -@Deprecated('Use InAppWebViewSettings instead') -class AndroidInAppWebViewOptions - implements WebViewOptions, BrowserOptions, AndroidOptions { - ///Sets the text zoom of the page in percent. The default value is `100`. - int textZoom; - - ///Set to `true` to have the session cookie cache cleared before the new window is opened. - bool clearSessionCache; - - ///Set to `true` if the WebView should use its built-in zoom mechanisms. The default value is `true`. - bool builtInZoomControls; - - ///Set to `true` if the WebView should display on-screen zoom controls when using the built-in zoom mechanisms. The default value is `false`. - bool displayZoomControls; - - ///Set to `true` if you want the database storage API is enabled. The default value is `true`. - bool databaseEnabled; - - ///Set to `true` if you want the DOM storage API is enabled. The default value is `true`. - bool domStorageEnabled; - - ///Set to `true` if the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport. - ///When the value of the setting is false, the layout width is always set to the width of the WebView control in device-independent (CSS) pixels. - ///When the value is true and the page contains the viewport meta tag, the value of the width specified in the tag is used. - ///If the page does not contain the tag or does not provide a width, then a wide viewport will be used. The default value is `true`. - bool useWideViewPort; - - ///Sets whether Safe Browsing is enabled. Safe Browsing allows WebView to protect against malware and phishing attacks by verifying the links. - ///Safe Browsing is enabled by default for devices which support it. - /// - ///**NOTE**: available on Android 26+. - bool safeBrowsingEnabled; - - ///Configures the WebView's behavior when a secure origin attempts to load a resource from an insecure origin. - /// - ///**NOTE**: available on Android 21+. - AndroidMixedContentMode? mixedContentMode; - - ///Enables or disables content URL access within WebView. Content URL access allows WebView to load content from a content provider installed in the system. The default value is `true`. - bool allowContentAccess; - - ///Enables or disables file access within WebView. Note that this enables or disables file system access only. - ///Assets and resources are still accessible using `file:///android_asset` and `file:///android_res`. The default value is `true`. - bool allowFileAccess; - - ///Sets the path to the Application Caches files. In order for the Application Caches API to be enabled, this option must be set a path to which the application can write. - ///This option is used one time: repeated calls are ignored. - String? appCachePath; - - ///Sets whether the WebView should not load image resources from the network (resources accessed via http and https URI schemes). The default value is `false`. - bool blockNetworkImage; - - ///Sets whether the WebView should not load resources from the network. The default value is `false`. - bool blockNetworkLoads; - - ///Overrides the way the cache is used. The way the cache is used is based on the navigation type. For a normal page load, the cache is checked and content is re-validated as needed. - ///When navigating back, content is not revalidated, instead the content is just retrieved from the cache. The default value is [AndroidCacheMode.LOAD_DEFAULT]. - AndroidCacheMode? cacheMode; - - ///Sets the cursive font family name. The default value is `"cursive"`. - String cursiveFontFamily; - - ///Sets the default fixed font size. The default value is `16`. - int defaultFixedFontSize; - - ///Sets the default font size. The default value is `16`. - int defaultFontSize; - - ///Sets the default text encoding name to use when decoding html pages. The default value is `"UTF-8"`. - String defaultTextEncodingName; - - ///Disables the action mode menu items according to menuItems flag. - /// - ///**NOTE**: available on Android 24+. - AndroidActionModeMenuItem? disabledActionModeMenuItems; - - ///Sets the fantasy font family name. The default value is `"fantasy"`. - String fantasyFontFamily; - - ///Sets the fixed font family name. The default value is `"monospace"`. - String fixedFontFamily; - - ///Set the force dark mode for this WebView. The default value is [AndroidForceDark.FORCE_DARK_OFF]. - /// - ///**NOTE**: available on Android 29+. - AndroidForceDark? forceDark; - - ///Sets whether Geolocation API is enabled. The default value is `true`. - bool geolocationEnabled; - - ///Sets the underlying layout algorithm. This will cause a re-layout of the WebView. - AndroidLayoutAlgorithm? layoutAlgorithm; - - ///Sets whether the WebView loads pages in overview mode, that is, zooms out the content to fit on screen by width. - ///This setting is taken into account when the content width is greater than the width of the WebView control, for example, when [useWideViewPort] is enabled. - ///The default value is `false`. - bool loadWithOverviewMode; - - ///Sets whether the WebView should load image resources. Note that this method controls loading of all images, including those embedded using the data URI scheme. - ///Note that if the value of this setting is changed from false to true, all images resources referenced by content currently displayed by the WebView are loaded automatically. - ///The default value is `true`. - bool loadsImagesAutomatically; - - ///Sets the minimum logical font size. The default is `8`. - int minimumLogicalFontSize; - - ///Sets the initial scale for this WebView. 0 means default. The behavior for the default scale depends on the state of [useWideViewPort] and [loadWithOverviewMode]. - ///If the content fits into the WebView control by width, then the zoom is set to 100%. For wide content, the behavior depends on the state of [loadWithOverviewMode]. - ///If its value is true, the content will be zoomed out to be fit by width into the WebView control, otherwise not. - ///If initial scale is greater than 0, WebView starts with this value as initial scale. - ///Please note that unlike the scale properties in the viewport meta tag, this method doesn't take the screen density into account. - ///The default is `0`. - int initialScale; - - ///Tells the WebView whether it needs to set a node. The default value is `true`. - bool needInitialFocus; - - ///Sets whether this WebView should raster tiles when it is offscreen but attached to a window. - ///Turning this on can avoid rendering artifacts when animating an offscreen WebView on-screen. - ///Offscreen WebViews in this mode use more memory. The default value is `false`. - /// - ///**NOTE**: available on Android 23+. - bool offscreenPreRaster; - - ///Sets the sans-serif font family name. The default value is `"sans-serif"`. - String sansSerifFontFamily; - - ///Sets the serif font family name. The default value is `"sans-serif"`. - String serifFontFamily; - - ///Sets the standard font family name. The default value is `"sans-serif"`. - String standardFontFamily; - - ///Sets whether the WebView should save form data. In Android O, the platform has implemented a fully functional Autofill feature to store form data. - ///Therefore, the Webview form data save feature is disabled. Note that the feature will continue to be supported on older versions of Android as before. - ///The default value is `true`. - bool saveFormData; - - ///Boolean value to enable third party cookies in the WebView. - ///Used on Android Lollipop and above only as third party cookies are enabled by default on Android Kitkat and below and on iOS. - ///The default value is `true`. - /// - ///**NOTE**: available on Android 21+. - bool thirdPartyCookiesEnabled; - - ///Boolean value to enable Hardware Acceleration in the WebView. - ///The default value is `true`. - bool hardwareAcceleration; - - ///Sets whether the WebView supports multiple windows. - ///If set to `true`, [PlatformWebViewCreationParams.onCreateWindow] event must be implemented by the host application. The default value is `false`. - bool supportMultipleWindows; - - ///Regular expression used by [PlatformWebViewCreationParams.shouldOverrideUrlLoading] event to cancel navigation requests for frames that are not the main frame. - ///If the url request of a subframe matches the regular expression, then the request of that subframe is canceled. - String? regexToCancelSubFramesLoading; - - ///Set to `false` to disable Flutter Hybrid Composition. The default value is `true`. - ///Hybrid Composition is supported starting with Flutter v1.20+. - /// - ///**NOTE**: It is recommended to use Hybrid Composition only on Android 10+ for a release app, - ///as it can cause framerate drops on animations in Android 9 and lower (see [Hybrid-Composition#performance](https://github.com/flutter/flutter/wiki/Hybrid-Composition#performance)). - bool useHybridComposition; - - ///Set to `true` to be able to listen at the [PlatformWebViewCreationParams.androidShouldInterceptRequest] event. The default value is `false`. - bool useShouldInterceptRequest; - - ///Set to `true` to be able to listen at the [PlatformWebViewCreationParams.androidOnRenderProcessGone] event. The default value is `false`. - bool useOnRenderProcessGone; - - ///Sets the WebView's over-scroll mode. - ///Setting the over-scroll mode of a WebView will have an effect only if the WebView is capable of scrolling. - ///The default value is [AndroidOverScrollMode.OVER_SCROLL_IF_CONTENT_SCROLLS]. - AndroidOverScrollMode? overScrollMode; - - ///Informs WebView of the network state. - ///This is used to set the JavaScript property `window.navigator.isOnline` and generates the online/offline event as specified in HTML5, sec. 5.7.7. - bool? networkAvailable; - - ///Specifies the style of the scrollbars. The scrollbars can be overlaid or inset. - ///When inset, they add to the padding of the view. And the scrollbars can be drawn inside the padding area or on the edge of the view. - ///For example, if a view has a background drawable and you want to draw the scrollbars inside the padding specified by the drawable, - ///you can use SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to appear at the edge of the view, ignoring the padding, - ///then you can use SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. - ///The default value is [AndroidScrollBarStyle.SCROLLBARS_INSIDE_OVERLAY]. - AndroidScrollBarStyle? scrollBarStyle; - - ///Sets the position of the vertical scroll bar. - ///The default value is [AndroidVerticalScrollbarPosition.SCROLLBAR_POSITION_DEFAULT]. - AndroidVerticalScrollbarPosition? verticalScrollbarPosition; - - ///Defines the delay in milliseconds that a scrollbar waits before fade out. - int? scrollBarDefaultDelayBeforeFade; - - ///Defines whether scrollbars will fade when the view is not scrolling. - ///The default value is `true`. - bool scrollbarFadingEnabled; - - ///Defines the scrollbar fade duration in milliseconds. - int? scrollBarFadeDuration; - - ///Sets the renderer priority policy for this WebView. - RendererPriorityPolicy? rendererPriorityPolicy; - - ///Sets whether the default Android error page should be disabled. - ///The default value is `false`. - bool disableDefaultErrorPage; - - ///Sets the vertical scrollbar thumb color. - /// - ///**NOTE**: available on Android 29+. - Color? verticalScrollbarThumbColor; - - ///Sets the vertical scrollbar track color. - /// - ///**NOTE**: available on Android 29+. - Color? verticalScrollbarTrackColor; - - ///Sets the horizontal scrollbar thumb color. - /// - ///**NOTE**: available on Android 29+. - Color? horizontalScrollbarThumbColor; - - ///Sets the horizontal scrollbar track color. - /// - ///**NOTE**: available on Android 29+. - Color? horizontalScrollbarTrackColor; - - AndroidInAppWebViewOptions({ - this.textZoom = 100, - this.clearSessionCache = false, - this.builtInZoomControls = true, - this.displayZoomControls = false, - this.databaseEnabled = true, - this.domStorageEnabled = true, - this.useWideViewPort = true, - this.safeBrowsingEnabled = true, - this.mixedContentMode, - this.allowContentAccess = true, - this.allowFileAccess = true, - this.appCachePath, - this.blockNetworkImage = false, - this.blockNetworkLoads = false, - this.cacheMode = AndroidCacheMode.LOAD_DEFAULT, - this.cursiveFontFamily = "cursive", - this.defaultFixedFontSize = 16, - this.defaultFontSize = 16, - this.defaultTextEncodingName = "UTF-8", - this.disabledActionModeMenuItems, - this.fantasyFontFamily = "fantasy", - this.fixedFontFamily = "monospace", - this.forceDark = AndroidForceDark.FORCE_DARK_OFF, - this.geolocationEnabled = true, - this.layoutAlgorithm, - this.loadWithOverviewMode = true, - this.loadsImagesAutomatically = true, - this.minimumLogicalFontSize = 8, - this.needInitialFocus = true, - this.offscreenPreRaster = false, - this.sansSerifFontFamily = "sans-serif", - this.serifFontFamily = "sans-serif", - this.standardFontFamily = "sans-serif", - this.saveFormData = true, - this.thirdPartyCookiesEnabled = true, - this.hardwareAcceleration = true, - this.initialScale = 0, - this.supportMultipleWindows = false, - this.regexToCancelSubFramesLoading, - this.useHybridComposition = true, - this.useShouldInterceptRequest = false, - this.useOnRenderProcessGone = false, - this.overScrollMode = AndroidOverScrollMode.OVER_SCROLL_IF_CONTENT_SCROLLS, - this.networkAvailable, - this.scrollBarStyle = AndroidScrollBarStyle.SCROLLBARS_INSIDE_OVERLAY, - this.verticalScrollbarPosition = - AndroidVerticalScrollbarPosition.SCROLLBAR_POSITION_DEFAULT, - this.scrollBarDefaultDelayBeforeFade, - this.scrollbarFadingEnabled = true, - this.scrollBarFadeDuration, - this.rendererPriorityPolicy, - this.disableDefaultErrorPage = false, - this.verticalScrollbarThumbColor, - this.verticalScrollbarTrackColor, - this.horizontalScrollbarThumbColor, - this.horizontalScrollbarTrackColor, - }); - - @override - Map toMap() { - return { - "textZoom": textZoom, - "clearSessionCache": clearSessionCache, - "builtInZoomControls": builtInZoomControls, - "displayZoomControls": displayZoomControls, - "databaseEnabled": databaseEnabled, - "domStorageEnabled": domStorageEnabled, - "useWideViewPort": useWideViewPort, - "safeBrowsingEnabled": safeBrowsingEnabled, - "mixedContentMode": mixedContentMode?.toNativeValue(), - "allowContentAccess": allowContentAccess, - "allowFileAccess": allowFileAccess, - "appCachePath": appCachePath, - "blockNetworkImage": blockNetworkImage, - "blockNetworkLoads": blockNetworkLoads, - "cacheMode": cacheMode?.toNativeValue(), - "cursiveFontFamily": cursiveFontFamily, - "defaultFixedFontSize": defaultFixedFontSize, - "defaultFontSize": defaultFontSize, - "defaultTextEncodingName": defaultTextEncodingName, - "disabledActionModeMenuItems": disabledActionModeMenuItems - ?.toNativeValue(), - "fantasyFontFamily": fantasyFontFamily, - "fixedFontFamily": fixedFontFamily, - "forceDark": forceDark?.toNativeValue(), - "geolocationEnabled": geolocationEnabled, - "layoutAlgorithm": layoutAlgorithm?.toNativeValue(), - "loadWithOverviewMode": loadWithOverviewMode, - "loadsImagesAutomatically": loadsImagesAutomatically, - "minimumLogicalFontSize": minimumLogicalFontSize, - "initialScale": initialScale, - "needInitialFocus": needInitialFocus, - "offscreenPreRaster": offscreenPreRaster, - "sansSerifFontFamily": sansSerifFontFamily, - "serifFontFamily": serifFontFamily, - "standardFontFamily": standardFontFamily, - "saveFormData": saveFormData, - "thirdPartyCookiesEnabled": thirdPartyCookiesEnabled, - "hardwareAcceleration": hardwareAcceleration, - "supportMultipleWindows": supportMultipleWindows, - "useHybridComposition": useHybridComposition, - "regexToCancelSubFramesLoading": regexToCancelSubFramesLoading, - "useShouldInterceptRequest": useShouldInterceptRequest, - "useOnRenderProcessGone": useOnRenderProcessGone, - "overScrollMode": overScrollMode?.toNativeValue(), - "networkAvailable": networkAvailable, - "scrollBarStyle": scrollBarStyle?.toNativeValue(), - "verticalScrollbarPosition": verticalScrollbarPosition?.toNativeValue(), - "scrollBarDefaultDelayBeforeFade": scrollBarDefaultDelayBeforeFade, - "scrollbarFadingEnabled": scrollbarFadingEnabled, - "scrollBarFadeDuration": scrollBarFadeDuration, - "rendererPriorityPolicy": rendererPriorityPolicy?.toMap(), - "disableDefaultErrorPage": disableDefaultErrorPage, - "verticalScrollbarThumbColor": verticalScrollbarThumbColor?.toHex(), - "verticalScrollbarTrackColor": verticalScrollbarTrackColor?.toHex(), - "horizontalScrollbarThumbColor": horizontalScrollbarThumbColor?.toHex(), - "horizontalScrollbarTrackColor": horizontalScrollbarTrackColor?.toHex(), - }; - } - - static AndroidInAppWebViewOptions fromMap(Map map) { - var instance = AndroidInAppWebViewOptions(); - instance.textZoom = map["textZoom"]; - instance.clearSessionCache = map["clearSessionCache"]; - instance.builtInZoomControls = map["builtInZoomControls"]; - instance.displayZoomControls = map["displayZoomControls"]; - instance.databaseEnabled = map["databaseEnabled"]; - instance.domStorageEnabled = map["domStorageEnabled"]; - instance.useWideViewPort = map["useWideViewPort"]; - instance.safeBrowsingEnabled = map["safeBrowsingEnabled"]; - instance.mixedContentMode = AndroidMixedContentMode.fromNativeValue( - map["mixedContentMode"], - ); - instance.allowContentAccess = map["allowContentAccess"]; - instance.allowFileAccess = map["allowFileAccess"]; - instance.appCachePath = map["appCachePath"]; - instance.blockNetworkImage = map["blockNetworkImage"]; - instance.blockNetworkLoads = map["blockNetworkLoads"]; - instance.cacheMode = AndroidCacheMode.fromNativeValue(map["cacheMode"]); - instance.cursiveFontFamily = map["cursiveFontFamily"]; - instance.defaultFixedFontSize = map["defaultFixedFontSize"]; - instance.defaultFontSize = map["defaultFontSize"]; - instance.defaultTextEncodingName = map["defaultTextEncodingName"]; - instance.disabledActionModeMenuItems = - AndroidActionModeMenuItem.fromNativeValue( - map["disabledActionModeMenuItems"], - ); - instance.fantasyFontFamily = map["fantasyFontFamily"]; - instance.fixedFontFamily = map["fixedFontFamily"]; - instance.forceDark = AndroidForceDark.fromNativeValue(map["forceDark"]); - instance.geolocationEnabled = map["geolocationEnabled"]; - instance.layoutAlgorithm = AndroidLayoutAlgorithm.fromNativeValue( - map["layoutAlgorithm"], - ); - instance.loadWithOverviewMode = map["loadWithOverviewMode"]; - instance.loadsImagesAutomatically = map["loadsImagesAutomatically"]; - instance.minimumLogicalFontSize = map["minimumLogicalFontSize"]; - instance.initialScale = map["initialScale"]; - instance.needInitialFocus = map["needInitialFocus"]; - instance.offscreenPreRaster = map["offscreenPreRaster"]; - instance.sansSerifFontFamily = map["sansSerifFontFamily"]; - instance.serifFontFamily = map["serifFontFamily"]; - instance.standardFontFamily = map["standardFontFamily"]; - instance.saveFormData = map["saveFormData"]; - instance.thirdPartyCookiesEnabled = map["thirdPartyCookiesEnabled"]; - instance.hardwareAcceleration = map["hardwareAcceleration"]; - instance.supportMultipleWindows = map["supportMultipleWindows"]; - instance.regexToCancelSubFramesLoading = - map["regexToCancelSubFramesLoading"]; - instance.useHybridComposition = map["useHybridComposition"]; - instance.useShouldInterceptRequest = map["useShouldInterceptRequest"]; - instance.useOnRenderProcessGone = map["useOnRenderProcessGone"]; - instance.overScrollMode = AndroidOverScrollMode.fromNativeValue( - map["overScrollMode"], - ); - instance.networkAvailable = map["networkAvailable"]; - instance.scrollBarStyle = AndroidScrollBarStyle.fromNativeValue( - map["scrollBarStyle"], - ); - instance.verticalScrollbarPosition = - AndroidVerticalScrollbarPosition.fromNativeValue( - map["verticalScrollbarPosition"], - ); - instance.scrollBarDefaultDelayBeforeFade = - map["scrollBarDefaultDelayBeforeFade"]; - instance.scrollbarFadingEnabled = map["scrollbarFadingEnabled"]; - instance.scrollBarFadeDuration = map["scrollBarFadeDuration"]; - instance.rendererPriorityPolicy = RendererPriorityPolicy.fromMap( - map["rendererPriorityPolicy"]?.cast(), - ); - instance.disableDefaultErrorPage = map["disableDefaultErrorPage"]; - instance.verticalScrollbarThumbColor = UtilColor.fromHex( - map["verticalScrollbarThumbColor"], - ); - instance.verticalScrollbarTrackColor = UtilColor.fromHex( - map["verticalScrollbarTrackColor"], - ); - instance.horizontalScrollbarThumbColor = UtilColor.fromHex( - map["horizontalScrollbarThumbColor"], - ); - instance.horizontalScrollbarTrackColor = UtilColor.fromHex( - map["horizontalScrollbarTrackColor"], - ); - return instance; - } - - @override - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } - - @override - AndroidInAppWebViewOptions copy() { - return AndroidInAppWebViewOptions.fromMap(this.toMap()); - } -} diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/android/main.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/android/main.dart deleted file mode 100644 index da217a8644..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/android/main.dart +++ /dev/null @@ -1 +0,0 @@ -export 'in_app_webview_options.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/apple/in_app_webview_options.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/apple/in_app_webview_options.dart deleted file mode 100755 index 904961acc0..0000000000 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/apple/in_app_webview_options.dart +++ /dev/null @@ -1,401 +0,0 @@ -import '../../types/main.dart'; - -import '../../in_app_browser/in_app_browser_settings.dart'; - -import '../in_app_webview_settings.dart'; -import '../platform_inappwebview_controller.dart'; - -class IosOptions {} - -///Use [InAppWebViewSettings] instead. -@Deprecated('Use InAppWebViewSettings instead') -class IOSInAppWebViewOptions - implements WebViewOptions, BrowserOptions, IosOptions { - ///Set to `true` to disable the bouncing of the WebView when the scrolling has reached an edge of the content. The default value is `false`. - bool disallowOverScroll; - - ///Set to `true` to allow a viewport meta tag to either disable or restrict the range of user scaling. The default value is `false`. - bool enableViewportScale; - - ///Set to `true` if you want the WebView suppresses content rendering until it is fully loaded into memory. The default value is `false`. - bool suppressesIncrementalRendering; - - ///Set to `true` to allow AirPlay. The default value is `true`. - bool allowsAirPlayForMediaPlayback; - - ///Set to `true` to allow the horizontal swipe gestures trigger back-forward list navigations. The default value is `true`. - bool allowsBackForwardNavigationGestures; - - ///Set to `true` to allow that pressing on a link displays a preview of the destination for the link. The default value is `true`. - /// - ///**NOTE**: available on iOS 9.0+. - bool allowsLinkPreview; - - ///Set to `true` if you want that the WebView should always allow scaling of the webpage, regardless of the author's intent. - ///The ignoresViewportScaleLimits property overrides the `user-scalable` HTML property in a webpage. The default value is `false`. - bool ignoresViewportScaleLimits; - - ///Set to `true` to allow HTML5 media playback to appear inline within the screen layout, using browser-supplied controls rather than native controls. - ///For this to work, add the `webkit-playsinline` attribute to any `